Django: Unable to add UPPERCASE attribute name in HTML input element - django

I'm trying to use a javascript library in django that requires some attributes for HTML elements in camelCase. For example, I've a model with a CharField field like this:
expires = models.DateField("Expiration Date", db_index = False, blank = True, null = True, editable = True, help_text = "Something")
My ModelForm has the following line in the init method:
self.fields['expires'].widget.attrs['SomeAttribute'] = "SomeValue"
and after the render_to_response the outputed HTML is like this:
<input id="id_expires" type="text" name="expires" someattribute="SomeValue">
instead of:
<input id="id_expires" type="text" name="expires" SomeAttribute="SomeValue">
Am I missing something?

As Issac points out at the top, what you've should be correct. The Django internals responsible for rendering the above in django.forms.widgets
return mark_safe(u'<input%s />' % flatatt(final_attrs))
should give you the correct attr you're looking for. I did get to replicate your problem when I inspected the HTML rendered in Firebug. It seems that Firebug lowercases the attribute name but when I did a view source code, it did show as SomeAttribute versus someattribute in Firebug (if this is indeed what you're doing :))

I couldn't find anything in the django forms codebase that suggests that it's anything that's django's fault. How are you rendering the form? Please see my shell session for my details.
>>> from django import forms
>>> class F(forms.Form):
... a = forms.CharField()
...
>>> f = F()
>>> f.as_p()
u'<p><label for="id_a">A:</label> <input type="text" name="a" id="id_a" /></p>'
>>> f.fields['a'].widget.attrs
{}
>>> f.fields['a'].widget.attrs['dERP'] = 'ddf'
>>> f.as_p()
u'<p><label for="id_a">A:</label> <input id="id_a" type="text" name="a" dERP="ddf" /></p>'
>>>

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 full field's id in view?

It's easy for templates: {{ field.id_for_label }}, but how to do same in view?
I need to get full id (with id_ and prefix). I can calculate it, but maybe is there a simpler way?
Update: I want to make a dictionary like {field_id: field_error_message} and send it back to browser as json response.
In view you can do the same - get the id_for_label property of the bound form field:
>>> from django import forms
>>> class MyForm(forms.Form):
... name = forms.CharField()
...
>>> form = MyForm(prefix='myform')
>>> form['name'].id_for_label
u'id_myform-name'
>>>

django : set default value for formset_factory form element

Model:
class AssociatedFileCourse(models.Model)
file_original = models.FileField(upload_to = 'assets/associated_files')
session = models.ForeignKey(Session)
title = models.CharField(max_length=500)
Form:
class AddAssociatedFilesForm(ModelForm):
class Meta:
model = AssociatedFileCourse
If I had to create a single form from above defination and set some initial value, It could have done using initial parameter like
form = AddAssociatedFilesForm(initial={'session': Session.objects.get(pk=id)})
how to set the initial form values when creating a formset_factory forms like:
AddAssociatedFilesFormSet = formset_factory(AddAssociatedFilesForm)
form = AddAssociatedFilesFormSet()
You want to use modelformset_factory, which is tailored to create and act on formsets of Model instances.
from django.forms.models import modelformset_factory
# create the formset by specifying the Model and Form to use
AddAssociatedFilesFormSet = modelformset_factory(AssociatedFileCourse, form=AddAssociatedFilesForm)
# Because you aren't doing anything special with your custom form,
# you don't even need to define your own Form class
AddAssociatedFilesFormSet = modelformset_factory(AssociatedFileCourse)
By default a Model formset will display a form for every Model instance - i.e. Model.objects.all(). In addition you'll have blank forms allowing you to create new Model instances. The number of blank forms is subject to the max_num and extra kwargs passed to modelformset_factory().
If you want initial data you can specify it with the initial kwarg when generating the formset. Note, the initial data needs to be inside a list.
formset = AddAssociatedFilesFormSet(queryset=AssociatedFileCourse.objects.none(),
initial=[{'session': Session.objects.get(pk=id)}])
That should look like you want it. However, you cannot (in current Django versions at least) create a Model formset with existing Model instances and initial data for the extra forms. That's why the objects.none() queryset is there. Set it to objects.all() or remove the queryset kwarg and - if you have instances - the extra forms will not have the initial data.
Further reading on Model formsets with initial data - see this post.
You would do it in the same way, except using a list of values in the dictionary rather than just a value.
From Django docs on formsets:
>>> ArticleFormSet = formset_factory(ArticleForm, extra=2)
>>> formset = ArticleFormSet(initial=[
... {'title': u'Django is now open source',
... 'pub_date': datetime.date.today()},
... ])
>>> for form in formset:
... print form.as_table()
<tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" value="Django is now open source" id="id_form-0-title" /></td></tr>
<tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" value="2008-05-12" id="id_form-0-pub_date" /></td></tr>
<tr><th><label for="id_form-1-title">Title:</label></th><td><input type="text" name="form-1-title" id="id_form-1-title" /></td></tr>
<tr><th><label for="id_form-1-pub_date">Pub date:</label></th><td><input type="text" name="form-1-pub_date" id="id_form-1-pub_date" /></td></tr>
<tr><th><label for="id_form-2-title">Title:</label></th><td><input type="text" name="form-2-title" id="id_form-2-title" /></td></tr>
<tr><th><label for="id_form-2-pub_date">Pub date:</label></th><td><input type="text" name="form-2-pub_date" id="id_form-2-pub_date" /></td></tr>

pre-selected checkbox in django with django forms

Am trying to display a pre-selected checkbox in Django :
option = forms.BooleanField(required=False, initial=True)
but the checkbox shows up un-checked. Am using django 1.3 beta. Am I missing something here ?
import django
from django import forms
class MyForm(forms.Form):
option = forms.BooleanField(required=False, initial=True)
>>>print MyForm()
<tr><th><label for="id_option">Option:</label></th><td><input checked="checked" type="checkbox" name="option" id="id_option" /></td></tr>
>>> django.VERSION
(1, 3, 0, 'beta', 1)
>>>
As you can see the checked="checked" is properly set.
Are you sure you are not modifying something with onload javascript ?
Set the attributes field:
options = forms.MultipleChoiceField(label='some label', choices=(('happy','Happy'),('sad','Sad')),
widget=forms.CheckboxSelectMultiple(attrs={'checked' : 'checked'}))
Try:
option = forms.BooleanField(
widget=forms.CheckboxInput(attrs={'checked': True})
)

Styling forms and django form values

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.