ModelForm 和模型验证一起玩
ModelForm and Model validation playing together
我有以下型号:
class Advertisement(models.Model):
slug = models.UUIDField(default=uuid4, blank=True, editable=False)
advertiser = models.ForeignKey(Advertiser)
position = models.SmallIntegerField(choices=POSITION_CHOICES)
share_type = models.CharField(max_length=80)
country = CountryField(countries=MyCountries, default='DE')
postal_code = models.CharField(max_length=8, null=True, blank=True)
date_from = models.DateField()
date_to = models.DateField()
根据广告商、位置、类型国家和 postal 代码,此存储范围为 date_from 和 date_to.
的广告
advertiser, position, share_type, country and postal_code
来自请求并在
中获取
class CreateAdvertisment(LoginRequiredMixin, CreateView):
# Some usefull stuff
def dispatch(self, request, *args, **kwargs):
self.advertiser = Advertiser.objects.get(user=self.request.user)
self.share_type = self.kwargs.get('share_type', None)
self.country = self.kwargs.get('country', None)
self.postal_code = self.kwargs.get('postal_code', None)
self.position = int(self.kwargs.get('position', None))
self.position_verbose = verbose_position(self.position)
ret = super(CreateAdvertisment, self).dispatch(request, *args, **kwargs)
return ret
没有任何检查 date_from、date_to 的验证。我可以简单地做
def form_valid(self, form):
form.instance.advertiser = self.advertiser
form.instance.share_type = self.share_type
form.instance.country = self.country
form.instance.postal_code = self.postal_code
form.instance.position = self.position
ret = super(CreateAdvertisment, self).form_valid(form)
return ret
我完成了。不幸的是,我不能这样做,因为我必须检查广告的有效时间范围,以避免同时进行双重预订。我在模型中使用以下内容执行此操作:
def clean(self):
ret = super(Advertisement, self).clean()
print ("country [%s] position [%s] share_type [%s] postal_code [%s]" % (self.country,
self.position, self.share_type, self.postal_code))
if self.between_conflict():
raise ValidationError("Blocks between timeframe")
elif self.end_conflict():
raise ValidationError("End occupied")
elif self.during_conflict():
raise ValidationError("Time Frame complete occupied")
elif self.start_conflict():
raise ValidationError("Start Occupied")
return ret
def start_conflict(self):
start_conflict = Advertisement.objects.filter(country=self.country,
position=self.position,
share_type=self.share_type,
postal_code=self.postal_code).filter(
date_from__range=(self.date_from, self.date_to))
return start_conflict
这很好用,我过滤掉了给定时间段内的任何冲突。问题是我没有实例变量,因为它们在 view.form_valid() 中设置并且 model.clean() 由表单验证过程调用。
我这里确实有一个鸡蛋问题。我正在考虑将请求参数设置为
中的 kwargs 形式
def get_form_kwargs(self, **kwargs):
kwargs = super(CreateAdvertisment, self).get_form_kwargs()
kwargs['advertiser'] = self.advertiser
kwargs['position'] = self.position
....
然后将它们放入form.init()
中的表单实例中
def __init__(self, *args, **kwargs):
advertiser = kwargs.pop('advertiser')
position = kwargs.pop('position')
# .. and so on
super(AdvertismentCreateForm, self).__init__(*args, **kwargs)
出于某些原因,我认为这不是很 pythonic。有人有更好的主意吗?我会 post 我的解决方案。
我认为覆盖 get_form_kwargs
没问题。如果所有的 kwargs 都是实例属性,那么我会在 get_form_kwargs
方法中更新实例。那么您就不必覆盖表单的 __init__
,或在 form_valid
方法中更新实例的属性。
def get_form_kwargs(self, **kwargs):
kwargs = super(CreateAdvertisment, self).get_form_kwargs()
if kwargs['instance'] is None:
kwargs['instance'] = Advertisement()
kwargs['instance'].advertiser = self.advertiser
...
return kwargs
在模型的 clean 方法中,您现在可以访问 self.advertiser
。
alasdairs 提案工作正常我现在有以下内容:
def get_form_kwargs(self, **kwargs):
kwargs = super(CreateAdvertisment, self).get_form_kwargs()
if kwargs['instance'] is None:
kwargs['instance'] = Advertisement()
kwargs['instance'].advertiser = self.advertiser
kwargs['instance'].share_type = self.share_type
kwargs['instance'].country = self.country
kwargs['instance'].postal_code = self.postal_code
kwargs['instance'].position = self.position
return kwargs
def form_valid(self, form):
ret = super(CreateAdvertisment, self).form_valid(form)
return ret
当然没有必要再覆盖form_valid了。我刚刚包含在这里是为了显示我们不再设置实例字段,因为这已经在 get_form_kwargs()
中完成了
我有以下型号:
class Advertisement(models.Model):
slug = models.UUIDField(default=uuid4, blank=True, editable=False)
advertiser = models.ForeignKey(Advertiser)
position = models.SmallIntegerField(choices=POSITION_CHOICES)
share_type = models.CharField(max_length=80)
country = CountryField(countries=MyCountries, default='DE')
postal_code = models.CharField(max_length=8, null=True, blank=True)
date_from = models.DateField()
date_to = models.DateField()
根据广告商、位置、类型国家和 postal 代码,此存储范围为 date_from 和 date_to.
的广告advertiser, position, share_type, country and postal_code
来自请求并在
中获取class CreateAdvertisment(LoginRequiredMixin, CreateView):
# Some usefull stuff
def dispatch(self, request, *args, **kwargs):
self.advertiser = Advertiser.objects.get(user=self.request.user)
self.share_type = self.kwargs.get('share_type', None)
self.country = self.kwargs.get('country', None)
self.postal_code = self.kwargs.get('postal_code', None)
self.position = int(self.kwargs.get('position', None))
self.position_verbose = verbose_position(self.position)
ret = super(CreateAdvertisment, self).dispatch(request, *args, **kwargs)
return ret
没有任何检查 date_from、date_to 的验证。我可以简单地做
def form_valid(self, form):
form.instance.advertiser = self.advertiser
form.instance.share_type = self.share_type
form.instance.country = self.country
form.instance.postal_code = self.postal_code
form.instance.position = self.position
ret = super(CreateAdvertisment, self).form_valid(form)
return ret
我完成了。不幸的是,我不能这样做,因为我必须检查广告的有效时间范围,以避免同时进行双重预订。我在模型中使用以下内容执行此操作:
def clean(self):
ret = super(Advertisement, self).clean()
print ("country [%s] position [%s] share_type [%s] postal_code [%s]" % (self.country,
self.position, self.share_type, self.postal_code))
if self.between_conflict():
raise ValidationError("Blocks between timeframe")
elif self.end_conflict():
raise ValidationError("End occupied")
elif self.during_conflict():
raise ValidationError("Time Frame complete occupied")
elif self.start_conflict():
raise ValidationError("Start Occupied")
return ret
def start_conflict(self):
start_conflict = Advertisement.objects.filter(country=self.country,
position=self.position,
share_type=self.share_type,
postal_code=self.postal_code).filter(
date_from__range=(self.date_from, self.date_to))
return start_conflict
这很好用,我过滤掉了给定时间段内的任何冲突。问题是我没有实例变量,因为它们在 view.form_valid() 中设置并且 model.clean() 由表单验证过程调用。
我这里确实有一个鸡蛋问题。我正在考虑将请求参数设置为
中的 kwargs 形式def get_form_kwargs(self, **kwargs):
kwargs = super(CreateAdvertisment, self).get_form_kwargs()
kwargs['advertiser'] = self.advertiser
kwargs['position'] = self.position
....
然后将它们放入form.init()
中的表单实例中def __init__(self, *args, **kwargs):
advertiser = kwargs.pop('advertiser')
position = kwargs.pop('position')
# .. and so on
super(AdvertismentCreateForm, self).__init__(*args, **kwargs)
出于某些原因,我认为这不是很 pythonic。有人有更好的主意吗?我会 post 我的解决方案。
我认为覆盖 get_form_kwargs
没问题。如果所有的 kwargs 都是实例属性,那么我会在 get_form_kwargs
方法中更新实例。那么您就不必覆盖表单的 __init__
,或在 form_valid
方法中更新实例的属性。
def get_form_kwargs(self, **kwargs):
kwargs = super(CreateAdvertisment, self).get_form_kwargs()
if kwargs['instance'] is None:
kwargs['instance'] = Advertisement()
kwargs['instance'].advertiser = self.advertiser
...
return kwargs
在模型的 clean 方法中,您现在可以访问 self.advertiser
。
alasdairs 提案工作正常我现在有以下内容:
def get_form_kwargs(self, **kwargs):
kwargs = super(CreateAdvertisment, self).get_form_kwargs()
if kwargs['instance'] is None:
kwargs['instance'] = Advertisement()
kwargs['instance'].advertiser = self.advertiser
kwargs['instance'].share_type = self.share_type
kwargs['instance'].country = self.country
kwargs['instance'].postal_code = self.postal_code
kwargs['instance'].position = self.position
return kwargs
def form_valid(self, form):
ret = super(CreateAdvertisment, self).form_valid(form)
return ret
当然没有必要再覆盖form_valid了。我刚刚包含在这里是为了显示我们不再设置实例字段,因为这已经在 get_form_kwargs()
中完成了