How to change form layouts in Django 1.8 - django

I have a form
Field Name: [Input Box]
I want
Field Name:
[Input Box]
How can I achieve this?
forms.py
class SearchForm(forms.Form):
search = forms.CharField()
views.py
form = SearchForm()
html_dtc = {'form':form}
return render_to_response('site/home.html', html_dtc)
home.html
<form method='POST' action=''> {% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-success btn-sm">Update</button>
</form>
Thank you :)

You want a custom form rendering. You can read more about it here. For example, the following code would achieve what you're after.
<form method='POST' action=''> {% csrf_token %}
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} <br/>
{{ field }}
</div>
{% endfor %}
<button type="submit" class="btn btn-success btn-sm">Update</button>
</form>
(field.errors are added, because when you are manually rendering the form, you have to take care of error rendering as well)

Try to overide form.as_p()
class SearchForm(forms.Form):
search = forms.CharField()
def as_p(self):
"Returns this form rendered as HTML <p>s."
return self._html_output(
normal_row='<p%(html_class_attr)s>%(label)s <br> %(field)s%(help_text)s</p>',
error_row='%s',
row_ender='</p>',
help_text_html=' <span class="helptext">%s</span>',
errors_on_separate_row=True)

If this is a one off thing you can render your form manually like described here in the documentation.
Otherwise there's the django-floppyforms which gives you great control over how forms and (default) widgets are rendered.
Just define a custom layout, make it the default, use floppyforms custom Form classes (they behave exactly the same) and you're good to go.
As far as I remember some of floppyforms's functionality will also be included in Django 1.9, so look out for that, too.

Use django_crispy_forms: http://django-crispy-forms.readthedocs.org/en/latest/
In the template include {% load crispy_forms_tags %} and for the form:
{% crispy form %}
In addition, you can change the layout of the form easily, by overriding the form_class in the init function of the form:
class ContactForm(forms.Form):
def __init__(self, *args, **kwargs):
super(ContactForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_tag = False
self.helper.form_class = 'form-horizontal' # <-- leave out for vertical, or form-inline
self.helper.render_hidden_fields = True
self.helper.layout = Layout(
Div(InlineRadios('applying_for_whom'), css_class="col-xs-12"),
Div(InlineRadios('gender'), css_class='col-xs-12'),
Div('agreed_to_data_transmit', css_class="col-xs-12"),
As a bonus, if you are using bootstrap, set also set CRISPY_TEMPLATE_PACK = 'bootstrap3' so then everything is taken care of automatically for vertical bootstrap.

you can do
<form method='POST' action=''>
{% csrf_token %}
<label>Field Name:</label>
{{ form.search }}
<button type="submit" class="btn btn-success btn-sm">Update</button>
</form>

generally I don't recommend use the HTML code generated by Django, but instead I supply what is needed by the DJANGO form.
but some are required: like the ERRORs, like the CSRF token.
let me add some examples to clarify what I am talking
<form class="*" style="*">
<label /><input name="email" />
<label /><input name="password" />
<form>
basically what I am suggesting is, do not use template tags unless absolute necessary like CSRF.
in this way, you can completely separate the design from the backend logic. you can have front end work indecently on the UI. the interface is the form fields, you have to supply all fields to the backend. like in this case 'email' && 'password' is required at backend

Related

Django: Simple solution to prepend $ to form field

I would like to prepend a $ to an input field for a few of my forms. I don't want the $ sent to the backend as part of the input value. I have found a few stack overflow questions that suggest things like the updates below:
self.fields['buy_price'].localize = True
self.fields['buy_price'].widget.is_localized = True
self.fields['buy_price'].prefix = '$'
But none of these are working for me. I also would prefer to avoid adding 50+ lines of code, such as recommended in this S.O. Answer: How to represent Django money field with currency symbol in list template and plain decimal for edits?
HTML form:
{% url 'update-buy/' offer.id as buy_update_url %}
<form method="POST" action="{{ buy_update_url }}">
<div class="form-group">
<legend class="border-bottom mb-4">Update Offer to Buy a Game</legend>
{% csrf_token %}
{{ form|crispy }}
{{ form.media }}
</div>
<input type="hidden" id="hidden_desired_game_id" name="hidden_desired_game" value="{{ offer.desired_game_id }}">
<div class="form-group">
<button onclick="clearMessage()" class="post-button btn btn-outline-info" type="submit">Update</button>
</div>
</form>
Does anyone have a simple way to do this?
UPDATE:
I updated to use {% crispy form %} instead of {{ form|crispy }}, which is nicely showing the $. But now, the hidden input with id="hidden_desired_game_id" is not included in the POST request. For some reason, when rendering the form (screenshot below), that input is now BELOW the form, not inside it. Any idea how I can still have that included?
EDIT #2: I fixed the above problem by moving the input field higher up in the form. But now it looks like jquery is loading twice or something. There are 2 dropdown arrows on the right side of the Desired game field and it looks ugly. I tried using javascript to manipulate the class and played around with the css_class feature from crispy-forms, but i can't get it to only have one dropdown. Does anyone know how to fix that? Screenshot below
SOLUTION FOUND: FINAL UPDATE:
I was able to fix the above issue of 2 dropdowns by adding this javascript:
window.onload = function () {
$( ".custom-select" ).removeClass("custom-select"); // Remove dupe dropdown
}
Kinda hacky but oh well! Everything is good now
You can make use of Bootstrap Layout objects
forms.py
from crispy_forms.helper import FormHelper
from crispy_forms.bootstrap import PrependedText
class ProductForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.layout = Layout(
PrependedText('buy_price', '$')
)
instead of {{ form|crispy }} you have to use {% crispy form %}
The form field will look like

add multiple forms to page on button click

I am working on developing a permitting app using django. This is my first django project so bear with me here...
we have a default utility permit that contains some basic info like property owner and address. Then from that you can attach a sewer, or water or row or any combination of related tables to the permit. Basically I am looking for a way to return a page with the default utility permit then have a series of links or buttons to add more forms to that page.
I made some model forms for each of the models and can display them individually on the page
forms.py
class UtilityPermitForm(forms.ModelForm):
class Meta:
model = UtilityPermit
fields = ['...']
class SewerPermitForm(forms.ModelForm):
class Meta:
model = SewerPermit
fields = ['...']
class WaterPermitForm(forms.ModelForm):
class Meta:
model = WaterPermit
fields = ['...']
I successfully added them to a list and could iterate through and get them to add
views.py
class BuildForms(View):
permits = []
utility_form = UtilityPermitForm
sewer_form = SewerPermitForm
water_form = WaterPermitForm
permits.append(utility_form)
permits.append(sewer_form)
permits.append(water_form)
template_name = 'engineering/UtilityPermitForm2.html'
def get(self, request, *args, **kwargs):
out_permits = []
for form in self.permits:
out_permits.append(form())
return render(request, self.template_name, {'form': out_permits})
def post(self, request, *args, **kwargs):
if request.GET.get('testButton'):
return HttpResponse("I guess")
form = self.utility_form(request.POST)
return render(request, self.template_name, {'form': form})
def add_permit(self, request, permit):
# need to get a thing to add a permit to the list
pass
.html
{% block content %}
<div>
<form class="site_form" action={% url 'engineering:utility_permit' %} method="post">
{% csrf_token %}
{% for item in form %}
{{ item }}
<hr>
{% endfor %}
<input type="submit" value="Submit">
</form>
</div>
{% endblock content %}
so again, my problem is I want to start with a one permit and then have links or buttons to add each form as needed. I'm a bit at a loss here and any help would be greatly appreciated.
EDIT:
so I have this base permit that comes up when a user navigates to it like so, and I want to have a user click the add sewer permit button or link or whatever
and then the corresponding permit will come up
you can create multiple same form in one page dynamically using formset
see Documentation
and maybe this tutorial is exactly what you are looking for.
EDITED
if I understand your question correctly, how about this:
first, it would be better to separate your form with dictionaries instead of list in your views.py
context = {
'utility_form': self.utility_form,
'sewer_form': self.sewer_form,
'water_form': self.water_form
}
return render(request, self.template_name, context)
then in your .html file,
if you want to add one form each time you click the button, my trick is:
show your base permit form first (said utility_form), button to add other form, and hide your other form first.
<div class="form-container">
<form class="site_form" action={% url 'engineering:utility_permit' %} method="post">
{% csrf_token %}
{{ utility_form }}
<div id="additional-forms"></div> <!-- notice this div -->
<hr>
<input type="submit" value="Submit">
</form>
</div>
<button class="add-sewer-form">Sewer Permit</button>
<div id="sewer-form-template" style="display: none;">
<div class="sewer-form-container">
{{ sewer_form }}
</div>
</div>
and then using jquery to add onclick listener, clone that hidden form, then insert it after base form (actually inside div with id additional-forms).
$('.add-sewer-form').click(function(){
let sewer_form = $('#sewer-form-template .sewer-form-container:first').clone(true);
$(sewer_form).appendTo($('#additional-forms'))
});
I haven't test it yet, but when you click the add button, it should be give result like this:
<div class="form-container">
<form class="site_form" action={% url 'engineering:utility_permit' %} method="post">
{% csrf_token %}
{{ utility_form }}
<div id="additional-forms">
<div class="sewer-form-container">
{{ sewer_form }}
</div>
</div>
<hr>
<input type="submit" value="Submit">
</form>
</div>
<button class="add-sewer-form">Sewer Permit</button>
<div id="sewer-form-template" style="display: none;">
<div class="sewer-form-container">
{{ sewer_form }}
</div>
</div>
Hope it can answer your question :)
First add the button
<button><button>
Then add onclick attribute to it which will help react on click
<button onclick='do'><button>
Then create script that contain the function to display the other form
<script>
function do() {
document.getElementById('form').innerHTML ='add your form here'
}
</script>
all together
<button onclick='do'><button>
<script>
function do() {
document.getElementById('form').innerHTML ='add your form here'
}
</script>

Django: How save partial filled form state

I don't know exactly how to ask this question.
The thing is that I have a main view to create new entries in a model. This model has some 1-many relations, so I added a + button to add new entries of this fields (secondary model) in case they did not exist. When I submit this new data I redirect to the previous page (main view), and if you already filled some fields in the main view, that information is lost.
Can someone suggest me what the best way to deal with this would be?
Thanks in advance!
UPDATE:
'main model view'
class OrganismCreate(LoginRequiredMixin,CreateView):
"""Template: //catalog/templates/catalog/organism_form.html"""
model = Organism
fields = '__all__'
'main model template' (part)
<form action="" method="post">
{% csrf_token %}
<div class="panel-group">
<div class="panel panel-default">
<div class="panel-heading">Add a new entry: </div>
<div class="panel-body">
<hr>
<div class="row">
<div class="form-group col-sm-4 col-md-3">
<div class="form-group col-sm-4 col-md-3">
<label for="id_inst_own">Owner:</label>
{% render_field form.inst_own class="form-control" %}
<i class="fa fa-plus-circle "></i> Add new
</div>
<div class="panel panel-default">
<div class="panel-body">
...........................................
<button type="submit" class="btn btn-primary"> <span class="glyphicon glyphicon-filter"></span> submit </button>
</div>
</div>
</div>
Then the related model view:
def test_f(request):
if request.method == "GET":
Form = InstitutionForm()
render(request, 'catalog/institution_form.html')
if request.method == "POST":
Form = InstitutionForm(request.POST)
if Form.is_valid():
Form.save()
next = request.POST.get('next', '/')
return redirect(next)
pre=request.META.get('HTTP_REFERER')
return render(request, 'catalog/institution_form.html',{"form" : Form, "pre": pre})
And the related model template
{% block content %}
<form action="" method="post">
{% csrf_token %}
<table>
{{ form.as_table }}
</table>
<input type="hidden" name="next" value="{{ pre }}">
<input type="submit" class="btn btn-success" value="Submit" />
</form>
{% endblock %}
There are a number of ways to solve this problem. Here's some suggestions. Not an exclusive list:
Save the incomplete model data in the database as as a 'draft' version of the final data. This could be a totally different model or else using the same model (assuming the related fields are nullable) and giving it a 'draft' flag or similar.
Use an inline formset to create the related objects in the same view. Django Extra Views has some useful tools for this (https://github.com/AndrewIngram/django-extra-views).
Using JavaScript, save the unfinished form data to local storage and then recover it when the original form is loaded again.
I have implemented a draft system to do this along the lines of 1. in #ChidG's answer.
In models I have something like
class AbstractThing(models.Model):
field = models.CharField()
class Meta:
abstract = True
class CompleteThing(AbstractThing):
class Meta:
managed = True
db_table = 'complete_thing'
class IncompleteThing(AbstractThing):
fields_to_not_blank = [AbstractThing._meta.get_field(x) for x in []] #if you don't want to change some fields
for f in AbstractThing._meta.fields:
if f not in fields_to_not_blank:
f.blank = True
f.null = True
class Meta:
managed = True
db_table = 'incomplete_thing'
Then you can use model forms and handle the cases in your views.

django modelform with bootstrap

I want to format my modelforms with bootstrap, and without any additional packages (just using the bootstrap source files). A particular form that I want configured:
class FoodForm(forms.ModelForm):
class Meta:
model = Food
fields = ['name', 'company']
exclude = ('user', 'edit')
The 'name' is a text field I'd want to be a bootstrap text field, and 'company' is a selection field (from a foreign key) that I'd want to be a bootstrap dropdown.
The current setup of the form template:
{% extends "mainsite/base.html" %}
{% block content %}
<form method="POST" class="post-form">{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary">Save</button>
</form>
</form>
{% endblock %}
What's best practice for formatting any django modelform field into bootstrap?
The trick to bootstrap fields is injecting the form-control class into each field, and making sure each field lives inside a form-group dom element. To inject that class into each one of your fields, you could so something like:
class FoodForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(FoodForm, self).__init__(*args, **kwargs)
for field in iter(self.fields):
self.fields[field].widget.attrs.update({
'class': 'form-control'
})
Now, in your django template you can iterate through your forms fields, placing each one into a bootstrap'd form-group. For example:
<form method="POST" class="post-form">
{% for field in form %}
<div class="form-group">
{{ field }}
</div>
{% endfor %}
</form>
I'll also say that this setup (Django + Bootstrap) is super common now adays, so googling "Bootstrap forms with django" should yield a wealth of knowledge on customizing this even further. Good luck!
Simply use Django Crispy Forms
It is fairly easy and straight forward

Django Forms to values of html <input> field

I am trying to access the values of a Bootstrap btn-group from Django and from the documentation I have found, it seems that you should use Forms in Django for such tasks.
This is what the html looks like, right now:
<div class="col-md-6">
{% for metric in metrics %}
<input name="{{ metric.name }}" type="hidden" value="0"/>
{% endfor %}
<div class="btn-group" data-toggle="buttons">
{% for metric in metrics %}
<button type="button" class="btn btn-default" data-checkbox-name="{{ metric.name }}">{{ metric.name }}</button>
{% endfor %}
</div>
</div>
How can I use forms to get the values of the input fields?
Here it is a basic example about using a form in django
views.py:
#login_required
def your_view(request): # Add this code into your view
if request.method == 'POST':
# So here you can do a loop over POST fields like this
data_list = [] # We will insert all the inputs in this array
for key in request.POST:
data_list.append(request.POST[key])
# Here you can manage the the data_list and do whatever you need
# The content of the data_list depend on your inputs
# It could be string, integer....
# YOUR VIEW CODE
template (form example):
<form action="." method="post" id="add_user_form">
{% csrf_token %}
{% for metric in metrics %}
<input type="text" name="{{ metric.name }}" placeholder="whatever you want">
{% endfor %}
<input type="submit" value="submit" class="default"/> # Submit button
</form>
{% csrf_token %} : You need to put this in every form you use
action="." : This make the post to the actual page
But anyway I strongly recommend you to check this Django Forms Documentation to unterstand better the logic, and also check the ModelForms because can save you a lot of time when you need to make a form for a model that exists in your Django Models
You are'n forced to use django forms, this is just a way to get a sort of organization.
in you views toy can get the values sent to the server by using request.GET or request.POST, depending of the method of the form.
to get a list of values you have received just do a
print request.POST
request.POST is a dictionary, so you can get any value fron them by its key:
print request.POST['<key>']