Как вывести выборку объектов Blog в ListView в Django с поиском по ForeignKeys двух других различных моделей?
У меня есть три такие модели:
1:
class Blog(models.Model):
    title = models.CharField()
    published = models.DateField()
    ...
2:
class AuthorList(models.Model):
    blog = models.ForeignKey(Blog)
    author = models.ForeignKey(User)
    lastTimeEdited = models.DateTimeField()
    ...
3:
class CommentsList(models.Model):
    blog = models.ForeignKey(Blog)
    commentAuthor = models.ForeignKey(User)
    commentPosted = models.DateTimeField()
    ...
Мой ListView, основанный на классе, выглядит так:
class DashboardView(LoginRequiredMixin, ListView):
    model = Blog
    template_name = 'app/dashboard.html'
    paginate_by = 5
    def get_queryset(self) -> QuerySet[Blog]:
        user = self.request.user
        author = #HERE I want a queryset of all blogs, where the requested user is one of the authors.
        commentator = #HERE I want a queryset of all blogs, where the requested user is one of the commentators.
        blogs = author|commentator
        return blogs.order_by(#HERE I want to order them by the lastTimeEdited-Field or the commentPosted-Field)
Итак, я хочу вывести список всех блогов, к которым так или иначе имеет отношение пользователь. Я также хочу упорядочить их по значению lastTimeEdited, если пользователь является автором, или по значению commentPosted, если пользователь является комментатором. Как мне это сделать?
Я уже искал решение в других постах, но не смог найти правильное решение для моей проблемы.
Your AuthorList model acts as a junction table for a many-to-many relation between Blog and User. You can span a ManyToManyField [Django-doc] on the Blog model with:
class Blog(models.Model):
    # …
    authors = models.ManyToManyField(
        settings.AUTH_USER_MODEL,
        through='AuthorList',
        related_name='authored_blogs',
    )
    commenters = models.ManyToManyField(
        settings.AUTH_USER_MODEL,
        through='CommentsList',
        related_name='commented_blogs',
    )Это значительно упрощает составление запросов, так как мы можем работать с:
from django.db.models import Q
class DashboardView(LoginRequiredMixin, ListView):
    model = Blog
    template_name = 'app/dashboard.html'
    paginate_by = 5
    def get_queryset(self) -> QuerySet[Blog]:
        return Blog.objects.filter(
            Q(authors=request.user) | Q(commenters=request.user)
        ).order_by(???) Единственная проблема теперь - как упорядочить, мы можем определить последнего автора и/или время комментария с помощью .annotate(…) [Django-doc] и затем использовать это:
from django.db.models import Greatest, Max, Q
class DashboardView(LoginRequiredMixin, ListView):
    model = Blog
    template_name = 'app/dashboard.html'
    paginate_by = 5
    def get_queryset(self) -> QuerySet[Blog]:
        return (
            Blog.objects.filter(
                Q(authors=request.user) | Q(commenters=request.user)
            )
            .annotate(
                latest_edit=Greatest(
                    Max('authorlist__lastTimeEdited'),
                    Max('commentslist__lastTimeEdited'),
                )
            )
            .order_by('-latest_edit')
        )For databases like SQLite, Oracle and MySQL, this will not be sufficient, since if there the user is not an author, or a commenter, it will return NULL, only if you are both author and commenter, that will work. We can fix this in a very ugly way with Coalesce [Django-doc]:
from django.db.models import Coalesce, Greatest, Max, Q
class DashboardView(LoginRequiredMixin, ListView):
    model = Blog
    template_name = 'app/dashboard.html'
    paginate_by = 5
    def get_queryset(self) -> QuerySet[Blog]:
        return (
            Blog.objects.filter(
                Q(authors=request.user) | Q(commenters=request.user)
            )
            .annotate(
                latest_edit=Greatest(
                    Coalesce(
                        Max('authorlist__lastTimeEdited'),
                        Max('commentslist__lastTimeEdited'),
                    ),
                    Coalesce(
                        Max('commentslist__lastTimeEdited'),
                        Max('authorlist__lastTimeEdited'),
                    ),
                )
            )
            .order_by('-latest_edit')
        )Note: It is normally better to make use of the
settings.AUTH_USER_MODEL[Django-doc] to refer to the user model, than to use theUsermodel [Django-doc] directly. For more information you can see the referencing theUsermodel section of the documentation [Django-doc].