Запросы Django. Как выбрать только уникальный?

#django #django-models #orm #django-templates #django-orm

Вопрос:

Модели:

 class House(Model)

class Flat(Model):
    house = ForeignKey(House, related_name="houses")
    owner = ForeignKey(User)

class User(Model)
 

набор запросов:

 queryset = User.objects.prefetch_related(
    Prefetch("flats", queryset=Flat.objects.select_related("houses"))
 

А потом квартиры:

 {% for flat in user.flats.all %}
<p>№ {{ flat.number }}, {{ flat.house.name }}</p>
{% endfor %}
 

Все в порядке. Но для домов мне нужны только уникальные

 {% for flat in user.flats.all %}
<p>House {{ flat.house.name }}</p>
{% endfor %}
 

Но этот шаблон дает мне ВСЕ дома с дубликатами.
Как я могу избежать дубликатов, каких-либо идей? Я попробовал .distinct (), но это не сработало, похоже, я неправильно использую distinct() или т. Д.

Ответ №1:

Похоже, у вас могут оказаться дубликаты домов, если пользователь принадлежит к owner нескольким flat s, которые все находятся в одном и том же house . Чтобы получить все дома, с которыми пользователь связан через Flat s, вы можете использовать другой запрос, начиная с House , чтобы вы могли использовать distinct :

 distinct_houses = House.objects.filter(flats__owner=user).distinct()
 

Вышесказанное возвращает один объект дома для каждой квартиры, владельцем которой является пользователь, и гарантирует, что у вас нет дубликатов. (Обратите внимание , что выше предполагается related_name , что значение изменено на flats для house = ForeignKey(House, related_name="flats") , так как «дома» в качестве связанного имени похоже на опечатку, связанную с Flat моделью.)

В качестве альтернативы вы могли бы сделать что-то в памяти на Python, если вам все еще нужно знать все Flat s через ваш оригинал queryset = User.objects.prefetch_related(...) и вам не нужен дополнительный запрос. Нравится:

 distinct_houses = {flat.house for flat in user.flats.all()}
 

Примечание: похоже, у вас есть опечатка в необходимости использования Flat.objects.select_related('house') , а не Flat.objects.select_related('houses') на основе имени поля внешнего ключа house .

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

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

Ответ №2:

Найдено только решение с фильтрами шаблонов. Набор запросов:

 queryset = User.objects.filter(status="ACTIVE").prefetch_related(
        Prefetch("flats", queryset=Flat.objects.select_related("house"))
    )
 

С помощью этого я могу получить все квартиры для каждого пользователя:

 {% for user in object_list %}
    {% for flat in user.flats.all %}
        {{ flat.number }}, {{ flat.house.name }}
    {% endfor %}
{% endfor %}
 

И я использую фильтр шаблонов для получения уникальных домов.

 {% for user in object_list %}
    {% for flat in user.flats.all|get_unique_houses %}
        {{ flat.house.name }}
    {% endfor %}
{% endfor %}

# extra_tags.py
@register.filter(name="get_unique_houses")
def get_unique_houses(value):
    return value.distinct('house')