AttributeError at /addtowatchlist/5: объект 'QuerySet' не имеет атрибута 'listings'

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

views.py

from .models import *

def add_to_watchlist(request, listing_id):
    
    listing = Listing.objects.get(id=listing_id)
    # Retrieving the user watchlist (where it always fails)
    watchlist = PersonalWatchList.objects.filter(user=request.user)
    

    # Fails here too
    if (watchlist.listings.all() == None) or (listing not in watchlist.listings.all()):
        watchlist.listings.add(listing)
        watchlist.save()
    else:
        messages.error(request, "Listing is already in your Watchlist.")
        return redirect(reverse('index'))

    messages.success(request, "Listing added to your Watchlist.")
    return redirect(reverse('index'))

models.py

class PersonalWatchList(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    listings = models.ManyToManyField(Listing, blank=True)

    def __str__(self):
        return f"Watchlist for {self.user}"

urls.py

from django.urls import path

from . import views

urlpatterns = [
    path("", views.index, name="index"),
    path("login", views.login_view, name="login"),
    path("logout", views.logout_view, name="logout"),
    path("register", views.register, name="register"),
    path("create", views.createListing, name="create"),
    path("view/<str:listing_title>", views.view, name="view"),
    path("addtowatchlist/<int:listing_id>", views.add_to_watchlist, name="add_to_watchlist")
]

Раздел шаблона, используемый для добавления объявления в список наблюдения

<div class="listing-actions">
<a href= {% url 'view' listing.title %} class="btn btn-primary view-button">View</a>
<!--TODO: Make watchlist-->
<a href={% url 'add_to_watchlist' listing.id %} class="btn btn-primary add-to-watchlist-button">Watchlist</a>
</div> 

Я попробовал изменить свою логику, используя try и except, но это все равно приводит к очень похожей ошибке. В своем urls.py я попробовал изменить имена путей, чтобы они не пересекались, так как "view" и "add_*to_*watchlist" были похожи, но это изменение все равно не помогло. Раньше, в

watchlist = PersonalWatchList.objects.filter(user=request.user)

Вместо этого я использовал get(), и это тоже не помогло. Любые советы будут очень признательны!

Чтобы получить список часов отдельного пользователя, используйте get вместо filter:

watchlist = PersonalWatchList.objects.get(user=request.user)

Использование метода filter() возвращает QuerySet (несколько объектов), а не один уникальный объект, который вам нужен.

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

превращаясь в это:

user = models.ForeignKey(User, on_delete=models.CASCADE)

в это:

user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)

Попробуйте это и прокомментируйте свои результаты.

Мне пришлось изменить свою логику, так как я понял, что причиной возникновения ошибки было то, что пользователь еще не существовал в модели PersonalWatchList. Вот обновленный вариант решения проблемы.

views.py updated

def add_to_watchlist(request, listing_id):
    user = request.user

    # Getting the listing that was clicked
    listing = Listing.objects.get(id=listing_id)

    # Retrieving the user watchlist (if it exists)
    try:
        watchlist_exists = PersonalWatchList.objects.get(user=request.user)
    except:
        watchlist_exists = None

    # If there isn't one for this user, make one
    if watchlist_exists == None:
        PersonalWatchList.objects.create(user=user)

    # Access that watchlist
    watchlist = PersonalWatchList.objects.get(user=user)

    # Comparing the listings already present in their watchlist to the one that was hit
    if (listing not in watchlist.listings.all()):
        watchlist.listings.add(listing)
        watchlist.save()
    else:
        messages.error(request, "Listing is already in your Watchlist.")
        return redirect(reverse('index'))

    messages.success(request, f"'{listing}' added to your Watchlist.")
    return redirect(reverse('index'))

Вернуться на верх