I have recently upgraded to Django 1.2.5, and now I am having problems with localization, specifically number formatting. For example, in some templates I print the following samples:
data-id="{{ form.instance.id }}"
Which in cases >= 1000, used to evaluate to:
data-id="1235"
But now it actually results in (my localization is pt-BR, our decimal separator is dot):
data-id="1.235"
Which of course is not found when I afterwards query the database by ID. Using a |safe filter solves the problem, but I'm not willing to find all IDs in all templates and safe them.
Usually, I'll only localize the floating points, not the integers. I don't want to disable L10N, because of all the other formatting that is working fine. Is there a way to make this distinction in Django localization? Any other solution is accepted.
data-id="{{ form.instance.id|safe }}"
Also do the job
with django 1.2:
data-id="{{ form.instance.id|stringformat:'d' }}"
or, with django 1.3:
{% load l10n %}
{% localize off %}
data-id="{{ form.instance.id|stringformat:'d' }}"
{% endlocalize %}
or (also with django 1.3):
data-id="{{ form.instance.id|unlocalize }}"
http://docs.djangoproject.com/en/1.3/topics/i18n/localization/#topic-l10n-templates
http://docs.djangoproject.com/en/1.3/ref/templates/builtins/#stringformat
This doesn't really answer your question but check out this section of the docs. It says to use {{ |unlocalize }} filter or:
{% localize on %}
{{ value }}
{% endlocalize %}
{% localize off %}
{{ value }}
{% endlocalize %}
There's probably a better way but I'm thinking that you could write a method that gives you the id as a string in your model for each model you are trying to display the id in a template.
class MyModel(models.Model):
pass
def str_id(self):
return u'%s' % self.id
in your template:
{{ form.instance.str_id }}
Related
I know it's possible to have more than one Django form in one HTML form, even formsets, and standard forms combined and it works perfectly fine. I want to know if it is a good practice and how this can impact security if it will at all? I couldn't find any information about those cases but in tutorials, I saw both (multiple Django forms in one HTML and every Django form in a separate HTML form) in some cases is necessary since the two forms can do different things like update and delete for example. In my case, all forms POST data to different models, and then all are combined in one model. Please take a look at the example (This is a simple example and not the actual code) below:
<form action="" method="POST">
{% csrf_token %}
{{ form.field1 }}
{{ form.field2 }}
{{ form.field3 }}
{% for field in dates_form %}
{{ field.Loading_date_from }}{{ field.Loading_time_from }}{{ field.Loading_date_to }}{{ field.Loading_time_to }}
{% endfor %}
{% for field in dates_form2 %}
{{ field.Loading_date_from }}{{ field.Loading_time_from }}{{ field.Loading_date_to }}{{ field.Loading_time_to }}
{% endfor %}
{{ form.field4 }}
{{ form.field5 }}
<input type="submit">
</form>
Yes, it is okay, as long as you handle them properly in the view. There’s a package to help with this, including support for model forms as well:
https://github.com/kennethlove/django-shapeshifter
Full disclosure, I’m a contributor to the package.
If I have a model that contains a ChoiceField with a RadioSelect widget, how can I render the radio buttons separately in a template?
Let's say I'm building a web app that allows new employees at a company to choose what kind of computer they want on their desktop. This is the relevant model:
class ComputerOrder(forms.Form):
name = forms.CharField(max_length=50)
office_address = forms.Charfield(max_length=75)
pc_type = forms.ChoiceField(widget=RadioSelect(), choices=[(1, 'Mac'), (2, 'PC')])
On the template, how do I render just the Mac choice button? If I do this, it renders all the choices:
{{ form.pc_type }}
Somewhat naively I tried this, but it produced no output:
{{ form.pc_type.0 }}
(I found a few similar questions here on SO:
In a Django form, how do I render a radio button so that the choices are separated on the page?
Django Forms: How to iterate over a Choices of a field in Django form
But I didn't feel like they had good answers. Is there a way to resurrect old questions?)
Django 1.4+ allows you to iterate over the choices in a RadioSelect, along with the lines of
{% for choice in form.pc_type %}
{{ choice.choice_label }}
<span class="radio">{{ choice.tag }}</span>
{% endfor %}
I'm not sure if this change allows you to use the syntax you describe ({{ form.pc_type.0 }}) — if not, you could work around this limitation with the for loop above and a tag like {% if forloop.counter0 == 0 %}.
If you're tied to Django < 1.4, you can either override the render() method as suggested or go with the slightly-more-verbose-but-less-complicated option of building up the form field yourself in the template:
{% for choice in form.pc_type.field.choices %}
<input name='{{ form.pc_type.name }}'
id='{{ form.pc_type.auto_id }}_{{ forloop.counter0 }}' type='radio' value='{{ choice.0 }}'
{% if not form.is_bound %}{% ifequal form.pc_type.field.initial choice.0 %} checked='checked' {% endifequal %}
{% else %}{% ifequal form.pc_type.data choice.0 %} checked='checked' {% endifequal %}{% endif %}/>
<label for='{{ form.pc_type.auto_id }}_{{ forloop.counter0 }}'>{{ choice.1 }}</label>
{% endfor %}
(choice.0 and choice.1 are the first and second items in your choices two-tuple)
The rendering of the individual radio inputs is handled by the RadioSelect widget's render method. If you want a different rendering, subclass RadioSelect, change the render method accordingly, and then use your subclass as the field's widget.
I think the simply looking at what's available inside the for loop of a choice field will tell one what they need to know. For example, I needed the value to set a class surrounding the span of the option (for colors and such):
<div>
{% for radio_input in form.role %}
{# Skip the empty value #}
{% if radio_input.choice_value %}
<span class="user-level {{ radio_input.choice_value }}">{{ radio_input }}</span>
{% endif %}
{% endfor %}
</div>
There are several attributes as you can see that keep you from having to use the ordinal.
In Django 2.0+ you can subclass forms.RadioSelect and "simply" specify a template for rendering the radio fields:
class SlimRadioSelect(forms.RadioSelect):
template_name = 'includes/slim_radio.html'
where slim_radio.html contains a revised version of the combined template_name and option_template_name used by the default RadioSelect widget.
Note, the default RadioSelect widget template is low-level rendering and consists of heavily layered templates: include, conditional and loop logic tags abound.
You'll know you've arrived when you're digging around in packages/django/forms/templates/django/forms/widgets/input.html to get what you need.
One other oddity for overriding the default widget's template is that you must invoke the TemplatesSetting renderer or your subclass won't be able to find slim_radio.html in your project's normally accessible template paths.
To override RadioSelect's local-only template path lookup:
Add 'django.forms' to your INSTALLED_APPS;
Add FORM_RENDERER = 'django.forms.renderers.TemplatesSetting' to your settings.py.
This all seems harder than it should be, but that's frameworks. Good luck.
I like the convenient output form method {{ form.as_ul }} but is there a way I can still continue to use it but capture all the errors upfront instead of displaying the error just above each field.
I understand that there are ways to loop through each form element and so on as mentioned in django docs but I want to continue to utilize the capability of form.as_ul() except get control over error display.
Solved this problem by using Reusable Form Templates.
Its simple...
Create a reusable template with the following code snippets based on your need.
If you want to display all errors right at the top of the form...
{% if form %}
{% if form.errors %}
{% for field in form %}
{{field.errors}}
{% endfor %}
{% endif %}
{% for field in form %}
<li>{{ field.label_tag }}: {{ field }}</li>
{% endfor %}
{% endif %}
If you want to display all errors right after each form field without the default html elements around error use...
{% for field in form %}
{{ field.label_tag }}: {{ field }}
{% for error in field.errors %}{{ error }}{% endfor %}
{% endfor %}
Used the second template and created a Inclusion Tag
The only way I see is to inherit the new form class from forms.Form and alter as_ul method as you like. Which isn't very good if you are going to use third-party forms like login form and so on (they won't have this method).
I think the best solution is to create your own inclusion tag and render form with it. It will be as short as as_ul ({% render_form form %}) but very flexible, it will work with all forms and won't mix HTML and Python code.
I still think the customization for rendering form in templates is quite flexible. I usually do this for my webapps. You may work with a bit javascript and css but not a big problem. Moreover, I think we should try to make the app simple.
Maybe it's a little bit stupid question, but I didn't find an answer. Is there any way to use increased/decreased variables in django templates?
e.g.{{ some_variable + 1 }}
There's a built-in add filter:
{{ some_variable|add:"1" }}
One way of doing this is by using a django template filter.
https://docs.djangoproject.com/en/dev/howto/custom-template-tags/#writing-custom-template-filters
def inc(value):
return value+1
and then:
{{ some_variable|inc }}
Inside for loop use forloop.counter that will automatically increase the counter till the records.
{% for a in object_list %}
{{ forloop.counter }}
{% endfor %}
I'm trying to build a blog app and the problem is when I use tag 'truncatewords_html' in my template to truncate posts longer than specified number of words, I need to link to complete post by some title like 'read more...' after truncation. So I should know that the post was truncated or not.
P.S.: Is this a pythonic way to solve the problem?
{% ifequal post.body|length post.body|truncatewords_html:max_words|length %}
{{ post.body|safe }}
{% else %}
{{ post.body|truncatewords_html:max_words|safe }}read more
{% endifequal %}
This is pretty convoluted but django has some weird corners. Basically I figure if the string length is the same if you truncate at x and x+1 words then the string has not been truncated...
{% ifnotequal post.body|truncatewords_html:30|length post.body|truncatewords_html:31|length %}
read more...
{% endifnotequal %}
You could write a custom template tag (see django docs), or manually check in the template, whether the content you want to display exceeds the given length via length builtin filter.
It comes down to personal preference, but for my taste you're doing way too much work in the template. I would create a method on the Post model, read_more_needed() perhaps, which returns True or False depending on the length of the text. eg:
def read_more_needed(self):
from django.utils.text import truncate_html_words
return not truncate_html_words(self.body,30)==truncate_html_words(self.body,31)
Then your template would read:
{% if post.read_more_needed %}
{{ post.body|truncatewords_html:30|safe }}read more
{% else %}
{{ post.body|safe }}
{% endif %}
Check out http://code.djangoproject.com/ticket/6799
This patch provides a method to replace the default elipses for truncated text.