Compare attributes of a Django Queryset in a template using the `in` Operator
I'm trying to use the in
operator to determine if a template variable on the current page is also a foreign key in another model.
The model is like so:
class WishlistItem(models.Model):
user = models.ForeignKey(User, related_name='wishlist_items')
issue = models.ForeignKey(Issue)
On the "Issue" 开发者_如何学JAVApage template, I'm trying to do this:
{% if issue in user.wishlist_items %}
{% else %}
{# A button to add the issue to the user's wishlist #}
{% endif %}
What I need to do is to get at the issue
attribute of the wishlist_items
QuerySet for the currently logged-in user and compare it to the issue
object of the current page. I'm at a loss for how to do this. Do I need to write a templatetag to do this?
I ended up solving this by writing a template filter:
@register.filter
def in_list(obj, arg):
"Is the issue in the list?"
return obj in (item.issue for item in arg)
Then I could do something like this in a template:
{% if issue|in_list:user.wishlist_items.all %}
I got the idea from the answer on this Stack Overflow question.
It seems that there's a relationship between User
and wishlist issues that you ought to express as a ManyToManyField
on the User
. If there is extra metadata about the relationship that you need to record in a WishlistItem
, then use through=WishlistItem
.
If the User
model is from the auth
app, you'll need to extend the User
model to achieve this (see this blog post for some help). For example:
class MyUser(User):
wishlist_issues = models.ManyToManyField(Issue, through=WishlistItem)
# ...
Then, in your template use:
{% if issue not in user.wishlist_issues %}
{# A button to add the issue to the user's wishlist #}
{% endif %}
wishlist_items
is not a queryset - it's a manager. wishlist_items.all
IS a queryset, but obviously it is a queryset of WishlistItem
objects, not Issue
objects. What I would do is handle this logic in the view... something like:
user_has_issue = issue in (wl.issue for wl in request.user.wishlist_items.all())
If I understood correctly, instead of writing a templatetag for it you can pass that as a parameter of the view.
def myView(request):
return render_to_response('template.html',
{'query': queryToCheckIfIssueInWishList},
RequestContext(request))
I think what you are refering to should go into the view, more than the template.
Of course, you could create some templatetag, however Django's approach to templates is to maintain them as dumb as possible, and move all logic to the view.
On the other hand, moving the logic in the view, and then passing the additional information to the template should be quite straightforward, and I would definitely go for that solution.
精彩评论