问题
I have a form with a select list.
When the user selects a value of 8888 or 9999 from the award_grant_type
select list, I want some of the data that may or may not exist in the form input fields (the user may have entered data into the form text input fields and then selected 8888 or 9999) to be deleted before the form data is commited to the database.
So I have the following model.py code:
.....
DISPLAY_ONLY_AWARD_AND_GRANT_DESCRIPTION_WITH_PROMPT = 8888
DISPLAY_ONLY_AWARD_AND_GRANT_DESCRIPTION_WITHOUT_PROMPT = 9999
.....
AWARD_GRANT_TYPES = (
(SELECT_AWARD_AND_GRANT_TYPE, _('Select Type')),
(AWARD, _('Award')),
(GRANT, _('Grant')),
(TRAVEL_GRANT, _('Travel Grant')),
(OTHER_AWARD, _('Other Award')),
(OTHER_GRANT, _('Other Grant')),
(WRITE_MY_OWN_AWARD_AND_GRANT_TYPE_DESCRIPTION, _('Write my own Type description')), #7777
(DISPLAY_ONLY_AWARD_AND_GRANT_DESCRIPTION_WITH_PROMPT, _('Display only Description with prompt')), #8888
(DISPLAY_ONLY_AWARD_AND_GRANT_DESCRIPTION_WITHOUT_PROMPT, _('Display only Description without prompt')) #9999
)
user = models.ForeignKey(User)
language_version = models.ForeignKey('LanguageVersion')
award_grant_type = models.PositiveIntegerField(choices=AWARD_GRANT_TYPES, default=SELECT_AWARD_AND_GRANT_TYPE, validators=[MinValueValidator(1)])
award_grant_type_description = models.CharField(null=True, blank=True, max_length=250)
award_grant_date = models.DateField(null=True, blank=True)
award_grant_description = models.TextField(null=False, blank=False, max_length=5000)
Here is my forms.py clean code that should remove the award_grant_type_description
and award_grant_date
fields when the user has selected 8888 or 9999 from the select list award_grant_type
before being committed to the db:
def clean(self):
cd_agdf = super(AwardGrantDetailsForm, self).clean()
if 'award_grant_type' in cd_agdf:
if cd_agdf['award_grant_type'] == '':
self._errors['award_grant_type'] = self.error_class([_("You must select a Type.")])
elif cd_agdf['award_grant_type'] == 8888 or cd_agdf['award_grant_type'] == 9999:
# remove the entered values when the award grant type only requires minimum data.
self.cleaned_data.pop('award_grant_type_description', None)
self.cleaned_data.pop('award_grant_date', None)
else:
....
return cd_agdf
Can anyone point out what I have done incorrectly? The award_grant_type_description
and award_grant_date
are not removed before the form data is committed to the db.
EDIT / UPDATE
This issue only occurs when the existing record is updated. A new record removes the data as required before the form is saved to the db. When an existing record has a date field as part of the db record and the award_grant_type
is changed from say 1 to 8888 or 9999, then the award_grant_date
is NOT removed from the db. I cannot figure out why.
2nd EDIT
I have posted a related thread here.
回答1:
Try to change self.cleaned_data
to cd_agdf
. Dictionary, that method clean
returns, will be used as cleaned_data
. You popped items from self.cleaned_data
, but returned not changed cd_ahdf
. This is described here (see last step starting with "The form's subclass...").
回答2:
Answering to the edit only: there is a fight over what the data means.
Form validation happens first, its purpose is to parse the submitted data, clean it up and point any error in the data. The result of this step should be the cleaned up, canonical form of the data.
Then action: if valid, form is acted upon. You interpret that data to take appropriate action. Here, writing it to a database.
Your two steps disagree on the meaning of data. Validation removes award_grant_type_description
and award_grant_date
from the final data to mean “blank out those fields”. Then, the action interprets missing data as “leave that field as it is” (that's what the default ModelForm.save()
does).
Your choice: either conform to ModelForm
's convention and set the fields to None
instead of removing them, or override your form's save()
so it interprets missing data as “remove from object”. Unless I had a good reason to alter ModelForm's semantics, I'd go with setting the fields to None
.
回答3:
I finally figured this issue out.
When I wrap the values in quotation marks, the issue is resolved.
Here is the example code I used that works:
elif cd_agdf['award_grant_type'] == '8888' or cd_agdf['award_grant_type'] == '9999':
I hope that this will help someone.
回答4:
instead of self.cleaned_data.pop()
do cd_agdf.pop()
as you are assigning cd_agdf
to superclass
来源:https://stackoverflow.com/questions/31134274/using-django-cleaned-data-pop-to-remove-data-before-commit-to-db