我有一个包含 5 对位置和描述的表单。我有三组验证需要完成

  • 你至少需要输入一个位置
  • 第一个位置,你必须有描述
  • 用于每对剩余的位置和描述

  • 阅读 Django 文档后,我想出了以下代码来执行这些自定义验证
    def clean(self):
        cleaned_data = self.cleaned_data
        location1 = cleaned_data.get('location1')
        location2 = cleaned_data.get('location2')
        location3 = cleaned_data.get('location3')
        location4 = cleaned_data.get('location4')
        location5 = cleaned_data.get('location5')
        description1 = cleaned_data.get('description1')
        description2 = cleaned_data.get('description2')
        description3 = cleaned_data.get('description3')
        description4 = cleaned_data.get('description4')
        description5 = cleaned_data.get('description5')
        invalid_pairs_msg = u"You must specify a location and description"
    
        # We need to make sure that we have pairs of locations and descriptions
        if not location1:
            self._errors['location1'] = ErrorList([u"At least one location is required"])
    
        if location1 and not description1:
            self._errors['description1'] = ErrorList([u"Description for this location required"])
    
        if (description2 and not location2) or (location2 and not description2):
            self._errors['description2'] = ErrorList([invalid_pairs_msg])
    
        if (description3 and not location3) or (location3 and not description3):
            self._errors['description3'] = ErrorList([invalid_pairs_msg])
    
        if (description4 and not location4) or (location4 and not description4):
            self._errors['description4'] = ErrorList([invalid_pairs_msg])
    
        if (description5 and not location5) or (location5 and not description5):
            self._errors['description5'] = ErrorList([invalid_pairs_msg])
    
        return cleaned_data
    

    现在,它可以工作,但看起来真的很难看。我正在寻找一种更“Pythonic”和“Djangoist”(?)的方式来做到这一点。提前致谢。

    最佳答案

    您可以做的第一件事是简化对那些您想查看是否仅填充两个字段之一的情况的测试。您可以通过以下方式实现逻辑 xor:

    if bool(description2) != bool(location2):
    

    或者这样:
    if bool(description2) ^ bool(location2):
    

    我还认为,如果您分别为每个字段实现一个干净的方法,这会更清楚,如 the docs 中所述。这确保错误将显示在正确的字段上,并让您只引发 forms.ValidationError 而不是直接访问 _errors 对象。

    例如:
    def _require_together(self, field1, field2):
        a = self.cleaned_data.get(field1)
        b = self.cleaned_data.get(field2)
        if bool(a) ^ bool(b):
            raise forms.ValidationError(u'You must specify a location and description')
        return a
    
    # use clean_description1 rather than clean_location1 since
    # we want the error to be on description1
    def clean_description1(self):
        return _require_together('description1', 'location1')
    
    def clean_description2(self):
        return _require_together('description2', 'location2')
    
    def clean_description3(self):
        return _require_together('description3', 'location3')
    
    def clean_description4(self):
        return _require_together('description4', 'location4')
    
    def clean_description5(self):
        return _require_together('description5', 'location5')
    

    为了获得需要 location1 的行为,只需对该字段使用 required=True 即可自动处理。

    关于Django 自定义表单验证最佳实践?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/2173184/

    10-12 12:28
    查看更多