I have multiple form that handle with one view.
When I want to show my form in index.html and specific the field,Such as {{form_1.some_field}} All help texts and fields name disappear!
When I use {{ form_1}} everything run correctly. What is the problem?
This is my files:
index.html
<form method="post" class="mos-rtl">
{% csrf_token %}
<div>
<h4 class="mos-rtl">Section 1</h4>
<p>{{ form_1.some_field }}</p>
</div>
<div>
<h4 class="mos-rtl">Section 2</h4>
{{ form_2.some_field }}
<button type="submit" >submit</button>
</div>
</form>
forms.py
class Form1(ModelForm):
class Meta:
model = Model1
fields = '__all__'
class Form2(ModelForm):
class Meta:
model = Model2
fields = '__all__'
Views.py
def my_view(request):
if request.method == "POST":
form_1 = Form1(request.POST)
form_2 = Form2(request.POST)
if form_1.is_valid() and form_2.is_valid():
new_record_1 = form_1.save(commit=False)
new_record_1.save()
new_record_2 = form_2.save(commit=False)
new_record_2.record_1 = new_record_1
new_record_2.save()
return redirect('administrator:view_admin_curriculum')
else:
form_1 = Form1(request.POST)
form_2 = Form2(request.POST)
template = 'index.html'
context = {'form_1': form_1, 'form_2': form_2}
return render(request, template, context)
{{ form }} calls form.__str__() method, which on the other hand calls form.as_table(). So, because of this {{ form }} and {{ form.as_table }} are rendered in a same fashion.
Form class also support different kinds of rendering methods, like as_table(), as_p(), as_ul() (This is how Form object should be rendered as a html). All these methods implementation are in BaseForm class, which represents parent class of Form. This is source code.
So, You should try like this:
<form method="post" class="mos-rtl">
{% csrf_token %}
<div>
<h4 class="mos-rtl">Section 1</h4>
<p>{{ form_1.some_field }} {{ form_1.some_field.help_text }}</p>
</div>
<div>
<h4 class="mos-rtl">Section 2</h4>
{{ form_2.some_field }} {{ form_2.some_field.help_text }}
<button type="submit" >submit</button>
</div>
</form>
If you are trying to render Form fields manually like you did, You should render help_text (manually also), which represents attribute of field.
Related
This is my forms.
class CreateBooksForm(forms.ModelForm):
languages = forms.CharField(widget=forms.TextInput)
file = forms.FileField(widget=forms.FileInput(attrs={'accept':'application/pdf'}))
class Meta:
model = Book
fields = "name","languages", "about","image","file"
This is my view.So when I render to my update view template I get the empty form for languages and files but other are populated.
#login_required
def post_update(request,pk):
update = get_object_or_404(Book,pk=pk)
form = CreateBooksForm(request.POST or None ,request.FILES or None,instance=update)
if request.method == 'POST':
if form.is_valid():
post = form.save(commit=False)
languages = form.cleaned_data['languages']
post.save() # must be save before adding m2m
tag_list=[Language.objects.get_or_create(name=tag)[0] for tag in post.languages.lower().split()]
for tag in tag_list:
a = post.language.add(tag)
post.language.set = a
post.save()
messages.success(request,'Updated successfully!')
update_book.delay(post.pk)
context ={
'form':form
}
return render(request,'books/update.html',context)
my template.So this is simple django crispy template I have used.
<form method="POST" enctype="multipart/form-data">
<input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token }}">
<img class="rounded-circle" src="/media/{{form.image.value}}" height="100px" width="150px">
{{ form|crispy }}
<button type="submit" class="btn btn-dark">Update Books</button>
</form>
You'll have to render each field manually to get the prepopulated field.
for example:
{% for field in form %}
{% if field.languages %}
<input type="name" id={{ field.languages.id_for_label }} value={{ field.languages.value }}/>
{% endif %}
{% endfor %}
for more details refer docs
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.
I have view (CBV) with django-ckeditor on front-end side. Everything is working, but I can't validate text field (is mandatory), when I'm clicking "Post comment" button, I don't receive any message that this field is required.
Below is my code.
form.py
class Comment(forms.ModelForm):
text = forms.CharField(widget=CKEditorUploadingWidget(), label='', required=True)
class Meta:
model = Comment
form in template:
<form action="" method="POST">
{% csrf_token %}
{{ form.media }}
{{ form.as_p }}
<button type="submit" class="btn btn-primary">Post comment</button>
</form>
I want to replace the add object button in the listview of an admin page. The underlying idea is that an administrator can download data on all models in the db, use a tool to edit the data, and then reupload as a CSV file.
In the list view I am struggling to override the form, as setting
class SomeModelForm(forms.Form):
csv_file = forms.FileField(required=False, label="please select a file")
class Meta:
model = MyModel
fields = '__all__'
class SomeModel(admin.ModelAdmin):
change_list_template = 'admin/my_app/somemodel/change_list.html'
form = SomeModelForm
other stuff
The admin change_list.html is overridden as follows:
{% extends "admin/change_list.html" %}
{% load i18n admin_urls admin_static admin_list %}
{% block object-tools-items %}
<form action="{% url 'admin:custom_submit_row' %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<p>
{{ form.as_p }}
</p>
<p><input type="submit" value="Upload" /><input type="reset" value="Reset"></p>
</form>
{% endblock %}
Previously SomeModel was missing the class Meta, as per sebbs response this is updated. The original error has been resolved but now currently the admin page is displaying the upload and reset buttons but no field for file uploads.
cheers
Edited with sebb's input below. Thanks sebb.
The error fixed was
< class ‘my_model.admin.SomeModelAdmin'>: (admin.E016) The value of 'form' must inherit from 'BaseModelForm'
OP here, solution is as follows:
class SomeModelForm(forms.Form):
csv_file = forms.FileField(required=False, label="please select a file")
class SomeModel(admin.ModelAdmin):
change_list_template = 'admin/my_app/somemodel/change_list.html'
def get_urls(self):
urls = super().get_urls()
my_urls = patterns("",
url(r"^upload_csv/$", self.upload_csv, name='upload_csv')
)
return my_urls + urls
urls = property(get_urls)
def changelist_view(self, *args, **kwargs):
view = super().changelist_view(*args, **kwargs)
view.context_data['submit_csv_form'] = SomeModelForm
return view
def upload_csv(self, request):
if request.method == 'POST':
form = MineDifficultyResourceForm(request.POST, request.FILES)
if form.is_valid():
# process form
with the template overridden as so:
{% extends "admin/change_list.html" %}
{% load i18n admin_urls admin_static admin_list %}
{% block object-tools %}
{% if has_add_permission %}
<div>
<ul class="object-tools">
{% block object-tools-items %}
<form id="upload-csv-form" action="{% url 'admin:upload_csv' %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<p>{{ form.non_field_errors }}</p>
<p>{{ submit_csv_form.as_p }}</p>
<p>{{ submit_csv_form.csv_file.errors }}</p>
<p><input type="submit" value="Upload" />
<input type="reset" value="Reset"></p>
</form>
{% endblock %}
</ul>
</div>
{% endif %}
{% endblock %}
The form needs some custom validation but otherwise this solves the difficult part of customizing the admin page.
To elaborate what is going on here:
get_urls is overridden so that an additional endpoint can be added to the admin page, this can point to any view, in this case it points upload_csv
changelist_view is overridden to append the form info to the view
the change_list.html template block "object-tools" is overridden with the form fields
Hopefully someone else finds this helpful as well.
to your class SomeModelForm add something like this:
class Meta:
model = YourModel
fields = '__all__'
and change from forms.Form to forms.ModelForm
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.