简体   繁体   中英

Django queryset of related objects

Having the following model:

class Company(models.Model):
    name = models.CharField(max_length=10)
    
class Department(models.Model):
    name = models.CharField(max_length=10)
    company = models.ForeignKeyField(to=Company)
    persons = models.ManyToManyField(to=Person, on_delete=models.PROTECT)

class Person(models.Model):
    name = models.CharField(max_length=10)


I would like to get a queryset of all persons in a company

Using

def persons_by_company(company_name):
    l = []
    for d in Department.objects.filter(company__name=company_name):
        for p in d.persons:
            l.append(p)
    return l

would be

  1. slow
  2. does return a list and not a queryset (is not filterable, etc)

What would be the way to get a queryset here?

In my case, I think it's quite simple with just

Person.objects.filter(departement__company__id=company_id).distinct()

or with the company name:

Person.objects.filter(departement__company__name__iexact=company_name).distinct()

Your function would become:

def persons_by_company(company_name):
    return Person.objects.filter(departement__company__name__iexact=company_name).distinct()

It returns a queryset and it's faster. I use iexact to avoid case sensitive.

UPDATED: .distinct() Just to remove duplicate entries.

First you must have foreign key binded to your company or department

class Department(models.Model):
    name = models.CharField(max_length=10)
    company = models.ForeignKeyField(to=Company, related_name="department_company_key")

class Person(models.Model):
    name = models.CharField(max_length=10)
    person_department = models.ForeignKey(
        'Department',
        related_name="person_department_key"
        on_delete=models.CASCADE,
        blank=False,
        null=False
    )

then in your function:

def persons_by_company(company_name):
    l = []
    for d in Department.objects.filter(company__name=company_name):
        for p in d.person_department_key.all(): # You also apply some filter()
            l.append(p) # Remember This will append object  not  string or dictionary
    return l

Don't forget that related name must be unique

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM