61

I have users, videos, topics, criterias and ratings

  • A video has a topic
  • A topic has criterias
  • A user can create a video for a given topic
  • A user can rate a video on each criterias given for the concerned topic.

You can see my original post Django - Rating Model Example DetailView Template to get details on the model used

I have extended a DetailView template based on the video model to put the list of ratings for the selected video for a given user as extra context.

class VideoFileDetailView(DetailView):
  model = VideoFile

  def get_context_data(self, **kwargs):
    context = super(VideoFileDetailView, self).get_context_data(**kwargs)
    context['rates'] = VideoRate.objects.filter(video=self.object, user=self.request.user)
    return context

In the template pointed by the DetailView, I'd like to list the criterias of the video, and for each criteria display the current rating value form the user.

<div id="rating">
  <ul>
{% for crit in videofile.topic.crits.all %}
    <li>
  {% for rate in rates %}
    {% if rate.crit.id == crit.id %}
      {{ rate.rate }}
    {% endif %}
  {% endfor %}
      <div class="rateit"
        data-rateit-value="{# The rating value #}"
        data-rateit-ispreset="true"
        crit-id="{{ crit.id }}"></div>
      {{ crit }}
    </li>
{% endfor %}
  </ul>
</div>

(rateit is a jquery plugin that I use to draw pretty stars rating controls)

Actually I get my rating values here within the 2nd for but I'm sure there is a better way to do that. In fact, I'm still not sure about my model correctness.

Finally I'd like to replace {# The rating value #} by the rating value from rate for the current crit (in the loop). How can I do that ?

Community
  • 1
  • 1
Pierre de LESPINAY
  • 44,700
  • 57
  • 210
  • 307
  • 1
    You could simplify your template code if you add helper properties on your models that do some of this for you, for example the rate for loop. – Ken Cochrane Jun 23 '11 at 10:22
  • 1
    Actually, it would probably be best as a template tag. Pass in `rates` and `crit`, return `rates.filter(crit=crit)` – Chris Pratt Jun 23 '11 at 15:04

2 Answers2

98

Here is my solution (based on a custom tag):

Firstly create the file structure. Go into the app directory where the tag is needed, and add these files:

templatetags
templatetags/__init__.py
templatetags/video_tags.py

The templatetags/video_tags.py file:

from django import template

register = template.Library()

@register.simple_tag
def get_rate(crit, rates):
    return rates.get(crit=crit).rate

The template part, with our tag call:

{% load video_tags %}

<div id="rating">
  <ul>
{% for crit in videofile.topic.crits.all %}
    <li>
      <div class="rateit"
        data-rateit-value="{% get_rate crit rates %}"
        data-rateit-ispreset="true"
        crit-id="{{ crit.id }}"></div>
      {{ crit }}
    </li>
{% endfor %}
  </ul>
</div>
Pierre de LESPINAY
  • 44,700
  • 57
  • 210
  • 307
  • 11
    Shouldn't you import video_tags? {% load video_tags %} – Mc- Mar 25 '13 at 21:45
  • 36
    Also.. "you will need to restart your server before you can use the tags or filters in templates." [from the docs](https://docs.djangoproject.com/en/1.6/howto/custom-template-tags/) – Andrew Jan 30 '14 at 09:13
  • and it still doesn't load it. have no clue at all what's happening – holms Mar 10 '18 at 03:25
  • 2
    'custom_tags' is not a registered tag library. Must be one of: admin_list ... etc – 3pitt Jun 30 '18 at 21:21
17

Inline HTML in tag

If the HTML is small, this method is more convenient than creating a separate file.

This example factors out links to user profiles. The file templatetags/somemodule.py contains:

from django import template
from django.template import Template

register = template.Library()

@register.simple_tag(takes_context=True)
def user_link(context):
    return Template('<a href="{% url \'user_detail\' ' +
            'user.id %}">{{ user.username }}</a>').render(context)

Template#render already returns a safe string which is not XSS escaped. E.g. if we had done just:

return '<br>'

it would be escaped. You might also want to play with mark_safe.

You can make that tag available on all views with:

TEMPLATES = [
    {
        'OPTIONS': {
            'builtins': [
                'myprojectname.templatetags.somemodule',

in settings.py.

See also:

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985