Selecting related foreignkeys in Django - django

Say I have two models, Article and Category:
class Article(models.Model):
category = models.ForeignKey(Category, related_name='articles')
class Category(models.Model):
...
When I run Category.objects.select_related(), the ORM does not select the articles. I realize it's because of the way the foreignkey is shuffled around, but I'm not sure how to go about doing that. Any ideas?

Here's what I ended up doing, at the advice of the kind people on #django:
articles = Article.objects.select_related()
categories = {}
for article in articles:
if not categories.get(article.category, None):
categories[article.section] = []
categories[article.category].append(article)

Related

Django QuerySet to return unique objects in ManyToMany fields

Given the following models:
class Author(models.Model):
name = models.CharField()
class Book(models.Model):
title = models.CharField()
published_year = models.PositiveIntegerField()
authors = models.ManyToManyField(Author)
Let's say I want to get all of the authors who have authored a book published in the year 2008. I can do the following:
Book.objects.filter(published_year=2008).values_list('authors__name').distinct()
That'll get me a list of authors - almost exactly what I want, except that instead of just the names, I want the Author objects. I can achieve that somewhat by doing this:
authors = []
for b in Book.objects.filter(published_year=2008):
for a in b.authors.all():
if a not in authors:
authors.append(a)
But that seems totally unnecessary. Is it possible to get the QuerySet to do that work for me? Thanks!
Just use backward relationship
Author.objects.filter(book__published_year=2008).all()
From Django docs
Reverse m2m queries are supported (i.e., starting at the table that
doesn’t have a ManyToManyField):

Defining a two way many to many in Django

Just starting in Python/Django framework so sorry if this is dumb... but i cant find any solution.
class Dealer(models.Model):
name = models.CharField(max_length=200)
contacts = models.ManyToManyField(Contact)
class Contact(models.Model):
name = models.CharField(max_length=200)
dealers = models.ManyToManyField(Dealer)
I have this relation set up however when I run SyncDB it doesnt work. It tells me that Contact is not defined on this line
contacts = models.ManyToManyField(Contact)
Im more familiar with compiled languages. Is there anyway to tell python that the contact class exists, or better yet is there a special syntax im missing for defining this kind of relation.
I dont see a need for a two way ManyToMany in both the models, as they are a M:N relationship (2 way relationship).
Your issue here is, Contact is not defined at the point of execution of this code:
contacts = models.ManyToManyField(Contact)
So You need to wrap it in quotes for it to work
contacts = models.ManyToManyField('Contact')
Documentation on that can be found here
I would recommend the following models:
class Dealer(models.Model):
name = models.CharField(max_length=200)
contacts = models.ManyToManyField('Contact')
class Contact(models.Model):
name = models.CharField(max_length=200)
and It would do exactly what you are looking for.
You can read about ManyToMany relationships here. The same link also covers how to handle Reverse m2m queries
If you want to do a two way ManyToMany both, you just only need to do this:
class Dealer(models.Model):
name = models.CharField(max_length=200)
contacts = models.ManyToManyField('Contact', blank=True)
class Contact(models.Model):
name = models.CharField(max_length=200)
dealers = models.ManyToManyField('Dealer', through=Dealer.projects.through, blank=True)
I guess it will work to you.

Django fetch all relations

I have an app with a similar structure as this snippet
class Blog(models.Model):
name = models.CharField(max_length=25)
class Category(models.Model):
name = models.CharField(max_length=25)
blog = models.ForeignKey(Blog)
class Entry(models.Model):
title = models.CharField(max_length=25)
category = models.ForeignKey(Category)
What is the most generic way, that i will be able to use in other apps to fetch all blogs with their category and entries?
I thought about creating a manager for the Blog model, that can fetch all the Categories for that blog, but it's hardcoding the model names
class BlogManager(models.Manager):
def categories(self):
return Category.objects.filter(blog=self)
Any suggestions?
What you want is a Select Related. It returns a QuerySet that will automatically "follow" foreign-key relationships, selecting that additional related-object data when it executes its query. Your query for Blogs would look something like:
Blog.objects.select_related().filter( something )
or
Blog.objects.select_related().get( something )
Why not use a standard way?
Filter using Blog's PK with FK relation.
Category.objects.filter(blog__pk=self.pk)

Django - many-to-one relationship - how to select parent models that have children only

Say I have this model relationship in Django 1.2...
class Section(models.Model):
title = models.CharField(max_length=200)
class Page(models.Model):
section = models.OneToOneField(Section)
title = models.CharField(max_length=200)
I want to select Sections that have one or more Pages associated with them, how would I achieve this in a query? Or would I have to select all sections and then filter out one's that do not have pages manually?
Change to:
class Section(models.Model):
title = models.CharField(max_length=200)
page = models.ForeignKey(Page, related_name="section")
class Page(models.Model):
title = models.CharField(max_length=200)
select Sections that have one or more Pages associated:
result_q = Section.objects.filter(page__isnull=False)
I would second sza's answer if was 100% sure that isnull works in all such cases - but I haven't checked that so I'm not sure (even though I occasionaly use it for such purposes) :-)
What I'm sure of is this:
from django.db import models
Section.objects.annotate(page_num=models.Count('page')).filter(page_num__gt=0)
-- and while counting might be an overkill for your case wih OneToOneField relationship, it definitely works.

Django order by related field

I want to sort a QuerySet of contacts by a related field. But I do not know how.
I tried it like this, but it does not work.
foundContacts.order_by("classification.kam")
Actually in a template I can access the kam value of a contact through contact.classification.kam since it is a OneToOne relationship.
The (simplified) models look like this:
class Classification(models.Model):
kam = models.ForeignKey(User)
contact = models.OneToOneField(Contact)
class Contact(models.Model):
title = models.ForeignKey(Title, blank=True, null=True)
first_name = models.CharField(max_length=200)
last_name = models.CharField(max_length=200)
It should be:
foundContacts.order_by("classification__kam")
Here is a link for the Django docs on making queries that span relationships: https://docs.djangoproject.com/en/dev/topics/db/queries/#lookups-that-span-relationships
You can also see some examples in the order_by reference:
https://docs.djangoproject.com/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.order_by
as the documentation indicates, it should be used as in queries about related models
https://docs.djangoproject.com/en/3.0/ref/models/querysets/#order-by
foundContacts.order_by("classification__kam")
I've struggled a lot with this problem, this is how I solved it:
contact ordered by "kam" (Classification) field:
show_all_contact = Contact.objects.all().order_by(title__kam)
classification ordered by Users email (no sense in it, but only show how it works):
show_all_clasification = Classification.objects.all().order_by(kam__email)