Как проверить, существует ли объект во многих ко многим django?

#django #django-queryset #django-orm

Вопрос:

У меня есть две модели:

 Model Student:
     name = models.CharField()
     ..... ....
     wishlist = models.ManyToManyField(University, blank=True)

Model University:
      name = models.CharField()
      ...... . .. . . . .
 

В основном я просто создаю список пожеланий, с помощью которого пользователь может поставить лайк на университет, а затем добавить его в свой список пожеланий ! ( я выражаю это через значок сердца ), Поэтому, когда пользователь повторно нажимает на тот же элемент, он удалит его из списка желаний, вот и все !

Проблема в том, как проверить, понравился ли пользователю тот или иной университет ?

вот мой код:

 def index(request):
    univesity = University.objects.filter(is_approved=True)
    context = {'univesity': univesity}
    return render(request, 'search/index.html', context)
 

выше я привожу весь университет для целей поиска ! В этом случае мне нужно проверить, не добавило ли использование университета в список желаний. И если это правда, то значок сердца превратится в красный или пустой цвет !

А теперь вот как я показываю на шаблоне

 {% if data.student_set.all %}
     <button><em class="icon ni ni-heart-fill" ></em></button>
{% else %}
     <button><em class="icon ni ni-heart"></em></button>
{% endif %}
 

Это работает не так, как я ожидал ! пожалуйста, направьте

Ответ №1:

Вы можете проверить, понравился ли этому человеку университет, Universities снабдив его Exists подзапросом [Django-doc]:

 from django.contrib.auth.decorators import login_required
from django.db.models import Exists, OuterRef

@login_required
def index(request):
    universities = University.objects.annotate(
        liked=Exists(Student.wishlist.through.objects.filter(
            student=request.user, university_id=OuterRef('pk')
        ))
    ).filter(is_approved=True)
    context = {'universities': universities}
    return render(request, 'search/index.html', context) 

Если Student это модель пользователя. Если это не так, вам сначала следует выбрать вошедшего в систему пользователя и использовать его в .filter(student=…, …) части.

Затем мы можем отобразить это в шаблоне с помощью:

 {% for university in universities %}
    {{ university }}
    {% if university.liked %}
        <button><em class="icon ni ni-heart-fill" ></em></button>
    {% else %}
         <button><em class="icon ni ni-heart"></em></button>
    {% endif %}
{% endfor %} 

Примечание. Вы можете ограничить просмотры представлением для пользователей, прошедших проверку подлинности, с
помощью @login_required декоратора [Django-doc].

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

1. О боже, я не мог понять аннотацию — неужели так сложно выполнить обратный поиск ?

2. @sixovov947: не для фильтрации, но здесь мы делаем подзапрос, чтобы проверить, есть ли список желаний учащихся с именем пользователя request.suer и university_id первичным ключом University .

3. что такое «Внешняя ссылка» и выполнение подзапроса считается дополнительным запросом и настолько эффективно ?

4. @sixovov947: никакие подзапросы не являются частью запроса, поэтому вся работа выполняется базой данных, а не дополнительными запросами из Django. OuterRef относится к полю, которое относится не к подзапросу, а к внешнему запросу (поэтому здесь запрос University модели, мы, таким образом, ссылаемся на первичный ключ University , по которому мы определяем, понравился ли пост).

5. Это выдает ошибку «объект » Существует» не имеет атрибута»фильтр»».