2017-04-19 90 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()中完成了。