Styling forms and django form values - django

I'm trying to style a form with CSS. First of all I haven't seen a complete example, other than on the official documentation, so I would appreciate any blog entries, or articles.
Now on my form, a typical Charfield gets translated on html like this:
<input type="text" name="artists" id="id_artists" />
If my form contains errors on some field, the previous Charfield remembers the value and goes:
<input type="text" name="artists" value="Pink Floyd" id="id_artists" />
How can I get this value (value="Pink Floyd") in django forms? Say my field is {{form.artists}}, I can use {{form.artists}} as the field, {{form.artists.label}} as label, {{form.artists.errors}} and {{form.artists.help_text}}, but how about this value?
Thanks in advance!

Create the input field specifically, rather than relying on django to auto-create it.
Something like:
<input type="text" name="artists" id="id_artists" value="{{form.artists.title}}" />
should work

You can get the current value of the field from the data property:
{{ form.artists.data }}
I can't see the Django documentation mentioning this, but it works...

You can also add additional validation to the form class to do something with the form data. From djangobook.com:
from django import forms
class ContactForm(forms.Form):
subject = forms.CharField(max_length=100)
email = forms.EmailField(required=False)
message = forms.CharField(widget=forms.Textarea)
def clean_message(self):
message = self.cleaned_data['message']
num_words = len(message.split())
if num_words < 4:
raise forms.ValidationError("Not enough words!")
return message
Inside of the clean_message method you can access a given field using the self.cleaned_data dictionary. This dictionary is available for any form that is validated.
Be sure to return the field, in this case message, or else None is returned.

Related

Django cannot save blank value in FloatField

I have a simple model in Django:
class Test(models.Model):
name = models.FloatField(default=0.0, blank=True)
In my views.py, I am fetching user input from a page. The html code is:
<form action="{% url 'test' %}" method="POST">
{% csrf_token %}
<input type="number" placeholder="Test" class="form-control mb-2" name="test">
<input type="submit" class="btn btn-primary" value="Submit">
</form>
The views.py code is:
name = request.POST.get('test', '0.0') #I have tried without the '0.0' as well.
new_test = Test(name=name)
new_test.save()
I keep getting the error:
ValueError at /test
Field 'name' expected a number but got ''.
How can I make django save a blank value or '0.0'(default value) or a null value when the user enters nothing. It seems to accept none of these.
Your field name is a FloatField hence it expects numbers, hence when an empty string ('') is passed to it you get an error. request.POST.get('test', '0.0') does not work because when the user submits the field leaving it blank the fields value is kept as an empty string, meaning the key is present in request.POST but it's value is ''.
Normally if one would have used a Form class [Django docs] or a ModelForm class, these values would have been cleaned automatically by the form and would have been replaced by None. I would advice you to use the form classes. If you still insist on doing things manually you would go about cleaning the value somewhat like this:
from django.core import validators
name = request.POST.get('test', '0.0')
if name in validators.EMPTY_VALUES: # if name in (None, '', [], (), {})
name = None
else:
name = float(name) # Might still get error here, if receiving non-numeric input
new_test = Test(name=name)
new_test.save()
Note: This is just a very small part of cleaning and validation, there are more errors that can occur here, example a user enters a non-numeric input into the field, etc. I would advice using form classes.
You have to use something like this:
name = models.FloatField(null=True, blank=True, default=0.0)

How to get type=time field in DJango

I am trying to use input type = time in Django. But every time my type = text. I have tried it:
field_name = forms.TimeField()
<!--return-->
<input type="text" name="field_name" required id="id_field_name">
this:
time_st = forms.TimeField(widget=forms.TimeInput(format='%H:%M'))
<!--return-->
<input type="text" name="time_st" value="" required id="id_time_st">
How to get an effect like this:
<input type="time" id="appt" name="appt" class="form-control" required>
Appologies if this is not the answer you are looking for I was trying to decrypt your question.
So you have a form which is something like this:
class MyForm(forms.Form):
time = forms.TimeField()
This is your basic django form which has a field called time.
In your django view you will need something like the following which will parse the form making it "usable".
def form_handler(request):
if request.method == 'POST':
form = MyForm(request.POST)
if form.is_valid():
print(form.valid_data['time'])
return redirect('valid_time_url_redirect')
return ... # failure of validation see form.errors
form = MyForm()
return render('django_template.html', {'form': form})
This is probably not valid code but hopefully it will point you in the right direction as to what you need to do.
There is TimeField and DateTimeField in both the models and the form classes. Make sure you are using the correct one for your usecase. Also make sure you take a look at the expected inputs for each field. Look at time_input_formats, this is a common gotcha for using these fields.

How do I use the input of one field in multiple places on a form?

I'm very new to Django, so please forgive me if I'm using some of the terminology incorrectly.
In one of my templates, I'm trying to use a form that has multiple input fields. In this specific case, the value of the two fields will always be the same (userName and userID will always match if they are at this template) and I do not want to alter the form itself. For this reason, I want to customize the form in this template so that there is only one place for the user to provide input, and use that in both fields of the form so that the user doesn't need to type in their ID twice.
This is the code fragment I'm currently using:
<form method="post">
{% csrf_token %}
<label>ID:</label>
<input type="text" name="userID" id="userID" placeholder="Type your ID number here.">
<input type="hidden" name="userName" id="userName" value=userID>
<button type="submit">Login</button>
</form>
I know that the issue is with the "value=userID" bit, but I've been searching and I can't figure out how to use information from one input field in multiple places. How do I take the userID and submit it as the userName without requiring the user to input it twice?
You don't need to provide the same input two times to use it in your back-end. You can use the same value in the back-end.
So let's say you have want the userName in your back-end to be same as userID value:
def login_page(request):
if request.method == 'POST':
userID = request.POST.get('userID')
userName = userID
That was the basic idea, if you are using class based views with Django's forms, you should place this code in the form_valid method.

Dynamically Delete form from model formset django

I have a web page where users can dynamically add and delete forms, to django formsets.
I have read Dynamically adding a form to a Django formset with Ajax, based on which I can add the forms to a formset dynamically. Now I want to delete the formset dynamically. I have looked at Dynamically Delete inline formsets in Django
The way I want to do it is when user clicks on delete, I have an ajax function that deletes the form instance record from the database. When my ajax function returns I keep the same total_form_count and initial_form_count and just the hide the form html so that even the deleted record is submitted in my POST.
Initially the formset renders its form elements as:
#form0
<input id="id_formprefix-0-id" type ="hidden "value="something" name="formprefix-0-id">
<input id="id_formprefix-0-field" value="something" type="text" name="formprefix-0-field">
#form1
<input id="id_formprefix-1-id" type ="hidden "value="something" name="formprefix-1-id">
<input id="id_formprefix-1-field" value="something" type="text" name="formprefix-1-field">
#form2
<input id="id_formprefix-2-id" type ="hidden "value="something" name="formprefix-2-id">
<input id="id_formprefix-2-field" value="something" type="text" name="formprefix-2-field">
Now suppose I dynamically delete form 0, using ajax, after my record is deleted, I do not change the form counts, so the total_form_count and initial_form_count are 3.
( If i reduce the total_form_count and initial_form_count in this case to 2, when I populate the formset in my view using POST data, it is expected to be ordered as form0 and form1. But in my case the valid forms are form1 and form2)
Now in my view, I am do something like the following to save my form.
myformset = modelformset_factory(ObjectElement,form=Object_Form, extra=0, can_delete=True)
for form in myformset.forms:
print(form.instance.id) #this does not print id of deleted record, but of the first existing record in the database.
print(form.instance.attribute)# this prints the correct element, which was submitted by POST even for a deleted record.
try:
objectInstance = ObjectElement.objects.get(id = form.instance.id)
objectInstance.save()
except ObjectElement.DoesNotExist:
print("Do not save as the record has already been deleted")
When I save my formset without deleting any record the saving works ok and the correct form.instance.id is printed.
However if I delete a form instance using ajax, and then try to save my formset, the
print(form.instance.id) for the deleted record seems to print the first available id in the database, but not the id that was submitted by post. (As the record is deleted , the id is not present in the database, but should it print what was submitted to it via POST right? )
If I do it without the try/catch loop I get the following error by form.errors:
<ul class="errorlist"><li>id<ul class="errorlist"><li>Select a valid choice. That choice is not one of the available choices.</li></ul></li></ul>
which seems to indicate that it is not accepting the correct form ID form the submitted post for the deleted record.
Any body has any idea as to what I am missing here? Or a better way to do this.
How to we go about dynamically deleting forms from formsets, as it seems that the order of the forms should be sequential..
Thanks in Advance!! Any help is appreciated.
For those who stumble across this issue this could be a possible solution
I am able to dynamically delete my form from formset as follows.
So the initial form html looks like
#form0
<input id="id_formprefix-0-id" type ="hidden "value="something" name="formprefix-0-id">
<input id="id_formprefix-0-field" value="something" type="text" name="formprefix-0-field">
#form1
<input id="id_formprefix-1-id" type ="hidden "value="something" name="formprefix-1-id">
<input id="id_formprefix-1-field" value="something" type="text" name="formprefix-1-field">
#form2
<input id="id_formprefix-2-id" type ="hidden "value="something" name="formprefix-2-id">
<input id="id_formprefix-2-field" value="something" type="text" name="formprefix-2-field">
Now suppose I delete form0 and form1 records from my database using ajax.
When I submit the form, the formset will not validate, because it expects the forms to be in order, and I only have form 2 remaining in the data base ( I deleted the top two). Formset errors with "Select a valid choice" as described in the question.
So after I delete the forms dynamically, when my ajax returns, I do not change the total_form_count,(https://docs.djangoproject.com/en/1.4/topics/forms/formsets/#understanding-the-managementform) but mark the form as deleted in my html, and just hide the form. Now when the formset is submitted using POST, it also submits the deleted form, but marked as deleted (https://docs.djangoproject.com/en/1.4/topics/forms/formsets/#can-delete)
Now in the view, I first filter out the forms that have been deleted, and only process the forms that still remain as follows
marked_for_delete = formset.deleted_forms
for form in formset.forms:
#Filtering out the deleted records, as the formset will not validate, for deleted records
# if we use form.instance.id or form.initial['id'] below it does not work.
#for some reason it returns the id of the first available record in the data base.
#form['id'].value(), gives us the id of the deleted element we are looking for
if form['id'].value() not in [deleted_record['id'].value() for deleted_record in marked_for_delete]:
if form.is_valid():
pass
# save the form
else:
pass
# error message

Using a radio button across forms in a formset in django

I have a page, where I display different forms using formsets.
These are my models:
class Phone(models.Model):
mac = models.CharField()
class PhoneLine(models.Model):
phone = models.ForeignKey(Phone)
voicemail = models.BooleanField("Voice Mail", default=False)
A phone can have many lines (phoneline), but only one phone line can have voice mail enabled.
By default when I display phonelines using formset, the voice mail field displays as a check box as follows.(I have added prefix to the formset, based on requirements)
form1 of the formset
<input type="checkbox" name="phone_client_line_1-0-voicemail" id="id_phone_client_line_1-0-voicemail">
form2 of the formset
<input type="checkbox" name="phone_client_line_1-1-voicemail" id="id_phone_client_line_1-1-voicemail">
(The checking and un-checking of the checkboxes update the backend)
Based on this thread, Django - Show BooleanField in a formset as one group of radio buttons, I modified the init and add_prefix method of my phoneline form to now display the voicemail field as radio buttons..
class PhoneLineForm(ModelForm):
def __init__ (self, *args, **kwargs):
super(PhoneLineForm, self).__init__(*args, **kwargs)
self.fields['voicemail'] = BooleanField( widget = RadioSelect(choices=((self.prefix+"-"+str("voicemail"), 'Voicemail LIne'),)))
def add_prefix(self, field):
if field == 'voicemail': return ('%s_%s') %(field, self.instance.phone.id)
else: return self.prefix and ('%s-%s' % (self.prefix, field)) or field
This modifies the html output to the following:
form1 of the formset
<input type="radio" id="id_voicemail_1_0" value="phone_client_line_1-0-voicemail" name="voicemail_1">
form2 of the formset
<input type="radio" id="id_voicemail_1_0" value="phone_client_line_1-1-voicemail" name="voicemail_1">
As you see, now for the radio field voicemail_1, I have the value of the selected phoneline.
If I submit this form, after I select a voicemail_1 radio, it does not update the database.
How can I capture the value of the phoneline selected on submit?. If I overwrite the save method of the phonelineform, what should it contatin..?
Any pointers on this would be appreciated. Thanks!!
I'd actually suggest simplifying this, and relying on JavaScript (you can always validate server-side and show a message to the user if they have selected more than one phone line with voicemail because they've not got JavaScript enabled).
This would be simpler than trying to hack the field names and values. Django formsets are hard enough beasts to wrangle at the best of times, so adding further server-side complexity is often not worth the hassle, especially when the problem can be solved - in a not too-inelegant way - via a little judicious jQuery work.
$('input[name^="voicemail_"]').on('click',
function() {
$('input[name^="voicemail_"]').not($(this)).prop('checked', false);
}
);
Just a rough-and-ready suggestion; hope it's useful.