Django call cleaned_data on all fields - django

Is there a way to call cleaned_data on all fields with some function instead of individually calling it for each field?
Also, why do we even need to call cleaned_data?
I am not sure if I need it here... I am using a for loop to save a formset, but it only saves the last one. Here is the code
for instance in form:
tmp = instance.save(commit=False)
# it throws an error when I try to do tmp[foreign_key] = other_model
setattr(tmp, foreign_key, other_model)
tmp.save()

What are you hoping for? You don't ever call it. cleaned_data gets populated upon validating the form.
form.is_valid() populates form.cleaned_data, which is a dictionary storing all data "cleaned" i.e. validated and converted to their python types.
I don't think one can make data much more accessible than a dictionary of keys mapped to field names.
As for your latest update, that itself is pretty confusing.
You appear to be setting an attribute on a foreign key in your modelform instance based on a local variable named 'gen_house_form_saved' (which I don't understand as well: if it's in the locals() namespace, and you're not using a dynamic name, why use locals at all).

Related

what's the value type of the value of request.POST in django?

This is from print(request.POST)
<QueryDict: {'csrfmiddlewaretoken': ['2Tg4HgJ07qksb3hPUDWSQYueYOjYOkQcmzll9fnjbJ0GZHkWHdM8DtYqZB4uv3Fv'], 'username': ['boycececil'], 'password': ['password']}>
This is from print(request.POST.get('username'))
boycececil
So as you can see, list (from one of the values of QueryDict)-> string(from the get function), that's magic! Isn't it?
So, somebody know what's going on?
What the value type of the value of request.POST in django?
The type is django.http.request.QueryDict
So as you can see, list -> string, that's magic! Isn't it?
No, it isn't magic. This is just the documented behavior of QueryDict:
"QueryDict.__getitem__(key)
Returns the value for the given key. If the key has more than one value, it returns the last value. ..."
Note: if you want all values for a key, you can call getlist(key) on the QueryDict.
So, the request.POST is a subclass of the dictionary but not a raw dictionary.
It is a subclass of the django MultiValueDict class which is a subclass of dict.
When I call get(key) to the Querydict it return the last value of the list. Sounds like the get method in Querydict overwrite the get method in the raw dictionary.
Yes ... that is what the __getitem__ method does.
By the way, I wonder why we need multiple value for one key.
It is because HTTP allows multiple values for a given parameter in a request. So if multiple values can be provided, django need to be able to make them available via the HttpRequest.POST object.
But since this is an unusual case, they decided to just give your code one value for each parameter ... unless it specifically asks for them all. Django is being helpful.

Django ValidationError - how to use this properly?

Currently there is code that is doing (from with the form):
# the exception that gets raised if the form is not valid
raise forms.ValidationError("there was an error");
# here is where form.is_valid is called
form.is_valid() == False:
response['msg']=str(form.errors)
response['err']='row not updated.'
json = simplejson.dumps( response ) #this json will get returned from the view.
The problem with this, is that it is sending err message to the client as:
__all__"There was an error."
I want to remove the "all" garbage from the error template that is returned. How can I go about doing this? it seems to get added deep in django form code.
It's because the error is not associated with any field in particular, but it's so called non-field error.
If you're only interested in non-field errors, just simply pass this to the response:
response['msg']=str(form.errors['__all__'])
errors is an instance of a subclass of dict with some special rendering code. Most of the keys are the fields of the form, but as the docs describe, raising ValidationError in clean produces an error message that isn't associated with any particular field:
Note that any errors raised by your Form.clean() override will not be associated with any field in particular. They go into a special “field” (called __all__), which you can access via the non_field_errors() method if you need to. If you want to attach errors to a specific field in the form, you will need to access the _errors attribute on the form, which is described later.
https://docs.djangoproject.com/en/dev/ref/forms/validation/
So you can either generate your string representation of the errors differently (probably starting with form.errors.values() or form.errors.itervalues(), and maybe using the as_text method of the default ErrorList class) or associate your error with a particular field of the form as described in the docs:
When you really do need to attach the error to a particular field, you should store (or amend) a key in the Form._errors attribute. This attribute is an instance of a django.forms.utils.ErrorDict class. Essentially, though, it’s just a dictionary. There is a key in the dictionary for each field in the form that has an error. Each value in the dictionary is a django.forms.utils.ErrorList instance, which is a list that knows how to display itself in different ways. So you can treat _errors as a dictionary mapping field names to lists.
If you want to add a new error to a particular field, you should check whether the key already exists in self._errors or not. If not, create a new entry for the given key, holding an empty ErrorList instance. In either case, you can then append your error message to the list for the field name in question and it will be displayed when the form is displayed.
https://docs.djangoproject.com/en/dev/ref/forms/validation/#form-subclasses-and-modifying-field-errors

Django forms without widgets

I understand that Django want to generate forms automatically so you don't have to do so in your template, and I do understand that many people find it cool.
But I have specific requirements and I have to write my forms on my own. I just need something to parse the data, be it a form submitted using a user interface, or an API request, or whatever.
I tried to use ModelForm, but it doesn't seem to work as I want it to work.
I'd like to have something with the following behavior:
possibility to specify the model of the object I am going to create/update
possibility to specify an object in case of an update
possibility to provide new data in a dictionary
if I am creating a new object, missing fields in my data should be replaced by their default values as specified in my model definition
if I am updating an existing object, missing fields in my data should be replaced by the current values of the object I am updating. Another way of saying is, do not update values that are missing in my data dictionary.
data validation should be performed before calling save(), and it should throw a ValidationError with the list of erroneous fields and errors.
Currently, I prefer to do everything manually :
o = myapp.models.MyModel() # or o = myapp.Models.MyModel.objects.get(pk = data['pk'])
o.field1 = data['field1']
o.field2 = data['field2']
…
o.full_clean()
o.save()
It would be nice to have a shortcut :
o = SuperCoolForm(myapp.models.MyModel, data)
o.save()
Do you know if Django does provide a solution for this or am I asking too much?
Thank you!

In a Django form clean function, how can one reliably test if an optional field was filled out?

In Django, I have a form class with a clean function. In this clean function, I check to see if an optional select box was filled out.
def clean_session_1(self):
# Check if session_1 is filled out.
if self.cleaned_data['session_1']:
# more validation
return self.cleaned_data['session_1']
If the select box was filled out, then more validation of the field ensues.
For some reason, this code is not testing whether the field was filled out and runs "more validation" every time.
I was wondering how can one reliably test if this field "session_1" was filled out? Thanks!
Access self._raw_value('key') to get the raw entry in the form field (i.e. just text, not processed to a python object).
Update: As Ahsan says, do it in the clean method. You should probably call the superclass clean method also.
You can check it in form's clean method
def clean(self):
data = self.data # data contains all fields, optional or required both
optional_field = data.get('optional_field', None)
# more validation
return optional_field

Auto-truncating fields at max_length in Django CharFields

I have a field that has a max_length set. When I save a model instance, and the field's value is greater than max_length, Django enforces that max_length at the database level. (See Django docs on models: http://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.CharField.max_length)
However, since I am using Postgres, I receive a DatabaseError exception like this:
DatabaseError: value too long for type character varying(1000)
I would prefer to instead auto-truncate the value (so I don't have an exception). Now, I can do this manually, but what I would really want is to have all of my models auto-truncate the value. (Not necessarily intelligently. Just cutting it off at the 999th character is fine.)
Should I just write a custom class that imports from models.Model and override the save() method, looping through each _meta.field, checking for the max_length, and then truncating? That seems inelegant and there must be a better way.
You could create a custom field that auto-truncates the field (I think this code should work, but double-check it):
class TruncatingCharField(models.CharField):
def get_prep_value(self, value):
value = super(TruncatingCharField,self).get_prep_value(value)
if value:
return value[:self.max_length]
return value
Then, instead of using models.CharField in your models.py file, you'd just use TruncatingCharField instead.
get_prep_value prepares the value for a field for insertion in the database, so it's the ideal place to truncate.
Why don't you use a TextField? From the manual:
For large amounts of text, use
TextField.
Why don't you use ModelForm. ModelForm enforces a validation, setting its default max_length to model field's max_length property, and raising proper validation error when form.is_valid() is called. That way you don't have to save the form, until form is validated.
Or, if you want to silently pass the validation and truncate suits best to you, write a simple django form, and write a clean method that truncates input string to the max_length and return stripped data. Take data from form.cleaned_data after form is validated and save the object.
All considering the fact, Forms are designed to validate data before going to DB.
That seems inelegant and there must be a better way.
The only reason the truncate behavior ever happens in the first place is because of MySQL's failure to adhere to the SQL Standard. The throwing of an exception is the correct response when attempting to INSERT a string into a VARCHAR field that is not wide enough to hold it. MySQL truncates and inserts instead.
If you want to silently corrupt your data, then you'll have to do it manually somehow--PostgreSQL will never do it for you.