Hi Patryk,

> Currently we have Prefetch objects that kind of solve this problem for M2M
> relations but perhaps it would be nice to also be able to use QuerySets in
> select_related() or even in filter(). I don't think Prefetch objects are 
best
> suited for that and I personally find having to instantiate them 
explicitly
> kind of ugly.

>From what I understand you're not a fan of Prefetch objects but I think most
of your problems can be solved by using them and custom managers as the 
formers
also support foreign keys[1].

class AuthorDisplayManager(models.Manager):
    def get_queryset(self):
        queryset = super().get_queryset()
        return queryset.filter(
            visible=True,
        ).annotate(
            num_books=Count('books'),
            num_awards=Count('awards'),
        ).prefetch_related(
            'foo',
        )

class Author(models.Model):
    ...
    for_display = AuthorDisplayManager()


class BookDisplayManager(models.Manager):
    def get_queryset(self):
        queryset = super().get_queryset()
        return queryset.filter(
            visible=True,
        ).prefetch_related(
            Prefetch(
                'author',
                Author.for_display.all(),
            )
        )


class Book(models.Model):
    ...
    for_display = BookDisplayManager()

Simon

[1] https://code.djangoproject.com/ticket/17003

Le vendredi 22 janvier 2016 05:25:24 UTC-5, Patryk Zawadzki a écrit :
>
> Hi,
>
> Currently the way QuerySets work makes it hard to reuse code. Consider an 
> example where I have template tags to render an author and a book (that in 
> turn displays author). I don't want my template code to execute any 
> additional queries per row displayed so I am forced to prefetch everything 
> upfront. Now if I want to display a list of authors and a list of books my 
> code is vastly different:
>
> ```
> authors = Author.objects.filter(visible=True)
> authors_for_display = authors.annotate(num_books=Count('books'), 
> num_awards=Count('awards')).prefetch_related('foo')
> ```
>
> vs.
>
> ```
> books = Book.objects.filter(visible=True, author__visible=True)
> books_for_display = 
> books.annotate(author_num_books=Count('author__books'), 
> author_num_awards=Count('author__awards')).select_related('author').prefetch_related('author__foo')
> ```
>
> Both cases need to do the exact same filtering, annotations and prefetches 
> for the Author object but notation is so different that no code reuse can 
> happen ("baz" vs. "bar__baz" vs. "foo__bar__baz"). The behaviour of 
> annotations is also different as now they end up on the Book object which 
> forces me to write some glue code. If my structure gains another level of 
> depth I will be forced to go to even greater extents.
>
> Now consider that I have many other objects that reference the Author and 
> thus I have many places in code that implement the same logic but each time 
> with a slight syntactic twist. What if a front-end engineer asks me to 
> change the information fetched about the Author? Or perhaps I discover that 
> half of the query time is spent fetching a megabyte of Author's extended 
> biography in HTML that the front-end never uses outside of that Author's 
> page. I am forced to hunt down and update all of these.
>
> Currently we have Prefetch objects that kind of solve this problem for M2M 
> relations but perhaps it would be nice to also be able to use QuerySets in 
> select_related() or even in filter(). I don't think Prefetch objects are 
> best suited for that and I personally find having to instantiate them 
> explicitly kind of ugly. To me having another SelectRelated object is 
> probably a no-go.
>
> Ideas?
>

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers  (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to django-developers+unsubscr...@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.
Visit this group at https://groups.google.com/group/django-developers.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-developers/ebad6483-f90c-41f9-8710-65b328320cdd%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to