mailman_73
mailman_73

Reputation: 798

What is the best way to write two similiar ListView or render to similar lists in different templates in django?

I want to show a user the whole list of cats on one page and the list of cats that belongs to that user on another page. These two lists are almost identical except for one of them is filtered by self.request.user. Firstly, I wrote two different ListView but their querysets are practically the same. I don't know how to inherit one class based view from another. Is it possible?

According to my lack of knowledge of inheritance of the CBV, I put these lines into get_context_data:

cats_in_agent_base = Cat.objects.filter(cat_owner__exact=user)
context['cats_in_user_base'] = cats_in_user_base

On a personal owner page django will refer only to 'cats_in_user_base' but not to cat_list. But, of course, a user can't filter the list by get requests and paginate it right now.

What is a good way to solved the problem? How to inherit the queryset from one View to another? For example, what if I want to show on a DetailView page of the cat the list of similar cats by price or color? I'd like to use the same queryset from CatListView and filter it into get_context_data method.

My CatListView:

class CatListView(LoginRequiredMixin, ListView):
    template_name = 'ha/cat_list_template.html'
    context_object_name = 'cat_list'

    def get_queryset(self):
        max_price = self.request.GET.get('max_price')
        if max_price is None or max_price == '':
            max_price = 1000000000
        min_price = self.request.GET.get('min_price')
        if min_price is None or min_price == '':
            min_price = min(Cat.objects.filter().values_list('cat_price'))[0]

        cat_list = Cat.objects.filter(cat_price__gte=min_price) \
            .filter(cat_price__lte=max_price).order_by('-cat_pub_date')

        paginator = Paginator(cat_list, 20)
        page = self.request.GET.get('page')
        try:
            cat_list = paginator.page(page)
        except PageNotAnInteger:
            cat_list = paginator.page(1)
        except EmptyPage:
            cat_list = paginator.page(paginator.num_pages)

        return cat_list

    def get_context_data(self, **kwargs):
        user = self.request.user
        context = super(CatListView, self).get_context_data(**kwargs)
        cats_in_agent_base = Cat.objects.filter(cat_owner__exact=user)
        context['cats_in_user_base'] = cats_in_user_base
        return context 

Upvotes: 0

Views: 46

Answers (1)

Gocht
Gocht

Reputation: 10256

I think you can do this in some ways, I will try to give some basic ways to implement this.

I can see in your get_context_data method that you're filtering by user always and sending two list of cats to the template, I don't think that's a good idea.

You could do this:

Add a GET param to your url:

http://yourdomain/your-path-to-cat-list/?owned_by_user=1
# 1 it's not a pk is to say True
# Let's use 1 and 0 for this example
# You could use any other value as a flag

# Then you get that querystring in your get_queryset method

def get_queryset(self):
    max_price = self.request.GET.get('max_price')
    if max_price is None or max_price == '':
        max_price = 1000000000
    min_price = self.request.GET.get('min_price')
    if min_price is None or min_price == '':
        min_price = min(Cat.objects.filter().values_list('cat_price'))[0]

    cat_list = Cat.objects.filter(cat_price__gte=min_price) \
        .filter(cat_price__lte=max_price).order_by('-cat_pub_date')
    if int(self.request.GET.get('owned_by_user')):
        cat_list = cat_list.filter(cat_owner__exact=self.request.user)

    paginator = Paginator(cat_list, 20)
    page = self.request.GET.get('page')
    try:
        cat_list = paginator.page(page)
    except PageNotAnInteger:
        cat_list = paginator.page(1)
    except EmptyPage:
        cat_list = paginator.page(paginator.num_pages)

    return cat_list

If you want to do a new view for this, but don't repeat the same code, you can extend from your own view:

# You have
class CatListView(LoginRequiredMixin, ListView):
    # You could use this view for the complete list
    ...

# You can create a new one
# And modify get_queryset method

class OwnedByUserCatListView(CatListView):
    def get_queryset(self):
        max_price = self.request.GET.get('max_price')
        if max_price is None or max_price == '':
            max_price = 1000000000
        min_price = self.request.GET.get('min_price')
        if min_price is None or min_price == '':
            min_price = min(Cat.objects.filter().values_list('cat_price'))[0]

        cat_list = Cat.objects.filter(cat_price__gte=min_price) \
            .filter(cat_price__lte=max_price).filter(cat_owner__exact=self.request.user).order_by('-cat_pub_date')

        paginator = Paginator(cat_list, 20)
        page = self.request.GET.get('page')
        try:
            cat_list = paginator.page(page)
        except PageNotAnInteger:
            cat_list = paginator.page(1)
        except EmptyPage:
            cat_list = paginator.page(paginator.num_pages)

        return cat_list

Upvotes: 3

Related Questions