Ошибка в строке количества Django в шаблоне

Я сталкиваюсь с проблемами, пытаясь получить счет. Надеюсь, ты сможешь мне помочь.

В шаблоне, если я вставлю {{ message.count }} не произойдет ', потому что сообщение является строкой. Если я вставляю {% load inbox %} {% inbox_count как message %}, он возвращает все непрочитанные сообщения, но мне нужно получить непрочитанные сообщения, отправленные данным пользователем, в моем случае, кандидатом на должность.

Как мне это сделать?

#models.py
 class CandidateToJob(models.Model):
     job = models.ForeignKey(Job, related_name='applied_to')
     candidate = models.ForeignKey(Candidate, related_name='from_user')
     STATUS_CHOICES = (
        ('0', 'New'),
        ('1', 'Not approved'),
        ('2', 'Approved')
     )
     status = models.CharField(max_length=2, choices=STATUS_CHOICES)

     def __unicode__(self):
        return self.candidate.user.get_full_name()

 AUTH_USER_MODEL = getattr(settings, 'AUTH_USER_MODEL', 'auth.User')

 class MessageManager(models.Manager):

    def inbox_for(self, user):
        """
        Returns all messages that were received by the given user
        """
        return self.filter(
            recipient=user
        )

class Message(models.Model):
    """
    A private message from user to user
    """
    body = models.TextField(_("Mensagem"))
    sender = models.ForeignKey(AUTH_USER_MODEL, related_name='sent_messages')
    recipient = models.ForeignKey(AUTH_USER_MODEL, related_name='received_messages', null=False, blank=True)
    sent_at = models.DateTimeField(null=True, blank=True)
    read_at = models.DateTimeField(_("read at"), null=True, blank=True)

    objects = MessageManager()

    def __unicode__(self):
        return self.sender.username

def inbox_count_for(user):
    """
    returns the number of unread messages for the given user but does not
    mark them seen
    """
    return Message.objects.filter(recipient=user, read_at__isnull=True).count()

Вид

#views.py
class Screening(generic.DetailView):
    model = Job
    template_name = 'dashboard/screening.html'

    def get_context_data(self, **kwargs):
        context = super(Screening, self).get_context_data(**kwargs)
        context['candidate_list'] = self.object.applied_to.all().order_by('candidate')
        context['messages_received'] = Message.objects.inbox_for(self.request.user)
        return context

Шаблон

#template.html

{% for candidate in candidate_list %}

    {{ candidate.get_full_name }}
    {{ candidate.candidate.city }}

    {% for message in messages_received %}
        {% if candidate.candidate.user == message.sender %}
            {{ message }}
        {% endif %}
    {% endfor %}

{% endfor %}

тег шаблона

#inbox.py
from django.template import Library, Node, TemplateSyntaxError

class InboxOutput(Node):
    def __init__(self, varname=None):
        self.varname = varname

    def render(self, context):
        try:
            user = context['user']
            count = user.received_messages.filter(read_at__isnull=True).count()
        except(KeyError, AttributeError):
            count = ''
        if self.varname is not None:
            context[self.varname] = count
            return ""
        else:
            return "%s" % (count)

 def do_print_inbox_count(parser, token):
     """
    A templatetag to show the unread-count for a logged in user.
    Returns the number of unread messages in the user's inbox.
    Usage::

        {% load inbox %}
        {% inbox_count %}

        {# or assign the value to a variable: #}

        {% inbox_count as my_var %}
        {{ my_var }}

    """
    bits = token.contents.split()
    if len(bits) > 1:
        if len(bits) != 3:
            raise TemplateSyntaxError("inbox_count tag takes either no arguments or exactly two arguments")
        if bits[1] != 'as':
            raise TemplateSyntaxError("first argument to inbox_count tag must be 'as'")
        return InboxOutput(bits[2])
    else:
        return InboxOutput()

 register = Library()
 register.tag('inbox_count', do_print_inbox_count)

1 ответ

Решение

Вы не можете выполнять сложную логику, как вы хотите на языке шаблонов. Мне нравится этот факт, потому что он помогает вам не вводить бизнес-логику в шаблон (где он не принадлежит).

Вы должны быть в состоянии выполнить то, что вы хотите с помощью следующего:

from django.db.models import Count
class Screening(generic.DetailView):
    model = Job
    template_name = 'dashboard/screening.html'

    def get_context_data(self, **kwargs):
        context = super(Screening, self).get_context_data(**kwargs)

        # Fetch the sender_id for each unread message.
        # Count the number of times that the sender_id was included.
        # Then convert the list of tuples into a dictionary for quick lookup.
        sent_messages = dict(self.request.user.received_messages.filter(
            read_at__isnull=True
        ).values('sender_id').annotate(
            messages_sent=Count('user_id')
        ).values_list('sender_id', 'messages_sent'))

        candidates = []
        for candidate in self.object.applied_to.all().order_by('candidate'):
            candidate.messages_sent = sent_messages.get(candidate.id, 0)
            candidates.append(candidate)
        context['candidate_list'] = candidates
        return context

Тогда в вашем шаблоне вы будете использовать:

{% for candidate in candidate_list %}

    {{ candidate.get_full_name }}
    {{ candidate.candidate.city }}

    {{ candidate.messages_sent }}

{% endfor %}

Недостатком этого подхода является то, что у вас не будет доступа к отдельным сообщениям.

Редактировать: Вы можете прочитать об аннотациях и агрегациях здесь. Там намного больше информации.

Другие вопросы по тегам