Django ImageField - render only the <input> element - python

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.

Related

How to override a single item on a model form django

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.

Custom rendering of foreign field in form in django template

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

How to auto-generate full HTML from a WTForms form

I'm trying to create a simple WTForms-based admin interface for an SQLAlchemy app, using Jinja2 templates.
I've read the docs of WTForms-Alchemy and I understand that it can auto-generate a form from my model just via a few lines of code, like:
class UserForm(ModelForm):
class Meta:
model = User
My problem is that even though I have this form auto-generated, I found no resource anywhere about how can I make it into a functional HTML page. There are a few snippets about rendering errors for fields, as well as some SO answers mentioning macros for rendering whole fields, but I found absolutely no resource about how to generate a full, functional form automatically.
// I understand that this is something what Flask-Admin might do already, I'm not using Flask so this is not a possibility unfortunately.
WTForms leaves it up to you to figure out how to you want to render out your form after you pass it into your template. The simplest way to render a form would be to just iterate through your form and render the fields. When a field (or its label) is called, it emits HTML.
<form action="/some_url" method="POST">
{% for field in form %}
{{ field.label() }}
{{ field() }}
{% endfor %}
<button type="submit" />
</form>
The macros provided here provide an automated way to generate HTML surrounding these fields.
You can use wtf.quick_form like this, in which case you'll have a totally generic form template. Mark up your db.Model members with info{} properties to set field display names etc
<form method="post" action="/{{route}}">
<fieldset>
{{ wtf.quick_form(form, button_map={'submit':'success'}) }}
<input class="btn btn-success" type="submit" value="Submit" />
<button type="button" class="btn">Cancel</button>
</fieldset>
</form>
Your form definition:
class MyobjectForm(BaseModelForm):
class Meta:
model = Myobject
Then your route handler looks like this:
#app.route('/myobject', methods=('GET', 'POST'))
def myobject_route():
obj = Myobject()
form = MyobjectForm(obj = obj)
if form.validate_on_submit():
form.populate_obj(obj)
db.session.add(obj)
db.session.commit()
return redirect(url_for('index'))
return render_template('form.j2', form=form, title='My Object', route='myobject')

How to change HTML of models (classes) in Django?

Suppose I have a TrueFalseQuestion model (which only has a question_text) in myproject/myapp/models.py, and I want it to be rendered as, let's say
<a>Question Text</a>
<input type="radio">True</input>
<input type="radio">False</input>
(HTML could be wrong, not important) , in this template, only Question Text part changes, the input forms are always constant. So how can I implement this behaviour in Django?
An example would be appreciated. Thanks !
In your views.py file of the app, add the following.
from django.views.generic import ListView
from models import TrueFalseQuestion
class QuestionsList(ListView):
queryset = TrueFalseQuestion.objects.all()
template_name = 'name_of_your_template'
Then inside your template, iterate over the object_list like this:
{%for ques in object_list%}
<a>{{ques.question_text}}</a>
<input type="radio">True</input>
<input type="radio">False</input>
{%endfor%}
Also, make sure to point your url to the view.

How does Django's default template form rendering ( {{ form }} ) work?

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()

Categories