Reputation: 4371
here is the view function I am using
views.py
def favorite_item (request, pk):
favitem = get_object_or_404(Item, pk=pk)
userfav = Favorite.objects.filter(user=request.user)
for items in userfav:
if items.item == favitem:
items.delete()
else:
new_entry = Favorite(item=favitem, user=request.user)
new_entry.save()
return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
the part of deleting already exists row working perfectly :
if items.item == favitem:
items.delete()
but i think the problem is where i try to add a new row , just returns nothing not even raising an error !
else:
new_entry = Favorite(item=favitem, user=request.user)
new_entry.save()
Upvotes: 1
Views: 133
Reputation: 476557
The logic is probably off. favitem
is probably the item the user wants to favorite/unfavorite. Furthermore userfav
is the list of favorite items of that user.
if
-else
clauses in for
loopsBut then you start iterating over that list. In case the Favorite
is the item to favorite you remove it (this is probably correct). But in case the item in the favorite list of the user is not the favorite of that user, you add another Favorite
object, so now there are two Favorites
linking such element with the user.
You probably want to execute the else
part only in case the if
part was never (i.e. in no loop) was executed. We can do that with a for
-else
construct:
for items in userfav:
if items.item == favitem:
items.delete()
break
else:
new_entry = Favorite(item=favitem, user=request.user)
So note that here the else
is at the same level as the for
loop. And the
breakis crucial, since this will make sure the
else` part is not fired.
But we make it too hard. We can simply let Django perform the filtering, and remove the favorites. We can filter(..)
the queryset on the item
as well, and remove these entries. In case no entry was removed, we can then add such Favorite
entry:
def favorite_item (request, pk):
favitem = get_object_or_404(Item, pk=pk)
num, __ = Favorite.objects.filter(user=request.user, item=favitem).delete()
if not num:
new_entry = Favorite.objects.create(item=favitem, user=request.user)
return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
So here num
will contain the number of Favorite
entries removed. In case that is not zero, we removed one or more Favorite
s for which the user is request.user
, and item
is our favitem
.
In case num
is not zero, we then .create(..)
a new Favorite
.
Favorite
modelYou also better constrain your Favorite
model. Right now, it looks like a user can make the same Item
their Favorite
multiple times. You better use unique_together
for this, to prevent that:
class Favorite(models.Model):
item = ForeignKey(Item, on_delete=models.CASCADE)
user = ForeignKey(User, on_delete=models.CASCADE)
class Meta:
unique_together = (('item', 'user'), )
Of course I here make some assumptions on how the Favorite
model looks. The important part is however the unique_together
.
In case we have added such constraint, we know that for a .filter(user=..., item=...)
there will always be at most one such element. So in that case the logic is even simpler:
def favorite_item (request, pk):
favitem = get_object_or_404(Item, pk=pk)
try:
Favorite.objects.get(user=request.user, item=favitem).delete()
except Favorite.DoesNotExist:
new_entry = Favorite.objects.create(item=favitem, user=request.user)
return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
Upvotes: 1