Django - How to make a variable available to all templates? - python

I would like to know how to pass a variable to all my templates, without repeating the same code on every method in my views.py file?
In the example below I would like to make categories (an array of category objects) available to all templates in the web app.
Eg: I would like to avoid writing 'categories':categories on every method. Is it possible?
One view method
def front_page(request):
categories = Category.objects.all()
if is_logged_in(request) is False:
return render_to_response('users/signup.html', {'is_logged_in': is_logged_in(request), 'categories':categories}, context_instance=RequestContext(request))
else:
return render_to_response('users/front_page.html', {'is_logged_in': is_logged_in(request), 'categories':categories},context_instance=RequestContext(request))
Another view method
def another_view_method(request):
categories = Category.objects.all()
return render_to_response('eg/front_page.html', {'is_logged_in': is_logged_in(request), 'categories':categories},context_instance=RequestContext(request))

What you want is a context processor, and it's very easy to create one. Assuming you have an app named custom_app, follow the next steps:
Add custom_app to INSTALLED_APPS in settings.py (you've done it already, right?);
Create a context_processors.py into custom_app folder;
Add the following code to that new file:
def categories_processor(request):
categories = Category.objects.all()
return {'categories': categories}
Add context_processors.py to TEMPLATE_CONTEXT_PROCESSORS in settings.py
TEMPLATE_CONTEXT_PROCESSORS += ("custom_app.context_processors.categories_processor", )
And now you can use {{categories}} in all the templates :D
As of Django 1.8
To add a TEMPLATE_CONTEXT_PROCESSORS, in the settings you must add the next code:
TEMPLATES[0]['OPTIONS']['context_processors'].append("custom_app.context_processors.categories_processor")
Or include that string directly in the OPTIONS.context_processors key in your TEMPLATES setting.

Related

Django url kwargs in templates

Previously we have been accessing kwargs in Django templates with {{view.kwargs.kwarh_name}}.
However, it has been to my surprise that this is not working in my django 3.2.4+
Has it been removed, is there any issue with the line above?
Note: Kwargs here I mean something like below:
Given a function as below:
def GetSomething(request, code):
return render(request, "some template here")
Now, the urlpatterns would be something like,
import GetSomething from .views
app_name = "some_app_name_here"
urlpattern = [
path("link/<int:code>/", GetSomething, name="some_cool_name") #http:localhost/link/12345/
]
Now in HTML/Django templates or Jinja2(whichever you use), accessing this code would be via {{ view.kwargs.code }}
But it so happens that this is not working for me in Django 3.2, any reasons??
Hope I was very clear!
The get_context_data method of class based views adds the view to the context as view. If you have a function based view, it will not be added to the context automatically. This is not related to Django versions 3.2.4+
So either use a class based view or use a function based view and pass the kwargs to the template through the context variable.
def GetSomething(request, code):
context = {
#some values here
'code':code,
}
return render(request, "some template here", context)
Then you can access your context variables in the template directly.
{{code}}

How can i get form data from django layouts (like 'base.html') without sending forms in all page through views?

many templates extend from base.html. base.html have one newsletter form that get email from user. Is there any easy way to get the form data from 'base.html' to view.
(Sending forms in all page through views is possible But I think there is A easy good Looking idea)
Use a context processor to do so:
Add a new .py file in your root project, name it context_processors.py.
context_processors.py
from app.forms import GlobalForm
def global_variables(request):
form = GlobalForm()
context = {'global_form':form}
return context
Then in settings.TEMPLATES add the context processors as the last line.
# stuff
'django.contrib.messages.context_processors.messages'
'project_name.context_processors.global_variables'
So, {{global_form}} is available in all templates

Is it required to add custom views in admin page in ModelAdmin class when we can do it normally by adding views in views.py and urls in urls.py?

According to django docs:
class MyModelAdmin(admin.ModelAdmin):
def get_urls(self):
urls = super(MyModelAdmin, self).get_urls()
my_urls = [
url(r'^my_view/$', self.my_view),
]
return my_urls + urls
def my_view(self, request):
# ...
context = dict(
# Include common variables for rendering the admin template.
self.admin_site.each_context(request),
# Anything else you want in the context...
key=value,
)
return TemplateResponse(request, "sometemplate.html", context)
If I am not wrong, we can do the same thing by adding url in urls.py and the views in views.py as it is normally done then, what is the use of introducing this way? I am a newbie to django and I may be missing something here.
Can you please provide an example where we cannot do it in views.py and we must use the above method?
Any guidance/help would be appreciated.
I think I figured out, both of them can be used to do the same thing but the key difference is that the views which you write using above method will belong to admin app while the general views in views.py belongs to the particular app in you have written.
Hence, the url in ModelAdmin need to be called using name admin:url_name since the url goes as admin/my_views/ in given example.

Refactoring Django class-based views, clean up 18 repetitive classes.

https://github.com/AnthonyBRoberts/fcclincoln/blob/master/apps/story/views.py
I'm a little embarrassed to admit that this is mine. But it is.
class FrontpageView(DetailView):
template_name = "welcome_content.html"
def get_object(self):
return get_object_or_404(Article, slug="front-page")
def get_context_data(self, **kwargs):
context = super(FrontpageView, self).get_context_data(**kwargs)
context['slug'] = "front-page"
events = Article.objects.filter(slug="events")
context['events'] = events
return context
So this is a pretty normal class-based detail view in Django.
It's assigning a template, getting an Article object, and adding some things to the context_data.
Then I copied this class 17 times. Each time, there's a different template, and a different slug, and different stuff added to the context_data.
The idea is that there's a WYSIWYG editor for administrators to change the web content, and a user authentication system, to allow multiple people access to the site content. Basically, a super-simple CMS, so no one has to edit html to update the site.
But I really wish I could refactor this so I don't have these nearly identical 18 classes. Any suggestions on where I should start on this would be most welcome.
Squash all of your classes down to a single class that inherits from TemplateResponseMixin, as DetailView does, (also check out the SingleObjectTemplateResponseMixin) and override its get_template_names() method to return the template appropriate for the current situation.
A beautiful example of this being used is in the django-blog-zinnia project
def get_template_names(self):
"""
Return a list of template names to be used for the view.
"""
model_type = self.get_model_type()
model_name = self.get_model_name()
templates = [
'zinnia/%s/%s/entry_list.html' % (model_type, model_name),
'zinnia/%s/%s_entry_list.html' % (model_type, model_name),
'zinnia/%s/entry_list.html' % model_type,
'zinnia/entry_list.html']
if self.template_name is not None:
templates.insert(0, self.template_name)
return templates
Django will take that list of names and try each item to see if it exists in the templates folder. If it does, that template is used.
Update
After looking at your code a little more closely, perhaps something like this:
In your main urls.py
# convert each url
url(r'^$', FrontpageView.as_view()),
url(r'^history/$', HistoryView.as_view()),
url(r'^calendar/$', CalendarView.as_view()),
url(r'^news/$', NewsView.as_view()),
url(r'^visitors/$', VisitorsView.as_view()),
...
# to just
url(r'^(?P<slug>[\w\d/-]+)/$', SuperSpecialAwesomeView.as_view()),
# but, put this at the end of urls list after any routes that don't use this view
DetailView, after setting the class attribute model, will check to see if slug is in the url's kwargs and if it is, it will use the slug to do a model lookup just like what you are already doing: Article.ojects.get(slug=self.kwargs['slug'])
models.py
You could add a type field to your Article model. The type will specify what type of article it is. For example, your ChildrenView, YouthView, and AdultView could all have a type of music (since the templates are all music, I'm assuming that's how they are related).
ARTICLE_TYPE_CHOICES = (
(0, 'music'),
(1, 'weddings'),
(2, 'outreach'),
...
)
class Article(models.Model):
...
type = models.IntegerField(choices=ARTICLE_TYPE_CHOICES)
...
Then, in your views.py
class SuperSpecialAwesomeView(DetailView):
template_name = None
model = Article
def get_template_names(self):
slug = self.kwargs.get('slug', '')
templates = [
# create a template based on just the slug
'{0}.html'.format(slug),
# create a template based on the model's type
'{0}.html'.format(self.object.get_type_display()),
]
# Allow for template_name overrides in subclasses
if self.template_name is not None:
templates.insert(0, self.template_name)
return templates
Given an article instance with a type of music and a slug of ministry/children, Django will look for a template named ministry/children.html and a template named music.html.
And if you need to do some special stuff for other views (like you will probably need to for SermonsView), then subclass SuperSpecialAwesomeView
class SermonsView(SuperSpecialAwesomeView):
paginate_by = 2
queryset = Article.objects.order_by('-publish_date')
A quick approach I would think:
Add a template field in the model with a list of predefined template choices (those can be created dynamically).
Override the default DetailView methods, override the get_template_names method to assign the proper template to the view (if not available fallback, that can be done through a try: except:).
Apart from that you can alter the View behaviour with any kind of model flags.
This way you can have a single entry point for a model, rather than defining repeatable views all over the place.
I tend to keep a FrontPageView independent from other views though, for easiness and because it serves a different purpose.
If you need repeatable context entries, consider a context processor, if you need repeatable context entries for specific views consider Mixins.
Rarely I can find a places I need to use CBD.
You can refactor it like this:
def editable_page(slug):
return {
'context': {
'slug': slug
}
'template': 'mysupertemplates/{0}.html'.format(slug)
}
def frontpage(req):
return editable_page('frontpage')
def chat(req):
return editable_page('char')
def about(req):
return editable_page('about')

Django Variable Template Tags

<p>Hello, my name is {{ name }} ! </p>
Where/how do I set the variable: name = 'mike'? I've tried putting this in the settings.py and models.py file and it does not work.
Any info of proper code to put in a .py file would be great! I've searched through the docs page but didn't see how to set a variable for retrieval.
You need to set your variable value in the view function which normally put in view.py
e.g.
def hello(request):
return render(request, "hello.html", {"name": "mike"})
And you may would like to check https://docs.djangoproject.com/en/dev/topics/http/shortcuts/#render to find more about how to render templates with passed variables.
You need also learn more about how does Django's URL mapping works https://docs.djangoproject.com/en/dev/ref/urls/
Use context processors in django. Django handles this dilemma of making some information available to
all pages with something called context processors.
Some Code is like this,
Create a new file called context_processors.py inside your utils app directory, and add the
following code to it:
from project import settings
def context_data(request):
return {
'name': settings.name,
'request': request
}

Categories

Resources