1

I'm having trouble overriding the save method on a Django model to check a restriction on a many-to-many field.

Say I have the following models:

class Person(models.Model):
    name = models.CharField()

class ClothingItem(models.Model):
    description = models.CharField()
    owner = models.ForeignKey(Person)

class Outfit(models.Model):
    name = models.CharField()
    owner = models.ForeignKey(Person)
    clothing_items = models.ManyToManyField(ClothingItem)

I would like to put a restriction on the save method of Outfit that ensures that each ClothingItem in a given outfit has the same owner as the Outfit itself.

I.e. I'd like to write:

class Outfit(models.Model):
    name = models.CharField()
    owner = models.ForeignKey(Person)
    clothing_items = models.ManyToManyField(ClothingItem)

    def save(self, *args, **kwargs):
        for ci in self.clothing_items:
            if ci.owner != self.owner:
                raise ValueError('You can only put your own items in an outfit!)
        super(Outfit, self).save(*args, **kwargs)

but when I try that I get an error about <Outfit: SundayBest>" needs to have a value for field "outfit" before this many-to-many relationship can be used.

Any ideas what's going wrong here?

8one6
  • 13,078
  • 12
  • 62
  • 84

1 Answers1

2

There are two issues going on here. To directly answer your question, the error basically means: You cannot refer to any m2m relationship if the original object(an instance of Outfit here) is not saved in database.

Sounds like you are trying to do the validation in save() method, which is a pretty bad practice in django. The verification process should typically happen in Form that creates Outfit objects. To override default django form, please refer to django ModelAdmin.form. To understand how to do validation on django forms, check ModelForm validation.

If you want code to refer to for m2m validation, I found a good example from SO.

Community
  • 1
  • 1
Shang Wang
  • 24,909
  • 20
  • 73
  • 94