Reputation: 1125
Say I have models called "Post" and "Reaction" and I have made a Post, saved it and now I want to react on it with a Reaction. Now, when I visit my feed where a list of Posts is, I want to show my reaction if I had one.
Which means:
{% if post.my_reaction %}{{ post.my_reaction.contents }}{% endif %}
Now, obviously I want to load more than just one Post; posts which don't have my reactions on it.
I know that I used to solve this with SQL in PHP with
SELECT * FROM Post
LEFT JOIN Reaction ON Reaction.Post = Post.id AND Reaction.Author = <me>
My models:
class Post(models.Model):
content = RichTextField()
author = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
datetime = models.DateTimeField(auto_add_now=True)
class Reaction(models.Model):
reaction = models.CharField(max_length=1)
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name="reactions")
author = models.ForeignKey(User, on_delete=models.CASCADE)
It's not quite clear how I could achieve this in Django
Upvotes: 1
Views: 416
Reputation: 15926
Just drop into raw
:
results = Post.objects.raw("""
SELECT * FROM Post
LEFT outer JOIN Reaction ON Reaction.Post = Post.id AND Reaction.Author = %s
""", [ '<me>', ])
Upvotes: 1
Reputation: 3223
You could achieve this by creating a custom template tag to query the posts for the logged in user. Although it's optional, to me a good place for that query to live would be on the Post model.
class Post(models.Model):
content = RichTextField()
author = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
datetime = models.DateTimeField(auto_add_now=True)
def user_reactions(self, user):
return self.reactions.filter(author=user)
You would then need to create a custom template tag to call that method on the post object while passing in the user from the request.
from django import template
register = template.Library()
@register.simple_tag # (Django >= 1.9, earlier versions need to use `assignment_tag`)
def post_user_reactions(post, user):
return post.user_reactions(user)
This would return a queryset of reactions for that user, which you can then iterate through in the template:
{% post_user_reactions post user as user_reactions %}
{% for reaction in user_reactions %}
Do stuff with reaction object
{% endfor %}
Please keep in mind that making database queries in a for-loop (as you probably are, say if you're displaying a list of posts in this case), can end up being very expensive. You'll want to add a prefetch_related
or a queryset annotation to do this.
As some advice, the Django ORM is a slightly different way of thinking about database access than traditional SQL. Thinking about 'left joins' won't help - you need to think in terms of Django objects and their relationships.
Upvotes: 1