Набор запросов Django связанных объектов

#python #django #django-queryset

#python #django #django-набор запросов

Вопрос:

Имея следующую модель:

 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)


  

Я хотел бы получить queryset список всех людей в компании

Использование

 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
  

было бы

  1. медленно
  2. возвращает список, а не набор запросов (не поддается фильтрации и т. Д.)

Каков был бы способ получить здесь набор запросов?

Комментарии:

1. Как насчет этого Person.objects.filter(departement__company__id=company_id) ?

Ответ №1:

В моем случае, я думаю, это довольно просто, просто

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

или с названием компании:

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

Ваша функция станет:

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

Он возвращает набор запросов, и это быстрее. Я использую iexact , чтобы избежать учета регистра.

ОБНОВЛЕНО: .distinct() Просто чтобы удалить повторяющиеся записи.

Комментарии:

1. Я не думаю, что это работает — отдел — это поле «многие ко многим» (у человека может быть несколько отделов

2. Правильно, но вы используете department только для поиска в company, он просто перечислит все записи person, связанные с данным названием компании. Вы его тестировали?

3. Вы были правы, в моем случае для отдела больше ограничений, тогда я использую Q-запрос? т.Е. Я хотел бы получить его из Department.objects.filter(name__icontains="A")

4. Да, вы можете использовать его для поиска по разным полям

5. К сожалению, это решение не работает — если человек находится в двух отделах компании, он возвращается дважды

Ответ №2:

Сначала у вас должен быть внешний ключ, привязанный к вашей компании или отделу

 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
    )
  

затем в вашей функции:

 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
  

Не забывайте, что связанное имя должно быть уникальным

Комментарии:

1. (Моя реальная модель намного сложнее, это был всего лишь минимальный пример). Я не могу изменить модель — особенно ваша технически отличается — она имеет отношение от N до 1 человека к отделу, моя модель имеет отношение от M до N

2. Имеет ли в вашей модели один человек ccacn более одного отдела?