【问题标题】:Sharing form logic between Django Rest Framework and UI在 Django Rest Framework 和 UI 之间共享表单逻辑
【发布时间】:2018-09-20 19:04:17
【问题描述】:

我的 django 应用程序有一个实体 Campaign。对于我的 UI,我实现了 CampaignForm,它的逻辑并不简单。

我还集成了 Django Rest Framework,以通过 API 允许 Campaign 类的 CRUD 功能。

在 Google 和 DRF 的文档上搜索后,我发现 没有将 Django Forms 集成到 DRF 中的官方方法

我一定是搞错了吧?

我唯一看到的是 DRF 有自定义验证器,但我认为它不能将我的表单的所有逻辑移植到 DRF 的验证器。

如何将我的 CampaignForm 逻辑包含到我的 API 中?

参考:

class CampaignForm(forms.ModelForm):

    class Meta:
        model = Campaign
        fields = '__all__'
        help_texts = {
            'dayparting_schedule': schedule_help_text
        }

    def __init__(self, *args, **kwargs):
        self.request = kwargs.pop('request', None)
        super().__init__(*args, **kwargs)

    def clean(self, *args, **kwargs):
        """
        - All Active MUST have dayparting schedule defined
        - If schedule is set then timezone must also be set
        """
        cleaned_data = super().clean()
        status = cleaned_data.get('status')
        dayparting_schedule = cleaned_data.get('dayparting_schedule')

        if status == Campaign.ACTIVE:
            # if there is no existing dayparting_schedule OR
            # if this form does not have dayparting_schedule
            if dayparting_schedule is None \
                    and self.instance.dayparting_schedule is None:
                raise forms.ValidationError(_('dayparting_schedule cannot be empty for Active'))

        schedule_present = bool(dayparting_schedule)
        timezone_present = bool(cleaned_data.get('dayparting_timezone'))

        # XOR: 0^0, 1^1 => 0, otherwise 1
        if schedule_present ^ timezone_present:
            raise forms.ValidationError(
                _('dayparting_schedule and dayparting_timezone must be set together.'))

        return cleaned_data

    def clean_dayparting_schedule(self, *args, **kwargs):
        schedule = self.cleaned_data.get('dayparting_schedule')
        if not schedule:
            return
        self.validate_schedule(schedule)
        return schedule

    def validate_schedule(self, yaml_s):
        dic = yaml.load(yaml_s)
        if not isinstance(dic, dict):
            raise forms.ValidationError(_('Invalid Format: Please follow the format above'))
        if set(dic.keys()) != set(['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']):
            raise forms.ValidationError(_('Invalid Format: Missing mon/tue/wed/thu/fri/sun'))
        for v in dic.values():
            if not re.match('[0-9]{4}-[0-9]{4}$', v):
                raise forms.ValidationError(_('Invalid Format: value must be 1200-1500'))

【问题讨论】:

    标签: python django django-forms django-rest-framework


    【解决方案1】:

    简而言之: Django rest 框架有 serializers 模块,它等同于 Django 的 forms

    您应该创建Serializer(或ModelSerializer)来处理与CampaignForm 中相同的逻辑。

    看看Serializers | Django Rest Framework Docs

    【讨论】:

    • 有没有办法将它们组合在一起,以便我可以在一个地方测试逻辑? (如您所见,我的表单的逻辑并非微不足道且经过大量测试)
    • 您可以将您的逻辑放在模型级别,并从表单和序列化程序中调用这些方法。
    • 同样不推荐在 Meta fields 属性中使用__all__,不安全。
    • 谢谢。也许我错过了什么?为什么这个功能不是原生的?
    • 你指的是哪个功能?
    【解决方案2】:

    如果你想弄脏你的手:

    class CampaignSerializer(serializers.ModelSerializer):
        ... 
    
        def validate(self, data):
            """
            During updating, self.instance will be available.
            """
            form = CampaignForm(data, instance=self.instance)
            if form.is_valid():
                return data
            raise serializers.ValidationError(str(form.errors))
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-22
      • 2014-01-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多