I'm looking to implement a zipcode field in django using the form objects from localflavor, but not quite getting them to work. I want to have a zipcode field in a form (or ModelForm in my case), but the fields never validate as a zipcode when calling _get_errors() on the form object. The way I'm implementing it seems right to me but is apparently wrong, does anyone know what the right way to do this might be?
I have a ModelForm that I want to use zipcode (and also USStateField) in:
from django.contrib.localflavor.us.forms import USStateField
from django.contrib.localflavor.us.forms import USZipCodeField
class FooForm(ModelForm):
class Meta:
model = Bar
fields = ('address', #This form uses a subset of fields from the model
'address_apt',
'address_city',
'address_state',
'address_zip',
'home_phone',
'mobile_phone')
widgets= {
'address_zip' : USZipCodeField(),
'address_state' : USStateField(),
}
The ModelForm 'FooForm' links to a model that looks like:
from django.contrib.localflavor.us import models as usmodels
class Bar(models.Model):
db_table = 'BAR'
address = models.CharField(max_length=255)
address_apt = models.CharField(max_length=40, blank=True)
address_city = models.CharField(max_length=90)
address_state = usmodels.USStateField()
address_zip = models.CharField(max_length=15)
home_phone = usmodels.PhoneNumberField( )
mobile_phone = usmodels.PhoneNumberField( )
#... There are more fields in the model...
But if I create an instance of the form and run it's validation, it never cares about the form level validation, only the model level validation:
foo_instance = FooForm(request.POST)
#Let's assume request.POST looks like:
#<QueryDict: {u'address_city': [u'asdf'], u'mobile_phone': [u'asdf'], u'address_state': [u'California'], u'home_phone': [u'asdf'], [u'1'], u'address': [u'123 foo'], u'address_zip': [u'asdf']}>
foo_instance._get_errors()
Yields:
<ul class="errorlist">
<li>mobile_phone<ul class="errorlist">
<li>Phone numbers must be in XXX-XXX-XXXX format.</li></ul>
</li><li>home_phone<ul class="errorlist">
<li>Phone numbers must be in XXX-XXX-XXXX format.</li></ul>
</li></ul>
I need to be able to call validation on the populated form object and have it tell me that the zipcode is formated improperly if so. Doing something wrong, just don't know what atm.
Using widgets declaratively has literally only just been added to the trunk SVN version in the last day or so. If you're using an older checkout, or a released version, it won't work - you'll need to go back to the old way of doing it, by overriding the field declarations at the top level of the form.
Related
I have a formset as follows:
TableAddFormSet = modelformset_factory(Table, form=TableAddForm)
The model looks like this:
class Table(models.Model):
restaurant = models.ForeignKey(Restaurant, on_delete=models.CASCADE)
amount_of_people = models.IntegerField()
category = models.CharField(max_length=10)
reserved = models.BooleanField(default=False)
Now the model required the attribute 'restaurant', which I will set on form-submission. Until now I've done the following:
for form in formset:
form.instance.restaurant = request.user.restaurant
which means that even forms that already existed get looped through and updated. Is there a more efficient way to add this attribute to the newly added forms, something like:
for form in formset.new_forms():
or is my implementation the most suitable way for solving this problem?
You should be able to use inlineformset_factory like this:
TableAddFormSet = inlineformset_factory(Restaurant, Table, form=TableAddForm)
table_formset = TableAddFormSet(request.POST or None, instance=request.user.restaurant)
As the name implies, it's more intended for when you create a form that has a formset within it (so, a "restaurant" form that has multiple "table" entries within it), but it should work fine for what you're doing too.
Im seeing a weird behaviour with my modelform. If I submit and a field has errors, when I re display it with the errors, excluded fields are appearing. Also its happening that the fields were translated into spanish and I m getting the labels in the original English.
I m using django 1.6.10, does anyone know if this is a bug or I m doing something wrong?
I'm not doing anything fancy with the rendering, I'm just doing {{ form }} in the template.
For instance this is a normal form
But if I submit the field empty I get the extra excluded field "notes" and the original field's name in English "plate number":
Here is the model code:
class Operation3Domain(models.Model):
operation = models.ForeignKey(Operation, unique=True)
date = models.DateTimeField(auto_now_add=True)
update_date = models.DateTimeField(auto_now=True)
notes = models.TextField(blank=True, null=True)
#this one is the only one I want to show:
plate_number = NumberPlateField()
class Meta:
app_label = "operation"
and the model form:
class Operation3DomainForm(forms.ModelForm):
class Meta:
model = Operation3Domain
labels = { 'plate_number': 'Dominio/Patente'}
exclude = ['operation', 'notes']
I appreciate any help! Thanks!!
Let me answer my own question!
So the problem to excluded fields was that in the creation of the form I had an outdated exclude parameter (sorry!), which is overriding the form's exclude.
form_class = modelform_factory(step_model, exclude=('operation',))
form = form_class(request.POST, instance=instance)
BUT! I still don't know why the form appears in English instead of spanish, which doesn't happen if I use the form class directly:
form = Operation3DomainForm(request.POST, instance=instance)
Thanks!
I've got a model with a recursive relationship to itself:
class Tweet(models.Model):
text = models.CharField(max_length=140)
original = models.ForeignKey("self", null=True, blank=True)
And a serializer that renders the original Tweet inline:
class TweetSerializer(serializers.ModelSerializer):
class Meta:
model = Tweet
fields = ('id', 'text', 'original', 'original_id')
original_id = serializers.IntegerField(source='original_id', required=False)
def to_native(self, obj):
ret = super(TweetSerializer, self).to_native(obj)
del ret['original_id']
return ret
TweetSerializer.base_fields['original'] = TweetSerializer(source='original', read_only=True)
As you can see I've also got an original_id field that is removed in to_native. The purpose of original_id is to allow me to set the original_id of a new tweet, rather than having to supply a full blown Tweed object to the original field. You could say that I'm using it as a write only field.
This seems a bit clunky though. Is there a better way to do it?
OK, two points:
Have you tried using PrimaryKeyRelatedField for your original_id? It would seem to target your use-case specifically. Combined with the depth option it may give you everything you need.
You can switch serializers (e.g. based on request method) by overriding get_serializer_class() on your view. Not sure if you'll get the exact behaviour you want here though.
I'm struggling to get my head round django forms.. I've been reading various documentation but just can't quite grasp the concepts. I have got to grips with models, views and templates. What I am trying to do is to create a form with various fields composing of dropdown lists and checkboxes which are populated by values in a database.
I have a working app called vms. Using the models.py I have a built a simple schema that holds size and type. Size consists of 'small', 'medium' & 'large'. Type is 'windows' & 'linux'. Using the admin site, I can add an extra size, for example 'Extra Large'.
What I would like to do is create a form that has a drop down list of the vm sizes. If an extra size gets added via the admin site, I would like that size to appear in the drop down list.
I would submit my attempts at the code, but actually am struggling with the concepts. Can anyone help guide me in how to accomplish the above?
Thanks
Oli
Forms are just a tool to simplify and speed-up (the development of) the process of fetching POST data from the request. A manual way would be to do request.POST.get('somefield') for all the fields there are in some HTML form. But Django can do better than that...
In its essence, a Form class holds a number of Fields and performs these tasks:
display HTML inputs,
collect and validate data when user submits it,
if fields don't validate, return the values along with error messages to HTML,
if all fields validate, provide form.cleaned_data dictionary as a convenient way to access these values in view.
With these values, I could then manually create a new instance of a MyModel and save it. Of course, I would have to define a Field in the Form for every Field in MyModel model.
This means that, basically, I could do something like this:
(forgive me for not testing this code, so I can't vouch that it's 100% correct)
models.py:
class MyModel(models.Model):
field1 = models.CharField(max_length=40, blank=False, null=False)
field2 = models.CharField(max_length=60, blank=True, null=True)
forms.py:
class FormForMyModel(forms.Form):
form_field1 = forms.CharField(max_length=40, required=True)
form_field2 = forms.CharField(max_length=60, required=False)
views.py:
def create_a_my_model(request):
if request.method == 'POST':
form = FormForMyModel(request.POST)
if form.is_valid():
my_model = MyModel()
my_model.field1 = form.cleaned_data.get('form_field1', 'default1')
my_model.field2 = form.cleaned_data.get('form_field2', 'default2')
my_model.save()
else:
form = FormForMyModel()
context_data = {'form': form}
return HttpResponse('templtate.html', context_data)
(this could be written with a few lines of code less, but it's meant to be as clear as possible)
Notice there are no relation between model Fields and form Fields! We have to manually assign values to MyModel instance when creating it.
The above example outlines generic form workflow. It is often needed in complex situations, but not in such a simple one as is this example.
For this example (and a LOT of real-world examples), Django can do better than that...
You can notice two annoying issues in the above example:
I have to define Fields on MyModel and Fields on FormForMyModel separately. However, there is a lot of similarity between those two groups (types) of Fields, so that's kind of duplicate work. The similarity grows when adding labels, validators, etc.
creating of MyModel instance is a bit silly, having to assign all those values manually.
This is where a ModelForm comes in.
These act basically just like a regular form (actually, they are extended from regular forms), but they can save me some of the work (the two issues I just outlined, of course :) ).
So back to the two issues:
Instead of defining a form Field for each model Field, I simply define model = MyModel in the the Meta class. This instructs the Form to automatically generate form Fields from model Fields.
Model forms have save method available. This can be used to create instance of model in one line in the view, instead of manually assigning field-by-field.
So, lets make the example above with a ModelForm:
models.py:
class MyModel(models.Model):
field1 = models.CharField(max_length=40, blank=False, null=False)
field2 = models.CharField(max_length=60, blank=True, null=True)
forms.py:
class MyModelForm(forms.ModelForm): # extending ModelForm, not Form as before
class Meta:
model = MyModel
views.py:
def create_a_my_model(request):
if request.method == 'POST':
form = MyModelForm(request.POST)
if form.is_valid():
# save the model to database, directly from the form:
my_model = form.save() # reference to my_model is often not needed at all, a simple form.save() is ok
# alternatively:
# my_model = form.save(commit=False) # create model, but don't save to database
# my.model.something = whatever # if I need to do something before saving it
# my.model.save()
else:
form = MyModelForm()
context_data = {'form': form}
return HttpResponse('templtate.html', context_data)
Hope this clears up the usage of Django forms a bit.
Just one more note - it is perfectly ok to define form Fields on a ModelForm. These will not be used in form.save() but can still be access with form.cleaned_data just as in a regular Form.
Have you tried working with ModelForms before? As I understand, you're looking to create a form based on the model you created right?
Lets say your model is called Temp. You can create a form that correlates with this model (and your question) like this:
forms.py
from django.forms import ModelForm
class TempForm(ModelForm):
class Meta:
model = Temp
The ModelForm will automatically map the selections/choices from your model to a form version.
If you plan on using this in a template later, doing something like this will automatically create a drop-down menu with choices:
<form>
<label for="id_size">Size</label>
{{ form.size }}
</form>
Hope that answers your question!
Simply use CharField in your modelform as below:
SIZES_CHOICES = (
('size1', 'M'),
('size2', 'L'),
)
size = models.CharField(max_length=100, choices=SIZES_CHOICES, default=size1)
in the above code, size1 is the value which will be going to store in your database as name 'size1' and in the drop-down menu, there will be an option is 'M' of right side.you can mentioned any name to these options.
I have a Django model:
class Customer(models.Model):
first_name=models.CharField(max_length=20,null=True, blank=True)
last_name=models.CharField(max_length=25,null=True, blank=True)
address=models.CharField(max_length=60,null=True, blank=True)
address2=models.CharField(max_length=60,null=True, blank=True)
city=models.CharField(max_length=40,null=True, blank=True)
state=models.CharField(max_length=2,null=True, blank=True)
From there, I created a ModelForm:
class CustomerForm(forms.ModelForm):
class Meta:
model=Customer
I'd like to be able to show pieces of the form in my template corresponding to specific information the users can change. For example, if I want to let the customers change their name, I'd like to be able to show a form that only has the fields 'first_name' and 'last_name'.
One way to do this would be to create a ModelForm for each of the various field snippets... for the name example, it would look something like:
class CustomerFormName(forms.ModelForm):
class Meta:
model=Customer
fields=('first_name','last_name')
This seems pretty inelegant, and inflexible. What I'd like to do is be able to specify the fields at runtime, so when I pass the dictionary from the view to the template, I can just set which fields I'd like to show. How can I set it up so that I set the fields for a form at runtime? I'd ideally like the final dictionary passed to look something like this:
{'name_change_form':CustomerFormName(<form with only first_name and last_name>), 'address_change_form':CustomerFormName(<form with only address fields>)}
Then, I know that whenever I output name_change_form.as_p, it'll have exactly the form fields that I'm looking for.
Thoughts? Also feel free to recommend a better way to do it.
from django.forms import ModelForm
from wherever import Customer
def formClassFactory(model,fields):
ff = fields
mm = model
class formClass(ModelForm):
class Meta:
model = mm
fields = ff
return formClass
form_class = formClassFactory( ('first_name','last_name') )