Django覆盖外键表单小部件以接收用户输入的最佳实践
我定义了一个模型,该模型具有其他模型的一些外键。因此,我在models.py中有以下内容:Django覆盖外键表单小部件以接收用户输入的最佳实践,django,forms,django-models,django-forms,django-views,Django,Forms,Django Models,Django Forms,Django Views,我定义了一个模型,该模型具有其他模型的一些外键。因此,我在models.py中有以下内容: class Appelation(models.Model): appelation = models.CharField(max_length=100, verbose_name=_('Appelation'), validators=[non_numeric],
class Appelation(models.Model):
appelation = models.CharField(max_length=100,
verbose_name=_('Appelation'),
validators=[non_numeric],
blank=True,
unique=True
)
class Wine(models.Model):
appelation = models.ForeignKey(ForeignKeyModel, null=True, blank=True, verbose_name=_('Appelation'))
forms.py
class WineForm(ModelForm):
class Meta:
model = Wine
appelation= CharField(widget=TextInput)
class WineCreateView(WineActionMixin, LoginRequiredMixin, CreateView):
model = Wine
form_class = WineForm
action = 'created'
def post(self, *args, **kwargs):
self.request.POST = self.request.POST.copy() # makes the request mutable
appelationForm = modelform_factory(Appelation, fields=('appelation',))
form_dict = {
'appelation': appelationForm
}
for k, modelForm in form_dict.iteritems():
model_class = modelForm.Meta.model
log.debug('current model_class is: %s' % model_class)
log.debug('request is %s' % self.request.POST[k])
try:
obj = model_class.objects.get( **{k: self.request.POST[k]} )
log.debug("object exists. %s pk from post request %s " % (model_class,obj.pk))
self.request.POST[k] = obj.id
except ObjectDoesNotExist as e:
log.error('Exception %s' % e)
f = modelForm(self.request.POST)
log.debug('errors %s' % f.errors)
if f.is_valid():
model_instance = f.save()
self.request.POST[k] = model_instance.pk
return super(WineCreateView,self).post(self.request, *args, **kwargs)
视图.py
class WineForm(ModelForm):
class Meta:
model = Wine
appelation= CharField(widget=TextInput)
class WineCreateView(WineActionMixin, LoginRequiredMixin, CreateView):
model = Wine
form_class = WineForm
action = 'created'
def post(self, *args, **kwargs):
self.request.POST = self.request.POST.copy() # makes the request mutable
appelationForm = modelform_factory(Appelation, fields=('appelation',))
form_dict = {
'appelation': appelationForm
}
for k, modelForm in form_dict.iteritems():
model_class = modelForm.Meta.model
log.debug('current model_class is: %s' % model_class)
log.debug('request is %s' % self.request.POST[k])
try:
obj = model_class.objects.get( **{k: self.request.POST[k]} )
log.debug("object exists. %s pk from post request %s " % (model_class,obj.pk))
self.request.POST[k] = obj.id
except ObjectDoesNotExist as e:
log.error('Exception %s' % e)
f = modelForm(self.request.POST)
log.debug('errors %s' % f.errors)
if f.is_valid():
model_instance = f.save()
self.request.POST[k] = model_instance.pk
return super(WineCreateView,self).post(self.request, *args, **kwargs)
基本上,视图代码所做的是,如果我们传递的Appelation模型实例不存在,它会尝试创建一个新的Appelation模型实例(这是一个fk到Wine)。它在字段中返回pk,因为我们期望的是pk,而不是字符串作为输入
我想创建appelationForm,因为我需要应用一些自定义验证器来验证foreignKey输入
我现在看到的限制是,我不知道如何将appelationForm中的验证错误附加到主窗体中的验证错误,以便显示它们,而不是通常从foreignKey字段中显示的验证错误
要查看完整的示例代码,请执行以下操作:
您应该做的是在
WineForm
上编写一个clean_appelation
方法,该方法根据您的条件(即现有appelation id或新appelation name)全面验证输入,并引发相应的错误。然后在您的视图中,您可以假设表单数据是有效的,并且可以正常工作。这应该给你一些开始的东西:
class WineForm(ModelForm):
...
appelation= CharField(widget=TextInput)
def clean_appelation(self):
data = self.cleaned_data['appelation']
if data.isdigit():
# assume it's an id, and validate as such
if not Appelation.objects.filter(pk=data):
raise forms.ValidationError('Invalid Appelation id')
else:
# assume it's a name
if ...:
raise forms.ValidationError('Invalid Appelation name')
return data
您应该做的是在
WineForm
上编写一个clean_appelation
方法,该方法根据您的条件(即现有appelation id或新appelation name)全面验证输入,并引发相应的错误。然后在您的视图中,您可以假设表单数据是有效的,并且可以正常工作。这应该给你一些开始的东西:
class WineForm(ModelForm):
...
appelation= CharField(widget=TextInput)
def clean_appelation(self):
data = self.cleaned_data['appelation']
if data.isdigit():
# assume it's an id, and validate as such
if not Appelation.objects.filter(pk=data):
raise forms.ValidationError('Invalid Appelation id')
else:
# assume it's a name
if ...:
raise forms.ValidationError('Invalid Appelation name')
return data
您应该做的是在
WineForm
上编写一个clean_appelation
方法,该方法根据您的条件(即现有appelation id或新appelation name)全面验证输入,并引发相应的错误。然后在您的视图中,您可以假设表单数据是有效的,并且可以正常工作。这应该给你一些开始的东西:
class WineForm(ModelForm):
...
appelation= CharField(widget=TextInput)
def clean_appelation(self):
data = self.cleaned_data['appelation']
if data.isdigit():
# assume it's an id, and validate as such
if not Appelation.objects.filter(pk=data):
raise forms.ValidationError('Invalid Appelation id')
else:
# assume it's a name
if ...:
raise forms.ValidationError('Invalid Appelation name')
return data
您应该做的是在
WineForm
上编写一个clean_appelation
方法,该方法根据您的条件(即现有appelation id或新appelation name)全面验证输入,并引发相应的错误。然后在您的视图中,您可以假设表单数据是有效的,并且可以正常工作。这应该给你一些开始的东西:
class WineForm(ModelForm):
...
appelation= CharField(widget=TextInput)
def clean_appelation(self):
data = self.cleaned_data['appelation']
if data.isdigit():
# assume it's an id, and validate as such
if not Appelation.objects.filter(pk=data):
raise forms.ValidationError('Invalid Appelation id')
else:
# assume it's a name
if ...:
raise forms.ValidationError('Invalid Appelation name')
return data
但是,我仍然需要将现有的Appelation转换为有效的foreignKey id,对吗?如果是,这意味着我仍然需要检查FK存在并在需要时创建它的视图代码。是的,您仍然在视图中进行保存,但您不必担心处理任何
DoesNotExist
异常,因为您已经验证了表单中的数据。但是,我仍然需要将现有的Appelation转换为有效的foreignKey id,对吗?如果是,这意味着我仍然需要检查FK存在并在需要时创建它的视图代码。是的,您仍然在视图中进行保存,但您不必担心处理任何DoesNotExist
异常,因为您已经验证了表单中的数据。但是,我仍然需要将现有的Appelation转换为有效的foreignKey id,对吗?如果是,这意味着我仍然需要检查FK存在并在需要时创建它的视图代码。是的,您仍然在视图中进行保存,但您不必担心处理任何DoesNotExist
异常,因为您已经验证了表单中的数据。但是,我仍然需要将现有的Appelation转换为有效的foreignKey id,对吗?如果是,这意味着我仍然需要检查FK存在并在需要时创建它的视图代码。是的,您仍然在视图中进行保存,但您不必担心处理任何DoesNotExist
异常,因为您已经验证了表单中的数据。