How to perform validation when using add() on many to many relation ships in Django?
i have a Category model with parent/child self relation For primary category and sub categories :
class Place(models.Model):
name = models.CharField(_("name"), max_length=100)
categories = models.ManyToManyField("Category", verbose_name=_("categories"))
class Category(models.Model):
name = models.CharField(_("name"), max_length=100)
parent = models.ForeignKey('self', blank=True, null=True, related_name='child_set')
i need to prevent orphans, to prevent this kind of errors (in admin web interface开发者_如何学Go)
c_parent = Category(name='Restaurant')
c_parent.save()
c_child = Category(name="Japanese restaurant", parent=c_parent)
c_child.save()
place1 = Place (name="Planet sushi")
place1.save()
place1.categories.add(c_parent)
place1.categories.add(c_child)
So now we have a new Place called "Planet sushi", it's a Restaurant (root category), and a Japanese Restaurant (sub category)
but i want to prevent this kind of things :
place2 = Place (name="Tokyofood")
place2.save()
place2.categories.add(c_child)
because parent is not set, or is not the correct parent category
where can i do form validation for the admin ? and other forms (because any user can add a new place and will have to choose correct categories for)
Use signals and more specifically the m2m_changed signal.
Take time to read the doc as signals are not easy to get, and the m2m_changed
is the most complicated as it's one signal for everything that appends to the m2m relationship.
Basically what you want to check if action is pre_add
, then raise a ValidationError if the category parent doesn't match your requirements.
Take some time on checking what is sender
and instance
, espacially since it changes according to the value of reverse
.
update:
in Place class add this method:
def add_cat(self,cat):
self.categories.add(cat)
if cat.parent:
self.add_cat(cat.parent)
now instead of using place1.categories.add(cat)
you can use place1.add_cat(cat)
and it will automatically add the category, and its parent category, and its parent category and so on. this is not tested, but even if it doesn't work it should get the point across.
精彩评论