Django 模型表单和模型验证一起玩

Django 模型表单和模型验证一起玩,django,validation,model,modelform,Django,Validation,Model,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 = mode

我有以下型号:

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的广告

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
未对检查日期从、日期到进行任何验证。我能做的很简单

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
这很有效,我过滤掉了给定时间段内的任何冲突。问题是我没有在视图中设置的实例变量。表单验证过程调用form_valid()和model.clean()

我确实有个鸡蛋问题。我正在考虑将requests参数设置为

def get_form_kwargs(self, **kwargs):
    kwargs = super(CreateAdvertisment, self).get_form_kwargs()
    kwargs['advertiser'] = self.advertiser
    kwargs['position'] = self.position
    ....
然后将它们放入表单中的表单实例中。init()


出于某些原因,我不认为这是非常蟒蛇。有人有更好的主意吗?我将发布我的解决方案。

我认为覆盖
get\u form\u kwargs
是可以的。如果所有kwargs都是实例属性,那么我将在
get\u form\u kwargs
方法中更新实例。这样,您就不必重写表单的
\uuuu init\uuuu
,也不必在
表单\u 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

我认为覆盖
get\u form\u kwargs
是可以的。如果所有kwargs都是实例属性,那么我将在
get\u form\u kwargs
方法中更新实例。这样,您就不必重写表单的
\uuuu init\uuuu
,也不必在
表单\u 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。广告商

阿拉斯代尔的提案很好,我现在有以下内容:

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

当然,没有必要再覆盖有效的表单。我刚刚在这里加入,以显示我们不再设置实例字段,因为这在get_form_kwargs()中已经完成了

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

当然,没有必要再覆盖有效的表单。我刚才在这里加入是为了显示我们不再设置实例字段,因为这已经在get_form_kwargs()中完成了。kwargs['instance']在我的例子中是没有的。可能是因为它是createview。在更新视图中,您的建议将很有效。我已对此进行了检查。如果
kwargs['instance']
None
,请将其替换!这个很好用。谢谢。但是,即使在CreateView.get_form_kwargs()中也有一个有效的kwargs['instance']不是更好吗?因为这显然是在UpdateView中执行的。是的,如果
CreateView
kwargs['instance']
设置为新的模型实例,而不是
None
,则会简化上面的代码。我认为这样会更好,因为我在这里混合了信息。视图与表单不一样,对模型一无所知。thx。kwargs['instance']在我的例子中是没有的。可能是因为它是createview。在更新视图中,您的建议将很有效。我已对此进行了检查。如果
kwargs['instance']
None
,请将其替换!这个很好用。谢谢。但是,即使在CreateView.get_form_kwargs()中也有一个有效的kwargs['instance']不是更好吗?因为这显然是在UpdateView中执行的。是的,如果
CreateView
kwargs['instance']
设置为新的模型实例,而不是
None
,则会简化上面的代码。我认为这样会更好,因为我在这里混合了信息。视图与表单不同,它对模型一无所知。