views:

21

answers:

1

I have a Django 1.1 model with unique_together on the owner and title where owner is foreign key on a user. This constraint is enforced but only after the clean. According to Django docs, I should be able to access self.instance to see non-form field object properties of a model instance.

However, I get the error

'JournalForm' object has no attribute 'instance'

Why is self.instance not set on this bound form in either the form clean() or the field clean_title() methods?

My model:

class Journal (models.Model):
    owner = models.ForeignKey(User, null=True, related_name='journals')
    title = models.CharField(null=False, max_length=256)
    published = models.BooleanField(default=False)

    class Meta:
        unique_together = ("owner", "title")

    def __unicode__(self):
        return self.title

My form:

class JournalForm (forms.Form):
    title = forms.CharField(max_length=256,
                                label=u'Title:')
    html_input = forms.CharField(widget=TinyMCE(attrs={'cols':'85', 'rows':'40'}, ), 
                            label=u'Journal Content:')
    published = forms.BooleanField(required=False)

    def clean(self):
        super(JournalForm, self).clean()
        instance = self.instance
        return self.cleaned_input

    def clean_title(self):
        title = self.cleaned_data['title']
        if self.is_bound:
            if models.Journal.objects.filter(owner.id=self.instance.owner.id, title=title).exclude(id=self.instance.id).count() > 0:
               raise forms.ValidationError(u'You already have a Journal with that title. Please change your title so it is unique.')
        else:
            if models.LabJournal.objects.filter(owner.id=self.instance.owner.id, title=title).count() > 0:
               raise forms.ValidationError(u'You already have a Journal with that title. Please change your title so it is unique.')
        return title

As requested - the view code:

def journal (request):
    try:
        journal = models.Journal.objects.get(id=id)
        if request.method == 'GET':
            if request.user.is_active:
                if request.user.id == journal.owner.id:
                    data = {
                        'title' : journal.title,
                        'html_input' : _journal_fields_to_HTML(journal.id),
                        'published' : journal.published
                    }
                    form = forms.JournalForm(initial=data)
                    return shortcuts.render_to_response('journal/Journal.html', { 'form':form, })
                else:
                    return http.HttpResponseForbidden('<h1>Access denied</h1>')
            else:
                return _display_login_form(request)
        elif request.method == 'POST':
            if LOGIN_FORM_KEY in request.POST:
                return _handle_login(request)
            elif request.user.is_active and request.user.id == journal.owner.id:
                form = forms.JournalForm(data=request.POST)
                if form.is_valid():
                    journal.title = form.cleaned_data['title']
                    journal.published = form.cleaned_data['title'];
                    journal.save()
                    if _HTML_to_journal_fields(journal, form.cleaned_data['html_input']):
                        html_memo = "Save successful."
                    else:
                        html_memo = "Unable to save Journal."
                    return shortcuts.render_to_response('journal/Journal.html', { 'form':form, 'saved':html_memo})
                else:
                    return shortcuts.render_to_response('journal/Journal.html', { 'form':form })
        return http.HttpResponseNotAllowed(['GET', 'POST'])
    except models.Journal.DoesNotExist:
        return http.HttpResponseNotFound('<h1>Requested journal not found</h1>')
+1  A: 

Well there are a couple of issues here.

First is that you're not using a ModelForm. The docs you link to are for those, not for standard forms.

Secondly, in order for the form to have an instance attribute, you need to pass that instance in when you're instantiating the form.

If you do use a ModelForm, you won't need the code that converts the journal fields to the form fields, and vice versa on save - the form does that for you. You'll also be able to remove the clean_title method which checks for uniqueness, because that's already defined by the unique_together constraint on the model, and the ModelForm will enforce that for you.

Daniel Roseman
I changed the form to a ModelForm, and tried to save but I get the same issue as before - exception thrown: IntegrityError at /labjournal/journal/2duplicate key value violates unique constraint. I can wrap the save in a try block, but I thought the ModelForm would enforce the unique_together constraint as part of is_valid(). Is this wrong?
selfsimilar
You didn't mention that before... It would be worth posting a new question for this, with your updated view/form code.
Daniel Roseman
Thanks, Daniel.Follow up question here: http://stackoverflow.com/questions/4034911/why-doesnt-django-enforce-my-unique-together-constraint-as-a-form-validationerro
selfsimilar