Django: How to make a form with custom templating? - python

I have a model:
class Setting(models.Model):
class Meta:
abstract = True
name = models.CharField(max_length=120, primary_key=True)
description = models.CharField(max_length=300, blank=True)
class IntegerSetting(Setting):
value = models.IntegerField()
I would like to create a form that looks something like:
<form method="POST" action="">
{% for model in models %}
<label>{{model.name}}</label> <input value='{{model.value}}' />
<p>{{model.description}}</p>
{% endfor %}
</form>
I'm not quite sure how to go about doing this. Perhaps I need to use a formset?
from django.forms.models import modelformset_factory
from apps.about.models import Setting, IntegerSetting
def site_settings(request):
formset = modelformset_factory(IntegerSetting)()
return render_to_response("about/admin/site-settings.html", {'formset': formset}, RequestContext(request, {}))
Then in the template, I'd want to render the form differently than default. I'm not quite sure how to go about accessing the model properties, however. Is this the right approach, or is there another way I should be going about doing this?
Update: This is what I'm currently doing. It renders exactly as I'd like it to, aside from the styling. However, I feel that it's deeply hacky:
class SettingsForm(ModelForm):
class Meta:
model = IntegerSetting
def as_table(self):
bound_field = BoundField(self, self.fields['value'], 'value')
return mark_safe("<tr><td><label>%s</label></td><td>%s\n<p class='help'>%s</p></td></tr>" % (self.instance.name,
self.instance.description,
bound_field.__unicode__()))
def edit_settings(request):
forms = [SettingsForm(instance=intSetting) for intSetting in IntegerSetting.objects.all()]
return render_to_response("admin/edit-settings.html", {'forms': forms}, RequestContext(request, {}))
edit-settings.html:
{% extends "admin/base_site.html" %}
{% block title %}System Settings{% endblock %}
{% block content %}
<form method="post" action="">
<table>
{% for form in forms %}
{{form}}
{% endfor %}
</table>
</form>
{% endblock %}
Is there a better approach to this?
Also, I'm not sure if I'll encounter problems when the form is submitted or not.

<form action="/contact/" method="post">
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }}: {{ field }}
</div>
{% endfor %}
<p><input type="submit" value="Send message" /></p>
</form>
You can find the complete documentation here:
http://docs.djangoproject.com/en/dev/topics/forms/#customizing-the-form-template

I don't think you need a formset here. Take a look here if you want a custom template for one view. If you want to create your own {{ form.as_foobar }}, just subclass forms.Form, something like this:
class MyForm(forms.Form):
def as_foobar(self):
return self._html_output(
normal_row = u'%(label)s %(field)s%(help_text)s',
error_row = u'%s',
row_ender = '',
help_text_html = u' %s',
errors_on_separate_row = False)
and just use it in your forms.py:
class ContactForm(MyForm):
# ..

For whoever needs the <table> version of jbcurtin's answer:
<form method="post">{% csrf_token %}
<table>
{% for field in form %}
<tr>
<th>{{field.label_tag}}</th>
<td>
{{ field.errors }}
{{ field }}
</td>
</tr>
{% endfor %}
</table>
<hr/>
<input type="submit" value="Conferma" />
</form>

Looks like you might be interested in django-floppyforms (docs), which gives you much more control over field rendering.

Related

How to just display one field from the form in Django

I want to display just one field from my form that I have created but I am getting 'Could not parse the remainder:' error
Here is my forms.py file
from django import forms
from .models import *
class ProductForm(forms.ModelForm):
class Meta:
model = Product
fields = ('prod_name', 'company', 'quantity', 'price', 'units', 'prod_type')
Here is my html file
{% extends 'base.html' %}
{% block body %}
<div class="container">
<form method="POST">
<br>
{% csrf_token %}
{% for field in form %}
{% if field.name=='units' %}
<div class ="form-form row">
<label for="id_{{field.name}}" class="col-2 col-form-label">{{field.label}}</label>
<div class ="col-10">
{{field}}
</div>
</div>
{% endif %}
{% endfor %}
<button type="submit" class="btn btn-primary" name="button">Update Sales</button>
</form>
</div>
{% endblock %}
I just want to display units in my webpage for this module that I am creating
I think you try to solve the problem on the wrong level. You can just construct a form with one field:
from django import forms
from .models import *
class UnitProductForm(forms.ModelForm):
class Meta:
model = Product
fields = ('units',)
If you need the other form as well, you can just create an extra one, with a different name, like here UnitProductForm.
Using a form with a subset of fields is not only easier to render. The form will not make modifications to fields of a model object if these are not specified, even if these items are passed in a (forged) POST request. So it makes it more safe to use as well.
If you want to display only prod_name field then you can do it:
{
from django import forms
from .models import *
class ProductForm(forms.ModelForm):
class Meta:
model = Product
fields = ('prod_name')
}
Displaying just one field can be controlled from the templates like:
{% extends 'base.html' %}
{% block body %}
<div class="container">
<form method="POST">
{% csrf_token %}
{{ form.units.label_tag }} /*Shows the label for the input field */
{{ form.units }} /*Shows the input field */
<button type="submit" class="btn btn-primary" name="button">Update Sales</button>
</form>
</div>
{% endblock %}
This is from the official documentation, found here.
Note that you will have to handle creation of the object in the backend, if you choose to display only certain fields like this.

Django-Filter: Dynamically Create Queryset on Search or Hide Queryset until Search

I am using django-filter to search a model. Here is the code:
filters.py:
class PersonFilter(django_filters.FilterSet):
lastName = django_filters.CharFilter(lookup_expr='icontains')
firstName = django_filters.CharFilter(lookup_expr='icontains')
class Meta:
model = Person
fields = ['lastName', 'firstName']
views.py:
def search(request):
people = Person.objects.all()
people = PersonFilter(request.GET, queryset=people)
context = {'filter': people}
return render(request, 'myapp/template.html', context)
template.html:
<form method="get">
{{ filter.form.as_p }}
<button type="submit">Search</button>
</form>
<table>
{% for field in filter.qs %}
<tr>
<td>
{{ field.idno }}
</td>
<td>
{{ field.lastName }}
</td>
<td>
{{ field.firstName }}
</td>
<td>
{{ field.status }}
</td>
</tr>
{% endfor %}
</table>
{% endblock %}
</body>
</html>
Right now, this results in a table that mirrors my model with search boxes for first name and last name. The search works perfectly.
How do I prevent the table of data from showing up initially? Logically, this could be done superficially (hide) or, better yet, substantially (dynamically create queryset). Is this possible?
You can leverage the FilterSet's is_bound property, although you would need to change the view code to only provide the request query params when the form has been submitted.
def search(request):
submitted = 'submitted' in request.GET
data = request.GET if submitted else None
people = PersonFilter(data, queryset=Person.objects.all())
return render(request, 'myapp/template.html', {'filter': people})
<form method="get">
{{ filter.form.as_p }}
<button type="submit" name="submitted">Search</button>
<!-- ^^^^ added 'name' parameter -->
</form>
{% if filter.is_bound %}
<table>
{% for person in filter.qs %}
...

django custom comment's image field not working

I'm doing django-contrib-comment's custom comment app to my django app. At long last i achieved my comment app that has image field, and it shows in template of course. But here is the thing, When i'm trying to post comment with image, it does not saving image file, and says empty(This field is required). Can anyone help me to figure it out. Here is some code snippets.
models.py
class CommentWithPic(Comment):
image = models.ImageField(upload_to="comments/%Y/%m/%d/", null=True, blank=True)
forms.py
class CommentFormWithPic(CommentForm):
image = forms.ImageField()
def get_comment_model(self):
return CommentWithPic
def get_comment_create_data(self):
data = super(CommentFormWithPic, self).get_comment_create_data()
data['image'] = self.cleaned_data['image']
return data
post_with_comment.html
{% render_comment_list for adi %}
{% get_comment_form for adi as form %}
<form action="{% comment_form_target %}" method="post">
{% csrf_token %}
{% for field in form %}
{% if field.is_hidden %}
{{ field }}
{% else %}
{% if field.errors %}{{ field.errors }}{% endif %}
{{ field.label }}
{{ field }}
{% endif %}
{% endfor %}
<input type="hidden" value="{% url 'ad' adi.id %}"/>
<input type="submit" value="comment"/>
</form>
You need to declare your form like the following (notice the enctype attribute) when dealing with `ImageField
<form enctype="multipart/form-data" action="{% comment_form_target %}" method="post">\
to bind uploads to a form:
Dealing with forms that have FileField and ImageField fields is a little more complicated than a normal form.
Firstly, in order to upload files, you’ll need to make sure that your element correctly defines the enctype as "multipart/form-data"
You also need to make the image optional in the form:
class CommentFormWithPic(CommentForm):
image = forms.ImageField(required=False)
...

Django Formset in generic FormView

Hi i used formsets in generic FormView like this:
class RequestRecommendationView(FormView):
template_name = "account/stepfour.html"
form_class = formset_factory(StepFourForm)
def form_valid(self,form):
print form.is_valid()
cleaned_data = form.cleaned_data
# return redirect(reverse("some_url_name"))
form for formset_factory is like this:
class StepFourForm(forms.Form):
contact_person = forms.CharField(required=True)
email = forms.EmailField(required=True)
company = forms.CharField(required=True)
request_message = forms.CharField(required=True)
my html structure is like this:
<div style="padding-top:100px;padding-left:10px;">
<h4> Request a Recommendation </h4>
<form method="post" action="">
{% csrf_token %}
<table id="myForm">
<tbody>
{% for f in form %}
{% for field in f %}
<tr>
<td>{{field.label_tag}}</td>
<td>{{field}}</td>
{% for error in field.errors %}
<td><span>{{ error }}</span></td>
{% endfor %}
</tr>
{% endfor %}
{% endfor %}
</tbody>
</table>
<button class="btn btn-primary btn-xlarge" type="submit" name="submit">Request Now</button>
{{ form.management_form }}
</form>
</div>
Then i used django-dynamic-formset (https://code.google.com/p/django-dynamic-formset/)
to add/remove extra forms through these:
<script type="text/javascript">
$(function() {
$('#myForm tbody').formset();
})
</script>
the problem is:
if i leave the form empty,(every field is required), it manages to get to form_valid() of my class-view (though it should not), if i fill one of the fields (leaving others unfilled), it displays the errors associated message successfully. why is this happening ? what should i do to fix it ? is providing form_class a formset is behind all of this ?
This question has been asked 6 years ago, I found it because i faced the same issue, since it is unanswered, I'll provide the solution i found.
according to the documentation to validate a minimum of forms, you have to provide a min_num and set validate_min=True in the formset_factory:
formset = formset_factory(your_form, min_num=2, validate_min=True, extra=2)

Django forms adding <div> after form field

Below is my form code :
class FMessage(forms.Form):
From = forms.CharField()
To = forms.CharField()
Subject = forms.CharField()
Message = forms.CharField()
and this is my html code:
<form method='POST' action='.'>
{% csrf_token %}
{{ form.as_p }}
<input type='submit' value='submit'>
</form>
The code works fine by displaying forms and has not any issue in functionality, but now I need to wrap my form fields in html by a div like this:
<div id='mydiv'>
<input ... />
<div>
How can I fix it?
Seems like you do not really want to use the inbuilt <p> or <table> wrapped forms and rather want to display the fields wrapped within a <div>'s. You can simply iterate over fields in the form as follows.
{% if form %}
<!-- Form Errors -->
{% if form.errors %}
<ul class="errors">
{% for error in form.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
<!-- Display Form -->
<form>
{% csrf_token %}
{% for field in form %}
<div class="mydiv">
<label class="mylabel">{{ field.label }}</label>
{{ field }}
</div>
{% endfor %}
</form>
{% endif %}
Dont render the form by using form.as_p. You need to show each field of the form, for example, by using form.to. By using this way, you can wrap the field 'to' into a div
<div>{{ form.To}} </div>
For more detail, view this link

Categories