How does one correctly override the styling of a single item in Django's model form {{form}} call. I cant seem to just overide the defualt behaviour and add my necessary style.
Specifically, I would like to add a simple slider that passes through some text to the view.
I have added an extra field to my form as follows:
class CreateTestForm(forms.ModelForm):
difficulty = forms.CharField()
class Meta:
model = Test
And the following in my html directly:
<form method="POST" action=""> {% csrf_token %}
{{ form|crispy }}
<strong>Difficulty</strong>
<input id="difficulty" type="text" value="" class="slider form-control" data-slider-min="0" data-slider-max="10"
data-slider-step="1" data-slider-value="[0,10]" data-slider-orientation="horizontal"
data-slider-selection="before" data-slider-tooltip="show" data-slider-id="blue">
</br>
<input type='submit' value='Create' class='btn'>
</form>
However, when I render the view, I get two difficulties inputs (one slider and one box). I understand that Django is creating the text box for me, but I assumed, giving my slider the same id would simply override it?
From my belief, I would also have to have the slider defined in the forms.py class for this form, else it is not accessible in cleaned_data in the view. Any ideas?
I'm not sure why you would assume that. But why not define the relevant attributes in the form in the first place, so that they get output automatically?
difficulty = forms.CharField(widget=forms.TextInput(attrs={"class": "slider form-control", "data-slider-min": "0"...}))
Or even better, use the Crispy API to let you declare those attributes (I don't use Crispy myself, but I know it gives you a lot of extra control.)
You can override the default widget, adding your class for styling like so:
from django import forms
class CreateTestform(forms.ModelForm):
class Meta:
model = Test
fields = ['difficulty'] # you don't need to define difficulty again,
# just get it from your model like in this example.
widget = {
'difficulty': forms.CharField(attrs={
'class': 'name-of-your-class',
'other-attribute': 'other-value',
}),
}
You can check for more here.
If you have too much styling to apply to your form, I suggest to render it manually and I know you use cripsy to avoid that, but it's a easier way, without limits, django is supposed to be used for backend, not frontend.
You can even render like this (supposing you have to render difficulty):
<input class="whatever-your-class-is" name="{{ form.difficulty.html_name }}" id="{{ form.difficulty.id_for_label }}">
If you look carefully, you found information about .html_name and .id_for_label, even .value here.
Related
I have a Django form which has an ImageField in it, and I render the field like this in my template:
{{ form.my_image_field }}
The resulting HTML looks like this:
Currently: ....jpg
<input name="my_image_field-clear" id="my_image_field-clear_id" type="checkbox">
<label for="my_image_field-clear_id">Clear</label><br>
Change:
<input name="my_image_field" id="id_my_image_field" type="file">
I want to render only the <input element, since I am using the bootstra-fileinput library: https://www.npmjs.com/package/bootstrap-fileinput :
<input name="my_image_field" id="id_my_image_field" type="file">
Is it possible to do this without writing the <input> tag manually in the template?
Normally, ImageFields use the ClearableFileInput widget. This widget by default uses the template name django/forms/widgets/clearable_file_input.html.
You can make your own ClearableFileInput widget subclass that uses a different template.
from django.forms.widgets import ClearableFileInput
class MyImageWidget(ClearableFileInput):
template_name = "myapp/my_template.html"
The content of that template may just be simply the <input> part of the default template with the extraneous label and checkbox removed. You can customize it however you need. That might look like
<!-- myapp/my_template.html -->
<input type="{{ widget.type }}" name="{{ widget.name }}"{% include "django/forms/widgets/attrs.html" %}>
Then in your form specify the widget for the ImageField
class MyForm(forms.Form):
# ...
my_image_field = forms.ImageField(widget=MyImageWidget)
# ...
Django also provides a FileInput widget which uses a plain template. If that suits your needs simply do
class MyForm(forms.Form):
# ...
my_image_field = forms.ImageField(widget=forms.widgets.FileInput)
Alternatively, you could simply override the default template by creating the django/forms/widgets/clearable_file_input.html file in your project's template directory. However, this would apply the change to the rendering of all fields using the ClearableFileInput widget, so it is not as flexible of an approach.
I am just beginner of Django.
At first, It seemed very convenient to use Django Form. I can get all which i already I defined in Model with ModelForm class. I can just put { form } in template. There are already pre-defined Field type and I can use it conveniently.
But it is tricky if you need to work with one who doesn't know Django or Python and are charge of making front-end part.
For example, I make template like this.
example.html
<form action="." method="post"> {% csrf_token %}
{{ form }}
<input type="submit" value="ok">
views.py
class TestView(FormView):
template_name = 'example.html'
form_class = TestForm
success_url = '/success/'
def form_valid(self, form):
print('data is validated! you can do work with cleaned data!')
return super(TestView, self).form_valid(form)
Q1 : A front-developer can't work with {{ form }}. right?
So I can change just example.html because it works properly if you set name attribute and type attribute correctly.
example.html
<form action="." method="post"> {% csrf_token %}
<input type="text" name="name">
<input type="text" name="calorie">
<input type="submit" value="Ok">
</form>
models.py
class Cereal(models.Model):
name = models.CharField(max_length=50)
calorie = models.CharField(max_length=50)
Q2 : I think it would be fine for a front developer to work with it if I change example.html above? right?
Well, if my questions are all fine, It seems fine to use ModelForm and write html code instead of {{ form }} django template syntax. But if you use ModelChoiceField, it seems nasty. You set queryset argument and it shows with select widget on template. for example queryset reqsult is { A, B, C }. it will turn to like below
<select id="id_something" name="name of something">
<option>A</option>
<option>B</option>
<option>C</option>
</select>
As i told you earlier, I don't want to use Django template syntax like {{ form }} as much as I can. so I am going to write like below instead.
views.py
render(request, "example.html", {queryset : something.objects.all()})
example.html
<select id="id_something" name="name of something">
{% for element in queryset %}
<option>{{ element }}</option>
{% endfor %}
</select>
Q3: does this approach seem alright? Isn't it better way to use less Django template syntax when you use Django Form?
well, I concluded that using DRF(Django RestFramework) is the best way to separate tasks for front-end and back-end developers independently. But In current situation I am facing, Template(html, css, js) is already made. I need to change it to use with Django framework. Front end developer will change little bit with the Template which is already made.
When I watched some pycon video in Youtube, some people said that Djang framework is kind of too much coupled.
I hope I can get Idea more efficiently to use Django Model form with front-end developer.
Thanks for reading. My question could be ridiculous for an expert. Please ask me again if it is not clear.
In my modelform I have a foreign key, I cannot figure out how to change the appearance of this field in template. I can change the text by changing
__unicode__
of the model, but how would I make it bold, for example?
in models.py I tried the following but form renders with and all other tags as if they were just text:
def __unicode__(self):
u'<b>Name</b>: {}\n<b>Loyal</b>: {}'.format(self.name, self.loyal)
my template.html:
<form method="post">
{% csrf_token %}
{{ form.client|safe}}
<br>
<input type="submit" value="Save changes" class="btn btn-s btn-success">
</form>
doesn't work.
Here is the picture:
Django 1.9 has a format_html function that might be what you are looking for. From the Docs:
format_html(format_string, *args, **kwargs)
This is similar to str.format(), except that it is appropriate for building up HTML fragments. All args and kwargs are passed through conditional_escape() before being passed to str.format().
For the case of building up small HTML fragments, this function is to be preferred over string interpolation using % or str.format() directly, because it applies escaping to all arguments - just like the template system applies escaping by default.
More information here: Prevent django admin from escaping html
i am working on project which is not in English language. I have encountered a little problem during registration.
In my registration html i have :
...
<form action="" style="text-align: center" method="POST">{% csrf_token %}
<ul style = "text-align: left">
{{user_form.as_p}}
</ul>
<input type="submit" value="UÅūsiregistruoti" onclick="validateForm()"/>
</form>
...
and now the text is by default in english. The {{user_form.as_p}} takes values from my forms.py:
...
fields = ('username', 'password1', 'password2')
...
is there a way to leave forms values unchanged, and rewrite the html part in my own language? how do i do that? I cant just take the generated parts of html and translate it, it wont work that way.
You can use verbose_name in model like this:
field = models.CharField(max_length=200, verbose_name="your_language_here")
More info see here
If your form didn't come from a 'Model, you can uselabel` instead like this:
field = forms.CharField(label="your_language_here")
More info here.
You can copy the generated HTML (except for the CSRFtoken wich you must put as {% csrf_token %}) and change the values inside the tags.
If you want to do it more maintainable and less error-prone, I will change the form labels https://docs.djangoproject.com/en/1.8/ref/forms/fields/#label in your forms.py.
Anyway, the form validation errors are going to be in English. so if you want to do it right, you must read the django docs on translation.
The most basic way to render a form in a template in Django is to add an instance of the form to the context:
context['form'] = MyForm()
And then, in your template, render the form by calling it as a template variable:
<form method="POST">
{% csrf_token %}
{{ form }}
</form>
When this template is rendered, {{ form }} gets rendered as:
<label for="my_field">my_field:</label>
<input type="default_widget_for_field_type" name="my_field" />
with one pair for each field in your form.
My question is: what code path on the form and/or in the templating language actually does this rendering? Based on other conventions in the Django templating language, I had expected the Python underlying {{ form }} to be form(), much like {{ object.get_absolute_url }} ends up being object.get_absolute_url(), but when I instantiate an instance of my form in the shell and try to call it, I get a TypeError telling me it's not callable. I had a look at the Django source code trying to figure out where this gets done, but I didn't have much luck.
Here's my use case. I want to create a ModelForm for a model representing a comment on a piece of content. It has a foreign key to that content model. There are multiple pieces of content on each page, so I need to instantiate multiple, unbound copies of the ModelForm to create comments on each piece of content. Each form will be attached to its content object on the page, so I don't want the foreign key to be a user-editable field.
This means that I need to take care of populating the foreign key field, and it makes sense to me to do that from the template as a hidden form field, because the template will have access to the object that it needs to set the foreign key to. However, if I leave the foreign key field off of the ModelForm, then the model won't save correctly on form validation. I could override the form validation to add in the hidden field, but I feel like a more elegant way to do it would be to add the field to the ModelForm, then override the ModelForm's rendering method so it doesn't try to render that field. Then I'll add the field manually in my template.
{% for piece_of_content in page_contents %}
{# the content #}
<p>Add your comment!</p>
<form method="POST" action="{% url 'comment-create' %}">
{% csrf_token %}
{# the overridden rendering method won't render the foreign key field... #}
{{ form }}
{# then I add it manually #}
<input type="hidden" name="commented_on" value="{{ piece_of_content.id }}" />
</form>
Then I wire the url for 'comment-create' to a CreateView, set its form_class to the ModelForm, and it will do its thing without any additional input from my end.
If the form were just callable, like I thought, then I could override __call__ on the ModelForm, and tell it to render everything but the foreign key field. But the ModelForm doesn't have a __call__, and I can't figure out where it is done! The form has methods for rendering various other configurations (as_p, as_ul, and as_table), but none that I see for just the default rendering.
Including {{ form }} is the same as {{ form.as_table }}. This is because the form's __str__ method calls its as_table() method. See the docs on outputting forms as HTML for more info.
The docs on template variables and lookups explain how variables are included in the template. If attributes are callable, the method is called. However in your case, form instances are not callable, so the unicode representation of the form is displayed.
If you don't want users to edit a field, I suggest you exclude it from the form and set it in the view. Users can tamper with the values of hidden fields.
The answer to your question is that this is just the string representation of the form: __unicode__() calls as_p() which renders the form.
However, this really isn't the way to do it. Rather than trying to hack both output and validation, and then try to insert the value, you should just exclude the foreign key from the form altogether. Then simply add it when you save: you can get the relevant value from the URL that the form posts to, and add it there:
if form.is_valid():
obj = form.save(commit=False)
obj.content_id = value_from_url
obj.save()