ilyas Jumadurdyew
ilyas Jumadurdyew

Reputation: 930

Use args for all views w/o repeating it django

I have faced one problem in django views. I'm getting categories for my menu, like:

args['categs'] = ArticleCategory.objects.filter(category_language=4).order_by('id')

so let's say, I have

  1. Homepage View
  2. Article List View
  3. Article View

And so on...

And the problem is that I have to write:

args['categs'] = ArticleCategory.objects.filter(category_language=4).order_by('id')

for all views and if I exclude some categories from this list then I have to make changes for all views

How can I use args once for all views?

Upvotes: 1

Views: 75

Answers (3)

Dmitry
Dmitry

Reputation: 442

Believe, there are 3 things that can be improved:

  • Avoid repeating the same code in views. You have to implement Mixin to add appropriate functionality to your Views
  • Move filter() logic to the appropriate Manager method:

    class ArticleCategoryManager(models.Manager):
        def menu_categories(self, model, language = 4):
            return self.filter(category_language=language).order_by('id')
    
    class ArticleCategory(models.Model):
        object = ArticleCategoryManager()
    

To use default language id:

args['categs'] = ArticleCategory.objects.menu_categories()

To explicitly set language:

args['categs'] = ArticleCategory.objects.menu_categories(language=4)
  • Replace 4 with a constant: it difficult to read such code & you have to spend some time to understand the meaning of this value.

    Example of implementation:

    class ArticleCategoryLanguage(object):
        GERMAN = 3
        ENGLISH = 4
    
        LANGUAGES = (
            (GERMAN, 'German'),
            (ENGLISH, 'English')
        )
    

    Usage:

    args['categs'] = ArticleCategory.objects.menu_categories(language=ArticleCategoryLanguage.ENGLISH)
    

Upvotes: 0

arogachev
arogachev

Reputation: 33548

Because this is related with filtering categories in database, you can just extend your ArticleCategory model manager:

from django.db import models


class ArticleCategoryManager(models.Manager):
    def for_menu(self, model):
        return self.filter(category_language=4).order_by('id')


class ArticleCategory(models.Model):        
    objects = ArticleCategoryManager()

Then you will need only to write:

args['categs'] = ArticleCategory.objects.for_menu()

and don't care about how they are actually retrieved. If you need to change the logic of getting them - you change it only in one place - in manager's method.

As about repeated arguments - I don't see a problem in it because there is only one argument and three views, in case of bigger amount use a mixin or helper method to get that set of arguments.

P.S. A little recommendation - do not use hardcoded magic numbers, like 4, use constants instead.

Upvotes: 0

user4426017
user4426017

Reputation: 2000

If you would like to make your categories available in templates, then I'd recommend using a ContextProcessor for that: See Dajgno Documention

However, if you would like to just include them in all your views for some other reason, then I'd use a mixin. See Django Documentation again

Here is a sample mixin I that inherit in all of my views:

class BlogPostMixin(View):
    """
    A mixin that renders BlogPost form on GET request and processes it on POST request.
    """

    @method_decorator(login_required)
    def dispatch(self, *args, **kwargs):
        """ this is fired up first regardless of what http method is used """
        return super(BlogPostMixin, self).dispatch(*args, **kwargs)

    def get_context_data(self, **kwargs):
        #context = RequestContext(self.request)
        context = super(BlogPostMixin, self).get_context_data(**kwargs)
        try:
            context['form'] = kwargs['form']
            context['attachment_form'] = kwargs['attachments_formset']
            context['attachment_helper'] = AttachmentFormsetHelper()
        except Exception as e:
            pass
        return context

I use this mixin in my view like:

class BlogPostUpdateView(BlogPostMixin, UpdateView):
    """
    A view that updates existing blogposts. The form_valid and form_invalid methods
    are handled in in BlogPostMixin because that code is shared between this view and
    the CreateView for blogpost.
    """
    model = BlogPost
    form_class = BlogPostForm
    template_name = 'blog/blogpost_form.html'

    def get(self, request, *args, **kwargs):
        self.object = self.get_object()
        return super(BlogPostUpdateView, self).get(request, *args, **kwargs)

Upvotes: 1

Related Questions