2017-04-19 104 views
1

我有以下型号:的ModelForm和模型验证一起玩

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() 

基于广告客户,位置,类型国家和邮政编码该商店的范围date_from和DATE_TO adverisements。

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 
    .... 

然后将它们放入表单实例的形式。 初始化()

def __init__(self, *args, **kwargs): 
    advertiser = kwargs.pop('advertiser') 
    position = kwargs.pop('position') 
    # .. and so on 
    super(AdvertismentCreateForm, self).__init__(*args, **kwargs) 

对于一些原因,我不认为这是很Python的。有人有更好的主意吗?我会发布我的解决方案。

回答

0

我认为覆盖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 

在模型的清洁方法中,您现在可以访问self.advertiser

+0

thx。 kwargs ['instance']在我的情况下是没有的。可能是因为它是一个创建视图。您的提案在UpdateView中可以正常工作。我已经检查过了。 – mbieren

+0

如果'kwargs ['instance']'是'None',则将其替换! – Alasdair

+0

这工作正常。非常感谢。但是,即使在CreateView.get_form_kwargs()中已经有一个有效的kwargs ['实例')会不会更好?这显然是在UpdateView中执行的。 – mbieren

0

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()中完成了。