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'))