Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletter Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds
Arrow up icon
GO TO TOP
Mastering Django: Core

You're reading from   Mastering Django: Core The Complete Guide to Django 1.8 LTS

Arrow left icon
Product type Paperback
Published in Dec 2016
Publisher
ISBN-13 9781787281141
Length 694 pages
Edition 1st Edition
Languages
Tools
Arrow right icon
Author (1):
Arrow left icon
Nigel George Nigel George
Author Profile Icon Nigel George
Nigel George
Arrow right icon
View More author details
Toc

Table of Contents (33) Chapters Close

Mastering Django: Core
Credits
About the Author
www.PacktPub.com
Preface
1. Introduction to Django and Getting Started FREE CHAPTER 2. Views and URLconfs 3. Templates 4. Models 5. The Django Admin Site 6. Forms 7. Advanced Views and URLconfs 8. Advanced Templates 9. Advanced Models 10. Generic Views 11. User Authentication in Django 12. Testing in Django 13. Deploying Django 14. Generating Non-HTML Content 15. Django Sessions 16. Djangos Cache Framework 17. Django Middleware 18. Internationalization 19. Security in Django 20. More on Installing Django 21. Advanced Database Management Model Definition Reference Database API Reference Generic View Reference Settings Built-in Template Tags and Filters Request and Response Objects Developing Django with Visual Studio

Related objects


When you define a relationship in a model (that is, a ForeignKey, OneToOneField, or ManyToManyField), instances of that model will have a convenient API to access the related object(s).

Using the models at the top of this page, for example, an Entry object e can get its associated Blog object by accessing the blog attribute: e.blog.

(Behind the scenes, this functionality is implemented by Python descriptors. This shouldn't really matter to you, but I point it out here for the curious.)

Django also creates API accessors for the other side of the relationship-the link from the related model to the model that defines the relationship. For example, a Blog object b has access to a list of all related Entry objects via the entry_set attribute: b.entry_set.all().

All examples in this section use the sample Blog, Author and Entry models defined at the top of this page.

One-to-many relationships

Forward

If a model has a ForeignKey, instances of that model will have access to the related (foreign) object via a simple attribute of the model. For example:

>>> e = Entry.objects.get(id=2)
>>> e.blog # Returns the related Blog object.

You can get and set via a foreign-key attribute. As you may expect, changes to the foreign key aren't saved to the database until you call save(). Example:

>>> e = Entry.objects.get(id=2)
>>> e.blog = some_blog
>>> e.save()

If a ForeignKey field has null=True set (that is, it allows NULL values), you can assign None to remove the relation. Example:

>>> e = Entry.objects.get(id=2)
>>> e.blog = None
>>> e.save() # "UPDATE blog_entry SET blog_id = NULL ...;"

Forward access to one-to-many relationships is cached the first time the related object is accessed. Subsequent accesses to the foreign key on the same object instance are 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.

Note that the select_related() QuerySet method recursively prepopulates the cache of all one-to-many relationships ahead of time. Example:

>>> 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.

Following relationships backward

If a model has a ForeignKey, instances of the foreign-key model will have access to a Manager that returns all instances of the first model. By default, this Manager is named foo_set, where foo is the source model name, lowercased. This Manager returns QuerySets, which can be filtered and manipulated as described in the Retrieving objects section above.

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 override the foo_set name by setting the related_name parameter in the ForeignKey definition. For example, if the Entry model was altered to blog = ForeignKey(Blog, related_name='entries'), the above example code would 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()

Using a custom reverse manager

By default, the RelatedManager used for reverse relations is a subclass of the default manager for that model. If you would like to specify a different manager for a given query you can use the following syntax:

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 performed default filtering in its get_queryset() method, that filtering would apply to the all() call.

Of course, specifying a custom reverse manager also enables you to call its custom methods:

b.entry_set(manager='entries').is_published() 

Additional methods to handle related objects

In addition to the QuerySet methods defined in Retrieving objects earlier, the ForeignKey Manager has additional methods used to handle the set of related objects. A synopsis of each is as follows (complete details can be found in the related objects reference at https://docs.djangoproject.com/en/1.8/ref/models/relations/#related-objects-reference):

  • add(obj1, obj2, ...) Adds the specified model objects to the related object set
  • create(**kwargs) Creates a new object, saves it and puts it in the related object set. Returns the newly created object
  • remove(obj1, obj2, ...) Removes the specified model objects from the related object set
  • clear() Removes all objects from the related object set
  • set(objs) Replace the set of related objects

To assign the members of a related set in one fell swoop, just assign to it from any iterable object. The iterable can contain object instances, or just a list of primary key values. For example:

b = Blog.objects.get(id=1) 
b.entry_set = [e1, e2] 

In this example, e1 and e2 can be full Entry instances, or integer primary key values.

If the clear() method is available, any pre-existing objects will be removed from the entry_set before all objects in the iterable (in this case, a list) are added to the set. If the clear() method is not available, all objects in the iterable will be added without removing any existing elements.

Each reverse operation described in this section has an immediate effect on the database. Every addition, creation and deletion is immediately and automatically saved to the database.

Many-to-many relationships

Both ends of a many-to-many relationship get automatic API access to the other end. The API works just as a backward one-to-many relationship, above.

The only difference is in the attribute naming: The model that defines the ManyToManyField uses the attribute name of that field itself, whereas the reverse model uses the lowercased model name of the original model, plus '_set' (just like reverse one-to-many relationships).

An example makes this easier to understand:

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. 

Like ForeignKey, ManyToManyField can specify related_name. In the above example, if the ManyToManyField in Entry had specified related_name='entries', then each Author instance would have an entries attribute instead of entry_set.

One-to-one relationships

One-to-one relationships are very similar to many-to-one relationships. If you define a OneToOneField on your model, instances of that model will have access to the related object via a simple attribute of the model.

For example:

class EntryDetail(models.Model): 
    entry = models.OneToOneField(Entry) 
    details = models.TextField() 
 
ed = EntryDetail.objects.get(id=2) 
ed.entry # Returns the related Entry object. 

The difference comes in reverse queries. The related model in a one-to-one relationship also has access to a Manager object, but that Manager represents a single object, rather than a collection of objects:

e = Entry.objects.get(id=2) 
e.entrydetail # returns the related EntryDetail object 

If no object has been assigned to this relationship, Django will raise a DoesNotExist exception.

Instances can be assigned to the reverse relationship in the same way as you would assign the forward relationship:

e.entrydetail = ed 

Queries over related objects

Queries involving related objects follow the same rules as queries involving normal value fields. When specifying the value for a query to match, you may use either an object instance itself, or the primary key value for the object.

For example, if you have a Blog object b with id=5, the following three queries would be identical:

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 
lock icon The rest of the chapter is locked
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at £13.99/month. Cancel anytime
Visually different images