简体   繁体   中英

Django class-based-view access context data from get_queryset

class ProfileContextMixin(generic_base.ContextMixin, generic_view.View):

    def get_context_data(self, **kwargs):
        context = super(ProfileContextMixin, self).get_context_data(**kwargs)
        profile = get_object_or_404(Profile, user__username=self.request.user)
        context['profile'] = profile
        return context

class CourseListView(ProfileContextMixin, generic_view.ListView):
    model = Course
    template_name = 'course_list.html'
    object_list = None

    def get_queryset(self):
        profile = self.get_context_data()['profile']
        return super(CourseListView, self).get_queryset().filter(creator=profile)

I have the following two class-based-views. CourseListView inherits ProfileContextMixin which I wrote so that I don't have to repeat overriding get_context_data to get the profile every time in my other views.

Now in my CourseListView , I need to filter the result based on the creator argument, which is the same one retrieved in get_context_data

I know my get_queryset works, and it will call get_context_data() to get the profile, but this will also cause my get_context_data to be called twice, executing the same SQL two times.

Is there a way I can access the context efficiently?

UPDATE:

After reading ListView method flowchart, I ended up doing this, but not sure if it's the best way. Feedback is appreciated.

    object_list = []
    context = None

    def get_context_data(self, **kwargs):
        return self.context

    def get_queryset(self):
        self.context = super(CourseListView, self).get_context_data()
        profile = self.context['profile']
        queryset = super(CourseListView, self).get_queryset()
        queryset = queryset.filter(creator=profile)
        self.context['object_list'] = queryset
        return queryset

You can move getting profile out of get_context_data to upper function, like dispatch , or use cached_property decorator. This way your profile will be stored in _profile argument of view and you will not do second get to DB after calling self.profile second time.

from django.utils.functional import cached_property

class ProfileContextMixin(generic_base.ContextMixin, generic_view.View):
    @cached_property
    def profile(self):
        return get_object_or_404(Profile, user__username=self.request.user)

    def get_context_data(self, **kwargs):
        context = super(ProfileContextMixin, self).get_context_data(**kwargs)
        context['profile'] = self.profile
        return context

class CourseListView(ProfileContextMixin, generic_view.ListView):
    model = Course
    template_name = 'course_list.html'
    object_list = None

    def get_queryset(self):
        return super(CourseListView, self).get_queryset().filter(creator=self.profile)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM