Django Rest Framework中的补丁方法验证

11

以下是我的模型定义

class ProfessionalQualification(Log_Active_Owned_Model_Mixin):

    PROF_TEACHER    = 1
    PROF_ENGINEER   = 2
    PROF_DOCTOR     = 4
    PROF_PROFESSOR  = 8
    PROF_MANAGER    = 16
    PROF_CLERK      = 32
    PROF_SALESMAN   = 64
    PROF_BUSINESSMAN= 128
    PROF_OTHER      = 129

    VALID_PROFESSIONS = (
        (PROF_TEACHER,      "Teacher"   ),
        (PROF_ENGINEER,     "Engineer"  ),
        (PROF_DOCTOR,       "Doctor"    ),
        (PROF_PROFESSOR,    "Professor" ),
        (PROF_MANAGER,      "Manager"   ),
        (PROF_CLERK,        "Clerk"     ),
        (PROF_SALESMAN,     "Salesman"  ),
        (PROF_BUSINESSMAN,  "Businessman"),
        (PROF_OTHER,        "Other"     )
    )

    profession_type         = IntegerField(choices=VALID_PROFESSIONS, null=False, blank=False)
    profession_type_name    = CharField(max_length=60, null=True, blank=True)
    institue                = CharField(max_length=160, null=False, blank=False)
    address                 = ForeignKey(to=City, null=False)
    year_start              = CurrentYearField(null=False, blank=False)
    in_progress             = BooleanField(null=False, blank=False)
    year_end                = CurrentYearField(null=True, blank=True)

以下是我的序列化程序。
class ProfQualSerializer(OwedModelSerializerMixin, ModelSerializer):

    #address = ConcreteAddressSerializer()
    class Meta:
        model   = UserProfessionalQual
        fields  = (
                    "profession_type", "profession_type_name", \
                    "institue", "address", "year_start",
                    "in_progress", "year_end"
                 )

    def validate(self, dict_input):
        errors = defaultdict(list)
        profession_type = dict_input["profession_type"]

        if profession_type == UserProfessionalQual.PROF_OTHER:
            try:
                RestAPIAssert(dict_input.get("profession_type_name", None),
                                "Profession-type-name must be passed, for other type of profession",
                                log_msg="Profession-type-name not passed", exception=ValidationError)

            except ValidationError as e:
                errors["profession_type"].append(str(e))

        year_start  = dict_input["year_start"]
        year_end    = dict_input.get("year_end", None)
        in_progress = dict_input.get("in_progress", None)

        request     = self._context["request"]
        user_dob    = request.user.dob
        age         = request.user.age

        current_time = datetime.datetime.now()
        if not user_dob:
            user_dob = relativedelta(current_time, years=age)

        if year_start < user_dob.year:
            errors["year_start"].append("Year-start can't be before user's DOB")

        elif year_start > year_end:
            errors["year_start"].append("Year-end can't be before year-start")

        elif year_end > current_time.year:
            dict_input["in_progress"] = True

        else:
            #   if user have not passed in_progress flag, then
            #   set it false.
            if dict_input.get("in_progress", None) == None:
                dict_input["in_progress"] = False

        if errors:
            raise ValidationError(errors)

        return dict_input

我在序列化器中定义了validate()方法,该方法在序列化器级别执行验证(而不是在字段级别)。现在的问题是,在只涉及某些字段的 http方法中,对于那些不属于请求主体的字段,它会给出keyerror。
最好的方法是如何编写上述validate()方法,以确保它在POST、PUT和PATCH方法中都能正常工作?
提前感谢您。

处理具有不同键数的字典时,我总是使用.get()调用。您在代码中混合使用了该方法和直接键访问。如果不知道哪个键引发了错误,我能给出的最好建议是将所有字典键访问更改为使用.get(),然后将其包装在条件语句中以正确处理它们是否为None。 - gallen
2
@Neelik,问题不在于访问字典。我肯定可以使用get()。但是,我的问题是关于如何处理patch(),create()和put()方法的验证。在create()和put()中,所有键都可用,但在patch()中,可能会缺少某些键。我可以编写一个天真的解决方案。但我想知道标准的处理方式。 - Mangu Singh Rajpurohit
2个回答

10

在验证方法中使用self.partial来判断是否为部分更新。

def validate(self, data):
    if self.partial:
        print("Partial update")
    return data

在验证函数中,我能否获取旧实例的ID? - Akash senta
@Akashsenta,由于这是一个更新,您应该知道旧实例的ID。您可以从视图中传递它到上下文中,并在此处访问它。 - Dineshs91
这个属性的存在应该在文档的部分更新章节中更加清晰地说明。 - af3ld

0
你可以定义 validate_< field_name > 方法来验证特定字段,这样如果该字段包含在请求数据中,则会进行验证;否则不会进行验证。
例如:
def validate_year_start(self, value):
    year_start  = value
    request     = self._context["request"]
    user_dob    = request.user.dob
    age         = request.user.age

    current_time = datetime.datetime.now()
    if not user_dob:
        user_dob = relativedelta(current_time, years=age)

    if year_start < user_dob.year:
        raise serializers.ValidationError({"year_start":"Year-start can't be before user's DOB"})
    return value

2
如果我需要进行验证,其中需要考虑两个字段,那么你提出的解决方案将无法使用。 - Mangu Singh Rajpurohit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接