Applying Django mixins and queries with Q objects - particular behavior

0

I have the following mixin in which I want to recover the data from the User model with which I work to place this data in different views based on classes that I am developing:

class UserProfileDataMixin(object):
    def get_context_data(self, **kwargs):
        context = super(UserProfileDataMixin, self).get_context_data(**kwargs)
        user = self.request.user
        #context['userprofile'] = user.profile
        if user.is_authenticated():
            context['userprofile'] = user.profile
        return context

So, I have the following class-based view in which I want to search for users according to their username and full_name fields of the User model I work with.

class SearchView(UserProfileDataMixin, ListView):
    template_name = 'search.html'
    def get(self, request, *args, **kwargs):
        query = request.GET.get("q")
        qs = None
        if query:
            qs = User.objects.filter(
                Q(username__icontains=query) |
                Q(full_name__icontains=query)
            )
        context = {"users": qs}

        return render(request, "search.html", context)

When I am inheriting from UserProfileDataMixin this mixin gives me the possibility to have the context variable userprofile to pass it to my template search.html which inherits from layout.html template in which I perform the following validation:

search.html template

{% extends "layout.html" %}

layout.html template

{% if userprofile %}
    I put the data of user by example:
    avatar, username, full_name, and menu options to my app.   
{% endif %}

So far, all right, but my view based on class SearchView does not apply the mixin UserProfileDataMixin , I say this, because I can not get the user data on my template which come from layout.html .

When I deploy the user search template, I get that my user data does not appear in the top menu or header where I want them to appear:

I have slightly changed my view based on class SearchView overwriting method get_queryset instead of method get

class SearchView(UserProfileDataMixin, ListView):
        template_name = 'search.html'
    def get_queryset(self):
        query = self.request.GET.get("q")
        qs = None
        if query:
            qs = User.objects.filter(
                Q(username__icontains=query) |
                Q(full_name__icontains=query)
            )
        context = {"users": qs}
        return render(self.request, "search.html", context)

And my view based on class SearchView applies the mixin UserProfileDataMixin because now I can get the user data from layout.html on my template of search.html on my template.

Now, it appears in my top header menu, this data that is what the UserProfileDataMixin

brings me

But then, now, I have the drawback that my query Q to search for users does not work

What is the reason, so that my mixin UserProfileDataMixin is not applied or inherited in my class-based view SearchView when I overwrite the get method, but yes when I overwrite the get_queryset method?

Why does this eliminate the effect of my Q query? When should I use get and when to use get_queryset?

In this post, there is a very illustrative answer and accordingly, I think that the get_queryset method is the better option for my case, but I do not know what I'm doing wrong that my query with the Q object of user search is not executed at all well.

Why with get_queryset my query is not executed in the same way as when I use get ?

    
asked by bgarcial 10.06.2018 в 08:23
source

1 answer

1
  

What is the reason, so that my UserProfileDataMixin mixin is not   applied or inherited in my view based on SearchView class when   I overwrite the get method, but I do overwrite the method   get_queryset?

First you must study how the code of your generic class is executed. from what I see in the code you are misusing legacy methods. For example:

def get(self, request, *args, **kwargs):
    self.object_list = self.get_queryset()
    allow_empty = self.get_allow_empty()

    if not allow_empty:
        # When pagination is enabled and object_list is a queryset,
        # it's better to do a cheap query than to load the unpaginated
        # queryset in memory.
        if self.get_paginate_by(self.object_list) is not None and hasattr(self.object_list, 'exists'):
            is_empty = not self.object_list.exists()
        else:
            is_empty = len(self.object_list) == 0
        if is_empty:
            raise Http404(_("Empty list and '%(class_name)s.allow_empty' is False.") % {
                'class_name': self.__class__.__name__,
            })
    context = self.get_context_data()
    return self.render_to_response(context)

The above code is the get of the BaseListView class from django. if you look at the penultimate line you realize that the context is taken from the context = get_context_data () method while you in the get method create it directly. context = {"users": qs} which causes the method you created in your mixin to never be called. and that's why it does not work when you overwrite the get method.

Now when you implement the get_query_set method, the mixin is executed because it is executed as the django class where the get_context_data is called. But it still does not work because you are returning an object of type response. while the method must return is a queryset. your class should look like this:

class SearchView(UserProfileDataMixin, ListView):
    template_name = 'search.html'

    def get_queryset(self):
        query = self.request.GET.get("q")
        qs = Users.objects
        if query:
            qs = qs.filter(
                Q(username__icontains=query) |
                Q(full_name__icontains=query)
            )
        return qs

You do not need to directly include the list of users in the context the ListView class does. it is accessible by the name '% s_list'% model_name so if it is Users the class would have it in user_list. if you want to change the name you can use the variable context_object_name in the definition of your class.

    
answered by 10.06.2018 в 14:46