问题
Consider this model
class Exercise(models.Model):
name = models.CharField(max_length=50)
def __unicode__(self):
return self.name
class Score(models.Model):
"""Scores of users by exercise"""
exo = models.ForeignKey(Exercise)
user = models.ForeignKey(User)
score = models.IntegerField()
class Meta:
unique_together = (('exo', 'user',),)
I have a template which displays the Exercise
s.
<ul>
{% for exo in exos %}
<li>{{ exo }}</li>
{% endfor %}
</ul>
Here is the view
def view_exos(request):
"""Lists Exercises"""
objs = {
'exos': Exercise.objects.all(),
}
return render_to_response('content/contents.html', objs
, context_instance=RequestContext(request)
)
Now I'd like to display the Score
of the current user in front of each Exercise
(if there is one) in order to access it from the template in this manner:
<li>{{ exo }} - {{ exo.user_score }}</li>
回答1:
What I'd do would be to get all the user's current scores up front, create a dictionary mapping exercise to score, then add the score as an attribute of each exercise. Something like:
user_scores = request.user.score_set.all()
score_dict = dict((sc.exo_id, sc.score) for sc in user_scores)
exos = Exercise.objects.all()
for ex in exos:
ex.current_user_score = score_dict.get(ex.id)
Now each exercise in exos
has a current_user_score
attribute, which is the current user's score for that exercise (or None).
回答2:
django.contrib.auth
has a context processor that adds a user
variable to the template context, referencing the current user. This can enable you to get all scores for the current user, then you can create a template filter that returns the score for a particular exercise.
In a file named exercises.py
within a templatetags
package.
[Put the package in the folder of one of your apps in INSTALLED_APPS
. Remember templatetags
must be a valid Python package ie. with an __init__.py
]
from django.template import Library
register = Library()
@register.filter
def score_for_exercise(scores, exercise):
s = scores.filter(exo=exercise)
if s:
return s[0].score
return None
In the template:
{% load exercises %}
{% with user.score_set.all as user_scores %}
<ul>
{% for exo in exos %}
{% with user_scores|score_for_exercise:exo as score %}
<li>{{ exo }}{% if score %} - {{score}}{% endif %}</li>
{% endwith %}
{% endfor %}
</ul>
{% endwith %}
回答3:
Maybe you can add an attribute to your Exercise
:
class Exercise(models.Model):
name = models.CharField(max_length=50)
def __unicode__(self):
return self.name
def user_score(self):
return Score.objects.get(exo=self).score
来源:https://stackoverflow.com/questions/7685012/django-prepare-objects-from-a-view-for-current-user