Reputation: 691
As an example, I will use the following code, showing a 'question' similar to stack overflow, and User specific information, e.g., having starred the post.
class Question(models.Model):
title = models.CharField(max_length=200)
body = models.CharField(max_length=2000)
class Star(models.Model):
owner = models.ForeignKey(User, on_delete=models.CASCADE)
question = models.ForeignKey(Question, on_delete=models.CASCADE)
starred = models.BooleanField()
The goal is now to create a list of all (or the last 20) questions and show a user in this overview which ones they starred.
How to Handle bad Questions? (X)
Why use Fluroid in toothpaste? ( )
Where is Waldo? (X)
This is dependent on the current logged in user.
Creating the list is straight forward, but adding in the boolean seems rather clumsy or inefficient, while in direct SQL, this could be expressed as a left outer join (just fill up non existent values with false).
I tried:
So I wondered if there is a simple way to handle this pattern? Edit: The answer seems to be: No, there is no simple way, but the accepted answer helped me reach a solution (thanks).
Note: I rewrote the question for clarity. Please keep in mind I am a beginner with Django and might have missed some crucial simple thing.
After rephrasing the question I realized it is similar to implementing a like button: Django Like Button
Upvotes: 0
Views: 81
Reputation: 424
New answer based on your edited question:
This "solution" is a guess. So please try it out. It might not work exactly as written, or a valid solution might be outside of what I can think of right now.
views.py:
questions = Question.objects.all()
# limit your results now
# I assume 'questions' going forward was reduced to the number of results you want to show
starred_questions = questions.filter(star_set__owner=request.user, star_set__starred=True)
for question in questions:
question.starred = question in starred_questions
# get 'questions' to your view now
my_template.html:
{% for question in questions %}
<p>{{ question }}(
{% if question.starred %}
X
{% endif %}
)</p>
{% endfor %}
I hope this approach will help you reach your goal.
Old answer: Based on
I wanted to show a list of all As and show the associated Bs for a user.
this phrase I guess your view is user specific? Meaning that if user X visits that view, that user sees their own values and if user Y visits that view, they see their own values ones again?
all_b_of_user = request.user.b_set.all().select_related('a')
select_related
gets all a data in that same query, to reduce query count, thus response time. doc
If on the other hand you want to show all values of all users on some sort of overview (some user Z is allowed to see all values of X and Y) you'll need to create as many DB queries as you have Users as far as I know.
Upvotes: 1
Reputation: 1500
from django.views import View
from django.contrib.auth.mixins import LoginRequiredMixin
from .models import Question, Star
class StarredQuestionsView(LoginrequiredMixin, View):
def get(self, request):
starred_questions = Star.objects.filter(owner=request.user).filter(starred=True)
return render(request, "app/list-of-starred-questions.html", {'starred_questions': starred_questions})
This should give you a queryset of all a user's starred questions. In your view, you can do something like this:
{% for question in starred_questions %}
<ul>
<li>{{ question.question.title }}</li>
</ul>
{% endfor %}
Hope this sets you on the right path.
Upvotes: 1