Django - Prepare objects from a view for Current User

一笑奈何 提交于 2019-12-11 12:46:15

问题


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 Exercises.

<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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!