How to make generic variables available in settings and contexts?

58 views
Skip to first unread message

ThomasTheDjangoFan

unread,
Jan 18, 2015, 5:26:50 AM1/18/15
to django...@googlegroups.com
Ladies and gentleman,

I am new to Django and would really love to have a solution for this:

My goal is to share generated settings between my views/models and templates, without repeating myself.

Right now I have following code, where the problem appears:

#MY_CONTEXT_PROCESSOR.PY
from django.conf import settings

def setDataToContext (request):
   
"""
        Send settings to context of tempalte
    """


   
#GENERATED STUFF
   
#Prepare common Objects
    main_category
= Category.objects.get(id=1)

   
return {
       
'settings': settings, # Global Django Settings
       
'MAIN_CATEGORY': main_category, # Make category available in template - Question: How do I make this available in views/models as settings.MAIN_CATEGORY?
   
}


The main question is:
How can I make the generic constant MAIN_CATEGORY available in views/models as settings.MAIN_CATEGORY without repeating myself?

I am really looking forward to see your solutions.

Kind regards
Thomas

James Schneider

unread,
Jan 18, 2015, 6:28:30 AM1/18/15
to django...@googlegroups.com

If I understand you right, you want to set MAIN_CATEGORY as a "global" variable/setting containing a Category object with an ID of 1. Is that right? If so...

Rather than populating a "global" variable, I would instead create a custom model manager for the Category model:

https://docs.djangoproject.com/en/1.7/topics/db/managers/#custom-managers

 It would be a pretty simple override just to add an extra method:

class CategoryManager(models.Manager):
    def get_main_category(self):
        return Category.objects.get(pk=1)

class Category(models.Model):
    <...other fields...>
    objects = CategoryManager()


Then, anywhere you needed the value that would be accessed via MAIN_CATEGORY, you would instead use 'main_category = Category.objects.get_main_category()'.

If you ever need to change the category that is returned, the only place you'll need to update the code/PK is in the manager method definition. Much more flexible than a simple variable in settings.py.

Realize that the example above is quite a naive/simplistic implementation, and can benefit from other optimizations (such as a basic caching mechanism in the CategoryManager in the event it is called multiple times during a request to avoid multiple queries for the same data, among others). Check out https://github.com/django/django/blob/master/django/contrib/auth/backends.py#L41 for how Django handles caching for permission checks (which are often called multiple times per request). 

To avoid the dependency on a specific key/PK, you may want to consider adding a boolean field to Category called 'is_main' that defaults to False. Then set the field to True for the single category you want to be the main one. Then your manager query would look like Category.objects.get(is_main=True). Just make sure you only have one category with is_main set to True (if you change your mind on which category will be the main category, set all of the Categories to False, and then reset the new main category to True). If you are confident that it will never change, though, you'll probably be fine.

-James

--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users...@googlegroups.com.
To post to this group, send email to django...@googlegroups.com.
Visit this group at http://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/eb76aeb9-bc51-4b1a-918d-db6d29956d08%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

ThomasTheDjangoFan

unread,
Jan 18, 2015, 7:47:03 AM1/18/15
to django...@googlegroups.com
Hi James,

thanks a lot for pointing me to the models.Mangager option. Now this is really interesting. I will definetly check out how caching works.

Now the question is:
How do I now access the CategoryManager.get_main_category() in my template.html? I guess I have to pass it over to context within the view?

James Schneider

unread,
Jan 18, 2015, 8:09:58 AM1/18/15
to django...@googlegroups.com

If you need it in all of (or a large majority of) your templates, stick with the context processor you originally posted, just replace the Category.objects.get() call with the custom manager call. Your templates would then have access to {{ MAIN_CATEGORY }}. And with a context processor, that literally means every template, including login forms, password resets, etc. which may or may not be acceptable.

If you don't necessarily need it in all templates, but you are using class-based views, you can write a custom mixin that overrides get_context_data() to add in the MAIN_CATEGORY variable for your templates, but only if you are not using the aforementioned context processor to populate it (otherwise you are doubling the work to set the same variable).

Templates are the only tricky part here. Everywhere else you can call your custom manager method directly.

-James

Collin Anderson

unread,
Jan 19, 2015, 12:28:53 PM1/19/15
to django...@googlegroups.com
Hi All,

Also, check out assignment_tags if you haven't seen them.

Collin
Reply all
Reply to author
Forward
0 new messages