Unique_together models constraint + None = fail?

2 questions:

  • How can I stop duplicate creation if parent = None and the name is the same?
  • Can I name a model method from a form?

See below for more details.

models.py

class MyTest(models.Model): parent = models.ForeignKey('self', null=True, blank=True, related_name='children') name = models.CharField(max_length=50) slug = models.SlugField(max_length=255, blank=True, unique=True) owner = models.ForeignKey(User, null=True) class Meta: unique_together = ("parent", "name") def save(self, *args, **kwargs): self.slug = self.make_slug() super(MyTest, self).save(*args, **kwargs) def make_slug(self): # some stuff here return generated_slug 

note: slug = unique, too!

forms.py

 class MyTestForm(forms.ModelForm): class Meta: model = MyTest exclude = ('slug',) def clean_name(self): name = self.cleaned_data.get("name") parent = self.cleaned_data.get("parent") if parent is None: # this doesn't work when MODIFYING existing elements! if len(MyTest.objects.filter(name = name, parent = None)) > 0: raise forms.ValidationError("name not unique") return name 

More details

The unique_together contract unique_together fine with the form when parent != None . However, when parent == None (null) allows duplicates.

To try to avoid this, I tried to use the form and the specific name clean_ to try to check for duplicates. This works when creating new objects, but does not work when modifying existing objects.

Someone mentioned that I should use commit = False on ModelForm.save, but I could not figure out how to do this / implement it. I also thought about using ModelForm has_changed to detect changes to the model and resolve them, but has_changed returns true for newly created objects with a form. help!

Also (a slightly different question) can I access the make_slug () model method from the form? I believe that currently my line exclude = ('slug',) also ignores the โ€œuniqueโ€ restriction in the slug field, and in the model save field I generate slug instead. I was wondering if I can do this in forms.py instead?

+6
django django-models django-forms
source share
3 answers

You may have another form created or updated.

Use the kwarg instance when creating the form instance.

 if slug: instance = MyTest.object.get( slug=slug ) form = MyUpdateTestForm( instance=instance ) else: form = MyTestForm() 

For the second part, I think that where you could take commit = False, something like:

 if form.is_valid(): inst = form.save( commit=False ) inst.slug = inst.make_slug() inst.save() 
0
source share

I donโ€™t know, for sure, this will fix your problem, but I suggest checking your code on the latest Django transaction code. Get it with:

 svn co http://code.djangoproject.com/svn/django/trunk/ 

Since release 1.02, several unique fixes have been fixed: for example, ticket 9493 .

-one
source share

Unique together should be a tuple of tuples

 unique_together = (("parent", "name"),) 
-one
source share

All Articles