I am trying to add a feature to my app that would allow me to enable/disable the "Call Me" button based on whether or not I am at [home|the office]. I created a model in the database called setting, it looks like this:
class setting(models.Model):
key = models.CharField(max_length=200)
value = models.CharField(max_length=200)
Pretty simple. There is currently one row, available, the value of it is the string True. I want to be able to transparently pass variables to the templates like this:
{% if available %}
<!-- Display button -->
{% else %}
<!-- Display grayed out button -->
{% endif %}
Now, I could add logic to every view that would check the database, and pass the variable to the template, but I am trying to stay DRY.
What is the best way to do this?
UPDATE
I created a context processor, and added it's path to the TEMPLATE_CONTEXT_PROCESSORS, but it is not being passed to the template
def available(request):
available = Setting.objects.get(key="available")
if open.value == "True":
return {"available":True}
else:
return {}
UPDATE TWO
If you are using the shortcut render_to_response, you need to pass an instance of RequestContext to the function.
from the django documentation:
If you're using Django's render_to_response() shortcut to populate a template with the contents of a dictionary, your template will be passed a Context instance by default (not a RequestContext). To use a RequestContext in your template rendering, pass an optional third argument to render_to_response(): a RequestContext instance. Your code might look like this:
def some_view(request):
# ...
return render_to_response('my_template.html',
my_data_dictionary,
context_instance=RequestContext(request))
Many thanks for all the help!
Write a custom context processor.
Related
base.html is used as the base template for all other pages. base.html has the navigation bar and in the navigation bar, I want to show the number of messages the user received. Thus, I need to have a variable like {{number_of_messages}} in the base.html.
However, how should I pass this variable to it? Every template extends base.html and is rendered by a function. I don't think returning number_of_messages in all functions is a good way. Is there better way to implement this? How can I pass this variable to all templates?
You can use tags.
#myproject/myproject/templatetags/tags.py
from django import template
register = template.Library()
#register.simple_tag
def number_of_messages(request):
return _number
In your Base.html
{% load tags %}
{% number_of_messages request %}
Have a look at:
https://docs.djangoproject.com/en/dev/ref/templates/api/#django.template.RequestContext
As long as:
you use the render shortcut in your view (or otherwise take care to use a RequestContext to render your response)
have django.contrib.auth.context_processors.auth in your TEMPLATE_CONTEXT_PROCESSORS setting (as it is by default)
...then you have the current request's User (or AnonymousUser) instance available in your template as {{ user }} ...I am guessing from there you may be able to access the number of messages directly?
Or perhaps you are using Django's messages framework?
This comes with it's own context processor which (as long as you use render or RequestContext) will make a {{ messages }} var (containing the messages for current user) available in your templates. For 'number of messages' you can do {{ messages|length }}
If none of these built-in options provide what you need you can either:
make your own template context processor which will run for every request and make additional variables available to all templates (when rendered with a RequestContext)
make your own template tag which can be used only where needed... of course if this is used in your base.html and all templates inherit from base.html then it's still going to run for every page.
I find the simplest steps to passing variables to your base templates in django is to add a context_processor.py file like so:
In your app create context_processors.py and declare your variables e.g.:
# context_processors.py
def message_processor(request):
if request.user.is_authenticated:
no_msgs = request.user.profile.msgs
else:
no_msgs = 0
return {
'messages' : no_msgs
}
Then register your process or under TEMPLATES in your settings.py file:
TEMPLATES = [
{
...
'context_processors': [
...
# custom
'appname.context_processors.message_processor',
],
},
},
]
And then you will be able to get that variable anywhere in your app as:
{{ messages }}
If you want the variable in really all the views, then a custom template context processor is probably the best option.
https://docs.djangoproject.com/en/dev/ref/templates/api/#subclassing-context-requestcontext
If you want the variable only in some of the views, then you can make those views call a common function that populates the common variables, something like this:
def some_view(request):
params = _common_params(request)
params.update({
# params specific to .some_view
})
return render_to_response('path/to/template, params)
or create a custom decorator like this:
from functools import wraps
def render_with_params():
def _inner(view_method):
def _decorator(request, *args, **kwargs):
params = _common_params(request)
(template_path, view_params) = view_method(request, *args, **kwargs)
params.update(view_params)
return render_to_response(template_path, params, context_instance=RequestContext(request))
return wraps(view_method)(_decorator)
return _inner
#render_with_params()
def some_view(request):
params = { ... }
return ('path/to/template', params)
I have a generic Django view that renders a template. The template is in an app which other projects will use. Importing projects will typically subclass the View the app provides. The View has a default template, which does a job with generic wording.
99% of the time, subclassing Views will want to only change the text, so rather than make them duplicate the template for the sake of altering non-markup wording, i'm looking for a way to allow users of the class to replace wording in the template in the most efficient way.
Options explored so far:
template partials containing only the text which using apps can override (magic, a lot of user work)
A template_strings method on the view which provides a dict of strings which end up in the template context which subclasses can override
Using (abusing?) the translation system such that the app provides default english translations and using code can provide their own translations instead (not actually worked this one out yet, just an idea)
Doing the above template_strings through AppConfig, but this seems ... yucky like it may get very unweildy with a lot of English strings. If doing this I would create a context-like setup so you don't have to re-declare all strings
Seems like it should be a solved problem to subclass a view which does a complete job and just provide alternate strings for text. Is there a better method than the above? Convention? Something I am missing?
(django 1.11 Python 3.6.2)
You can either inherit TemplateView or add ContextMixin to your view, and then override the get_context_data function like this:
from django.views.generic import TemplateView
class BaseView(TemplateView):
template_name = "common.html"
class SubView(BaseView):
def get_context_data(self, **kwargs):
context = super(SubView, self).get_context_data(**kwargs)
context['content'] = "Some sub view text"
return context
Update: Use template overriding
If you want to separate the text out, this is the better way to go
To allow easily and DRY override template across apps, you might need to install this package (Some other detail here)
We define it similarly as above, but change the template_name instead:
from django.views.generic import TemplateView
class BaseView(TemplateView):
template_name = "main.html"
# on another app
class SubView(BaseView):
template_name = "sub_view.html"
Then the magic is you can extends and override block of the BaseView template like this:
base_app/templates/main.html
<p>I'm Common Text</p>
{% block main %}
<p>I'm Base View</p>
{% endblock %}
sub_app/templates/sub_view.html
{% extends "base_app:main.html" %}
{% block main %}
<p>I'm Sub View</p>
{% endblock %}
The result would be:
<p>I'm Common Text</p>
<p>I'm Sub View</p>
Afaik you covered the options pretty well. My example is probably just a variant of the the template strings but maybe it helps anyway...
class DefaultStringProvider():
TITLE = 'Hello'
DESCRIPTION = 'Original description'
CATEGORY = 'Stuff'
class MyTemplateBaseView(TemplateView):
def get_context_data(self, **kwargs):
return super(MyTemplateBaseView, self).get_context_data(
provider=self.get_string_provider(), **kwargs)
def get_string_provider(self):
return DefaultStringProvider()
class OtherView(MyTemplateBaseView):
template_name = 'welcome.html'
def get_string_provider(self):
p = DefaultStringProvider()
p.TITLE = 'Hello'
p.DESCRIPTION = 'New description'
return p
The idea is to have a default string provider and the base view populates the context with it through get_string_provider().
It will at least be quite clear which strings can be overridden for a user extending the base class and it will not interfere with translations.
I created a custom filter in django template, but django has some constraints in passing no. of arguments, it allows only one or two arguments for custom filter functions Read more. And, i want to pass two arguments to my custom filter one is string and second one is object of model class. But can't able to successfully accomplish this.
index.html
{% load has_permission_filter %}
{% for u in users %}
<span class={{ user|has_location_perm:('user.view_user', u)}}>View</span>
{% endfor %}
In above template user is current logged user and users is a list of instances of User model class.
has_permission_filter.py
def has_location_perm(user, args):
perm_str, obj = args[0], args[1]
// business logic
if user.has_perm(perm_str) and business_logic_check(perm_str, obj):
return 'allow'
else:
return 'not-allow'
So, I want a some sort of solution which helps me in passing object in filter function from django template.
You can't use multiple arguments with filters. You can with a simple tag though.
I want to have a custom template tag which takes two variables as arguments. This is what I have in my template:
{% load accountSum %}
{% accountSum 'account_id' 'account_type' %}
I have read that you need to load the context of these variables but I have not found a working way. So my question is, how do I define the custom template tag in templatetags/accountSum.py?
This is what I have so far:
from django import template
register = template.Library()
def accountSum(context, account_id, account_type):
account_id = context[account_id]
account_type = context[account_type]
# do something with the data
# return the modified data
register.simple_tag(takes_context=True)(accountSum)
You have misunderstood the usage of template tags, I have read that you need to load the context of these variables... context is only required if you need to access/modify the existing context, not if you only need to return the calculated value from the provided arguments.
So, in your case, what you only need is this:
#register.simple_tag
def accountSum(account_id, account_type):
# your calculation here...
return # your return value here
Django document has a more detailed explanation and example that you can follow -- Simple tags
Or, if your intention is to take the context value account_id and account_type and return a modified value on each call, you can simply omit taking the arguments, and simply do this:
#register.simple_tag(take_context=True)
def accountSum(context):
account_id = context['account_id']
account_type = context['account_type']
# do your calculation here...
return # your modified value
Then you can simply call {% accountSum %} in your template.
Or, if you want to dynamically take context content as arguments:
#register.simple_tag(take_context=True)
def accountSum(context, arg1, arg2):
arg1 = context[arg1]
arg2 = context[arg2]
# calculation here...
return # modified value...
And passing arguments in template using string like:
{% accountSum 'account_id' 'account_type' %}
I hope this helps you understand how to use template tags in your case.
updated
What I meant is this (as you don't need to access the context, what you really need is taking arguments just like usual):
#register.simple_tag
def accountSum(arg1, arg2):
# your calculation here...
return # your return value here
and use this in your template:
{% accountSum account.account_id account.account_type %}
How can I create a widget on the site, such as login forms, dynamic menu (items taken from the database), site statistics?
I know that you can render a template that will extend out of a base template. And in the base template you can create these widgets.
But I do not know how to move the logic from the base template to my code. For example, the selection data for the block. Such actions certainly can be done in the template, but it would be a poor method in my opinion.
Sorry for my bad English. If you can not understand, I'll try to rephrase.
You would use a python library called WTForms. It helps you write code for creating forms and other widgets backed by database which you can render using jinja2 templates.
class YourForm(Form):
your_field1 = TextField()
....
your_fieldn = SubmitField()
#app.route('/')
def view():
form=YourForm()
return render_template('your.html', form=form)
In your.html
<form >
{{ form.your_field1 }}
....
{{ form.your_fieldn }}
</form>
Check out this flask pattern for form validation and rendering to know more about it.
Edit: To create global variables available to all templates,there are two ways:
You can use global dict of jinja environment.
This is the code:
app.jinja_env.globals.update({'variable':1})
You can use ContextProcessor. Code:
#app.context_processor
def inject_variable():
return dict(variable=1)
Now you can access variable in any template of your app.