Django-model advanced (mediation model, query optimization, extra, overall insertion)
Read the content (Content)
mediation model
When dealing with simple many-to-many relationships like matching pizza and topping, use the standard ManyToManyField . However, sometimes you may need to correlate data to a relationship between two models.
For example, there is an application that records the musical groups a musician belongs to. We can use a ManyToManyField to represent a many-to-many relationship between groups and members. However, sometimes you may want to know more details about membership, such as when members joined the group.
For these cases, Django allows you to specify an intermediary model to define a many-to-many relationship. You can put other fields inside the mediation model. The source model's ManyToManyField field will use the through parameter to point to the intermediary model. For the music group example above, the code is as follows:
from django.db import models class Person(models.Model): name = models.CharField(max_length=128) def __str__(self): # __unicode__ on Python 2 return self.name class Group(models.Model): name = models.CharField(max_length=128) members = models.ManyToManyField(Person, through='Membership') def __str__(self): # __unicode__ on Python 2 return self.name class Membership(models.Model): person = models.ForeignKey(Person) group = models.ForeignKey(Group) date_joined = models.DateField() invite_reason = models.CharField(max_length=64)
Now that you've set up the ManyToManyField to use the mediation model ( Membership in this case ), you'll start creating the many-to-many relationship. All you have to do is create an instance of the mediation model:
>>> ringo = Person.objects.create(name="Ringo Starr") >>> paul = Person.objects.create(name="Paul McCartney") >>> beatles = Group.objects.create(name="The Beatles") >>> m1 = Membership(person=ringo, group=beatles, ... date_joined=date(1962, 8, 16), ... invite_reason="Needed a new drummer.") >>> m1.save() >>> beatles.members.all() [<Person: Ringo Starr>] >>> ringo.group_set.all() [<Group: The Beatles>] >>> m2 = Membership.objects.create(person=paul, group=beatles, ... date_joined=date(1960, 8, 1), ... invite_reason="Wanted to form a band.") >>> beatles.members.all() [<Person: Ringo Starr>, <Person: Paul McCartney>]
Unlike normal many-to-many fields, you cannot use add , create and assignment statements (eg beatles.members = [...] ) to create relationships:
# THIS WILL NOT WORK >>> beatles.members.add(john) # NEITHER WILL THIS >>> beatles.members.create(name="George Harrison") # AND NEITHER WILL THIS >>> beatles.members = [john, paul, ringo, george]
Why can't this be done? This is because you can't just create an association between Person and Group , you also specify all the information you need in the Membership model; simple add , create , and assignment statements can't do that. So they cannot be used in many-to-many relationships using the mediation model. At this point, the only way is to create an instance of the mediation model.
The remove() method is disabled for the same reason. But the clear() method is available. It can clear all the many-to-many relationships of an instance
>>> # Beatles have broken up >>> beatles.members.clear() >>> # Note that this deletes the intermediate model instances >>> Membership.objects.all() []
Query optimization
overall insertion