0x00 - associated object
When you define an association in the model (e.g ForeignKey， OneToOneField , or ManyToManyField ), the instance of the model will automatically obtain a set of API s to quickly access the associated objects.
Take the model at the beginning of this article as an example. An Entry object e obtains its associated blog object: e.blog through the blog attribute.
(behind the scenes, this function is created by Python descriptors It's true. This thing usually won't bother you, but we've pointed out some points for you.)
Django also provides an API that can be accessed from the other side of the relationship -- the connection from the associated model to the model that defines the relationship. For example, a Blog object B can use entry_set attribute b.entry_set.all() accesses the list containing all associated Entry objects.
All examples in this chapter use the Blog, Author and Entry models defined at the beginning of this page.
0x01 - one to many Association
0x01 – 1 – forward access
If the model has a ForeignKey , instances of the model can access associated (external) objects through their properties.
give an example:
>>> e = Entry.objects.get(id=2) >>> e.blog # Returns the related Blog object.
You can get and set the value through the foreign key property. As you think, the foreign key is modified until you call save() Before it can be stored in the database. example:
>>> e = Entry.objects.get(id=2) >>> e.blog = some_blog >>> e.save()
if ForeignKey The field is configured with null=True (that is, it allows NULL values). You can specify the value of None to remove the association. example:
>>> e = Entry.objects.get(id=2) >>> e.blog = None >>> e.save() # "UPDATE blog_entry SET blog_id = NULL ...;"
Association relationships are cached the first time an association object is accessed through a forward one to many association. Subsequent access through foreign keys on the same object will also be cached. example:
>>> e = Entry.objects.get(id=2) >>> print(e.blog) # Hits the database to retrieve the associated Blog. >>> print(e.blog) # Doesn't hit the database; uses cached version.
>>> e = Entry.objects.select_related().get(id=2) >>> print(e.blog) # Doesn't hit the database; uses cached version. >>> print(e.blog) # Doesn't hit the database; uses cached version.
0x01 – 2 – inverse correlation
If the model has ForeignKey , the model instance associated with the foreign key will be accessible Manager , which returns all instances of the first model. By default, the Manager Named FOO_set, FOO is the lowercase form of the source model name. Manager Returns QuerySets, which can be filtered and operated in the way described in the "retrieve objects" chapter.
give an example:
>>> b = Blog.objects.get(id=1) >>> b.entry_set.all() # Returns all Entry objects related to Blog. # b.entry_set is a Manager that returns QuerySets. >>> b.entry_set.filter(headline__contains='Lennon') >>> b.entry_set.count()
You can define ForeignKey Time setting related_name Parameter overrides this FOO_set name. For example, if you modify the Entry model to blog = ForeignKey(Blog, on_delete=models.CASCADE, related_name='entries'), the previous example code will look like this:
>>> b = Blog.objects.get(id=1) >>> b.entries.all() # Returns all Entry objects related to Blog. # b.entries is a Manager that returns QuerySets. >>> b.entries.filter(headline__contains='Lennon') >>> b.entries.count()
0x01 – 3 – use custom inverting Manager
from django.db import models class Entry(models.Model): #... objects = models.Manager() # Default Manager entries = EntryManager() # Custom Manager b = Blog.objects.get(id=1) b.entry_set(manager='entries').all()
If EntryManager gets_ The queryset () method implements the default filtering behavior, which will be applied to the all() call.
Specifying a custom reverse management also allows you to call model custom methods:
0x01 – 4 – additional methods for managing associated objects
ForeignKey Manager There are also methods to handle collections of associated objects. Except as defined in "retrieve objects" above QuerySet In addition to the method, the following is a brief introduction to each item, and the complete details can be found in Associated object reference Found in.
add(obj1, obj2, ...)
Adds a specific model object to the associated object collection.
Create a new object, save it, and put it into the associated object collection. Returns the newly created object.
remove(obj1, obj2, ...)
Deletes the specified model object from the associated object collection.
Deletes all objects from the associated object collection.
Replace associated object collection
To specify the members of the associated collection, call the set() method and pass in an iteratable collection of object instances. For example, if both e1 and e2 are Entry instances:
b = Blog.objects.get(id=1) b.entry_set.set([e1, e2])
If you can use the clear() method, enter_ All old objects in the set are deleted before adding objects from the iteratable set (in this case, a list). If the clear() method cannot be used, the old object will not be deleted when adding a new object.
All "reverse" operations described in this section take effect immediately for the database. Each addition, creation and deletion are automatically saved to the database in time.
0x02 - many to many Association
Both ends of a many to many association automatically obtain an API to access the other end. The API works like the "reverse" one to many association above.
The difference is in naming attributes: defined ManyToManyField The model of uses the field name as the attribute name, while the "reverse" model uses the lowercase form of the source model name, plus'_ set '(like reverse one to many Association).
A more understandable example:
e = Entry.objects.get(id=3) e.authors.all() # Returns all Author objects for this Entry. e.authors.count() e.authors.filter(name__contains='John') a = Author.objects.get(id=5) a.entry_set.all() # Returns all Entry objects for this Author.
and ForeignKey Like, ManyToManyField Can specify related_name . In the above example, if the ManyToManyField Related has been specified_ Name ='entries', then each Author instance will have an entries attribute instead of an entry_set.
Another difference from one to many association is that in addition to model instances, the add(), set() and remove() methods in many to many association can receive primary key values. For example, if e and e2 are instances of Entry, the following two sets () call results are consistent:
a = Author.objects.get(id=5) a.entry_set.set([e1, e2]) a.entry_set.set([e1.pk, e2.pk])
0x03 - one to one Association
One to one associations are very similar to many to one associations. If defined in the model OneToOneField , instances of the model can access associated objects only through their properties.
class EntryDetail(models.Model): entry = models.OneToOneField(Entry, on_delete=models.CASCADE) details = models.TextField() ed = EntryDetail.objects.get(id=2) ed.entry # Returns the related Entry object.
The difference is the "reverse" query. The objects associated with a one-to-one association can also be accessed Manager Object, but this Manager Represents only one object, not a collection of objects:
e = Entry.objects.get(id=2) e.entrydetail # returns the related EntryDetail object
If no object is specified for the association, Django throws a DoesNotExist exception.
The instance can be assigned to the reverse association in the same way as the association object is assigned to the forward association:
e.entrydetail = ed
0x04 - how to implement reverse association
Other object association mapping implementations require you to define associations on both sides. Django developers firmly believe that this violates the DRY principle (don't repeat yourself), so Django only requires you to define an association at one end.
But how is this implemented? Give you a model class. The model class does not know whether other model classes are associated with it until other model classes are loaded?
The answer lies in Application registration . When Django starts, it imports INSTALLED_APPS List each application and the model module in each application. Whenever a new model class is created, Django adds a reverse Association for each association model. If the associated model is not imported, Django will continue to track these associations and add association relationships when the associated model is imported.
For this reason, applications that contain all the models you use must be listed in INSTALLED_APPS Yes. Otherwise, reverse association may not work properly.
0x05 - query associated objects
Queries involving associated objects follow the same rules as queries involving common fields. When no value is specified for the query criteria, you can use the object instance or the primary key of the instance.
For example, if there is a blog object b with id=5, the following three queries are the same:
Entry.objects.filter(blog=b) # Query using object instance Entry.objects.filter(blog=b.id) # Query using id from instance Entry.objects.filter(blog=5) # Query using id directly
0x06 - return to native SQL
If you find that the SQL query statement you need to write is too complex to handle Django's database mapping, you can return to writing SQL manually. Django has several options for writing native SQL; reference resources Execute native SQL queries.
Finally, it is important to understand that the Django database layer is just an interface to access the database. You can also access the database through other tools, programming languages or database frameworks; Django does not do anything unique to the database.
October 11, 2021