Reputation: 329
I have the following table in my Django model, Dishes and Likes. On my home page I am showing a list of all the dishes in the database, and I have a like button on each dish. For dishes that the user has liked I want to indicate that they already liked it, so that they can unlike it and vice versa. I have been trying different approaches for the last few days but can't seem to figure anything out. Here is the code for my latest unsuccessful attempt.
#dishes table
class Dishes(models.Model):
name = models.CharField(max_length=40, unique=True)
def liked(dish, user):
try:
user_upvoted = Likes.objects.get(dish=dish, user=user)
except:
user_upvoted = None
if user_upvoted:
return True
else:
return False
#upvotes
class Likes(models.Model):
dish = models.ForeignKey(Dishes)
user = models.ForeignKey(User)
date_added = models.DateTimeField(auto_now_add=True)
def home(request):
this_user = auth.models.User.objects.get(id=1)
dishes = models.Dishes.objects.all()
for dish in dishes:
models.Dishes.voted(dish, this_user)
`enter code here`return render_to_response('frontend/home.html', { 'dishes': dishes, })
Upvotes: 4
Views: 1082
Reputation: 174622
Adding a ManyToMany makes this an easy problem to solve:
class Dishes(models.Model):
name = models.CharField(max_length=40, unique=True)
likes = models.ManyToManyField(Likes)
class Likes(models.Model):
dish = models.ForeignKey(Dishes)
user = models.ForeignKey(User)
date_added = models.DateTimeField(auto_now_add=True)
Adjust your view like this:
from django.contrib.auth.decorators import login_required
from django.shortcuts import render
@login_required
def home(request):
dishes = Dishes.objects.all()
return_list = []
for dish in dishes:
return_list.append((dish, dish.likes_set.filter(user=request.user)))
return render(request, 'dish_list.html', {'dishes': return_list})
Your template is where you do the "toggle":
{% for dish, liked in dishes %}
{{ dish.name }}
{% if liked %}
You already like this dish.
{% else %}
Like this dish now, its yummy!
{% endif %}
{% endfor %}
Or, if you can't change your model, adjust your view code like this:
@login_required
def home(request):
dishes = Dishes.objects.all()
return_list = []
for dish in dishes:
return_list.append((dish,
Likes.objects.filter(user=request.user, dish=dish)))
return render(request, 'dish_list.html', {'dishes': return_list})
The idea is that the list of objects you return to the template is already flagged for the user that is logged in.
The login_required
decorator makes sure that the view is only called when a user is logged in. Otherwise, it will redirect the user to the login page.
The render
shortcut will make sure that RequestContext
is always passed from your views.
Upvotes: 2
Reputation: 9112
You need a new model and assuming you are using django User model, you could have something like this:
models.py
from django.contrib.auth.models import User
class DishLiked(models.Model):
dish = models.ForeignKey(Dish,
related_name='liked_by'
)
like = models.ForeignKey(Like,
related_name='like_by'
)
user = models.ForeignKey(User,
related_name='liked_dishes'
)
views.py
Note: also note they way of getting user from request
:
def home(request):
user = request.user
liked = DishLiked.objects.filter(
user__id=user.id
)
dish_id_list = []
for liked_dish on liked:
dish_id_list.append(liked_dish.dish.pk)
dishes_liked_by_user = Dish.objects.filter(id__in=dish_id_list)
Upvotes: 0