Leszek Wroński Leszek Wroński - 23 days ago 8
Python Question

Updating a model instance via a ModelForm: 'unicode' object has no attribute '_meta'

Disclaimer: I have read this and a few other related questions, but either I have not understood the answers or the problems discussed there are actually different.

In my app the user can view an instance of a model Kurs or edit it -- I have two separate views for the two actions. The details of the model Kurs are as follows:

class Kurs(models.Model):
prowadzacy = models.ForeignKey(User)
nazwa = models.CharField(max_length=200)
[skipping some fields...]
def __unicode__(self):
return self.nazwa
class Meta:
verbose_name_plural = "Kursy"


So as you can see it has a unicode method and a Meta class.

The ModelForm I'm using is this simple one:

class KursForm(ModelForm):
class Meta:
model = Kurs
fields = "__all__"


The relevant view is as follows (I don't want to use class-based views now):

def editcourse(request, pk):
kurs_id = pk
if request.method=='POST':
form = KursForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/polls/usersite')
else:
form = KursForm(instance=pk)

return render(request, 'polls/editcourse.html', {"form" : form})


My urlpatterns contain

url(r'^editcourse/(?P<pk>[0-9]+)/$', views.editcourse, name='editcourse')


and I'm calling the view from a page which contains the link

<a href="{% url 'polls:editcourse' kur.id %}">EDIT THIS COURSE</a>


where "kur" is a Kurs. My editcourse.html contains the following:

<form action="" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit" />
</form>


Unfortunately when the user clicks on 'EDIT THIS COURSE', what happens is an AttributeError 'unicode' object has no attribute '_meta' and the last few lines of the traceback are

File "[my path here]/views.py" in editcourse
84. form = KursForm(instance=pk)

File "/usr/local/lib/python2.7/dist-packages/Django-1.10.3-py2.7.egg/django/forms/models.py" in __init__
282. object_data = model_to_dict(instance, opts.fields, opts.exclude)

File "/usr/local/lib/python2.7/dist-packages/Django-1.10.3-py2.7.egg/django/forms/models.py" in model_to_dict
87. opts = instance._meta

Exception Type: AttributeError at /polls/editcourse/6/
Exception Value: 'unicode' object has no attribute '_meta'


What am I doing wrong? Should I add an empty '_meta' class to my Kurs model?

Answer

In your editcourse view, pk isn't the kurs instance, it's a string with the id (in this case '6').

You need to fetch the instance from the db. The shortcut get_object_or_404 is useful for this. Note that you should pass the instance to the form in the GET and POST branches of your if statement.

from django.shortcuts import get_object_or_404

def editcourse(request, pk):
   kurs = get_object_or_404(Kurs, pk=pk)
    if request.method=='POST':
        form = KursForm(request.POST, instance=kurs)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect('/polls/usersite')
    else:
        form = KursForm(instance=kurs)

    return render(request, 'polls/editcourse.html', {"form" : form})