Группировка результатов многомодельного поиска в Django - PullRequest
0 голосов
/ 17 июня 2020

Я использую следующий код для поиска нескольких моделей в моем приложении Django:

model:

class PostManager(models.Manager):
    def search(self, query=None):
        qs = self.get_queryset()
        if query is not None:
            or_lookup = (Q(title__icontains=query) |
                         Q(body__icontains=query)|
                         Q(slug__icontains=query)
                        )
            qs = qs.filter(or_lookup).distinct()
        return qs

class Post(models.Model):
    [...]
    objects = PostManager() 

class EventManager(models.Manager):
    def search(self, query=None):
        qs = self.get_queryset()
        if query is not None:
            or_lookup = (Q(title__icontains=query) |
                         Q(description__icontains=query)
                        )
            qs = qs.filter(or_lookup).distinct() # distinct() is often necessary with Q lookups
        return qs

class Event(models.Model):
    [...]
    objects = EventManager()

view:

class SearchView(ListView):
    template_name = 'search.html'
    count = 0

    def get_context_data(self, *args, **kwargs):
        context = super().get_context_data(*args, **kwargs)
        context['count'] = self.count or 0
        context['query'] = self.request.GET.get('q')
        return context

    def get_queryset(self):
        request = self.request
        query = request.GET.get('q', None)

        if query is not None:
            blog_results        = Post.objects.search(query)
            event_results      = Event.objects.search(query)

            # combine querysets
            queryset_chain = chain(
                    blog_results,
                    event_results,
            )
            qs = sorted(queryset_chain,
                        key=lambda instance: instance.pk,
                        reverse=True)
            self.count = len(qs)
            return qs
        return Post.objects.none()

template:

class_name.py:

from django import template
register = template.Library()

@register.filter()
def class_name(value):
    return value.__class__.__name__

template:

{% load class_name %}

{% for object in object_list %}
    {% with object|class_name as klass %}

      {% if klass == 'Post' %}
           <div class='row'>
             <div class='col-12'>
                Article: <a href='{{ object.get_absolute_url }}'>{{ object.title|highlight_search_term:query }}</a>
            </div>
          </div>

      {% elif klass == 'Event' %}
           <div class='row'>
             <div class='col-12'>
                Event : <a href='{{ object.get_absolute_url }}'>{{ object.title }}</a>
              </div>
            </div>
    {% endwith %}
{% endfor %}

Все отлично работает. Тем не менее, я хотел бы изменить свой вывод с этого:

7 results for john
Article: James MacMillan Horn Quintet
Page: The RCS Award for Making it Happen
Article: Programming The Cottier Chamber Project
Page: About This Website
Profile: John

На это:

7 results for john
Articles:

James MacMillan Horn Quintet
Programming The Cottier Chamber Project

Pages:
The RCS Award for Making it Happen
About This Website

Profiles:
John

Как я могу это сделать? Я знаю функцию шаблона Django перегруппировать . Однако я могу получить название модели из результирующего набора запросов. object.__class__.__name__ или что-то в этом роде просто ничего не возвращает, а использование object | class_name в коде перегруппировки ({% regroup result by object|class_name as object_list %}) вызывает ошибку cannot parse remaining.

...