【问题标题】:DRF Update Insert in ManytoMany, ForeignKey Relationship Models多对多、外键关系模型中的 DRF 更新插入
【发布时间】:2022-02-02 03:15:51
【问题描述】:

我有六个模型,它们如下:

class Certificate(DateTimeLog):
    name = models.TextField(max_length=255)


class Vacancy(DateTimeLog):
    name = models.CharField(max_length=255)
    parent_position = models.ForeignKey("self", on_delete=models.CASCADE, null=True, blank=True,
                                        related_name='sub_positions')


class Region(DateTimeLog):
    name = models.CharField(max_length=255)


class MaritalStatus(DateTimeLog):
    name = models.CharField(max_length=255)


class Candidate(DateTimeLog):
    pin = models.CharField(max_length=16, unique=True)
    first_name = models.CharField(max_length=64, blank=True, null=True)
    last_name = models.CharField(max_length=64, blank=True, null=True)
    marital_status = models.ForeignKey(MaritalStatus, on_delete=models.SET_NULL, null=True, blank=True)
    certificate = models.ManyToManyField(Certificate, blank=True)


class Candidacy(DateTimeLog):
    candidate = models.ForeignKey(Candidate, on_delete=models.CASCADE)
    vacancy = models.ForeignKey(Vacancy, on_delete=models.CASCADE)
    work_region = models.ForeignKey(Region, on_delete=models.SET_NULL, null=True, blank=True)

现在我要处理,如果存在candidate记录(我正在用pin检查它),然后检查并更新Candidate相关数据。如果候选人不存在,请创建它。 创建或更新候选人后,将其分配给候选人。 我的序列化器如下所示:

class CandidateSerializer(serializers.ModelSerializer):
    marital_status = MaritalStatusSerializer(required=False)
    certificate = CertificateSerializer(many=True, required=False)

    def create(self, validated_data):
        marital_status_data = validated_data.pop("marital_status")
        certificate_data = validated_data.pop("certificate")
        candidate = Candidate.objects.create(**validated_data)

        ms_o = MaritalStatus.objects.get(name=marital_status_data["name"])
        candidate.marital_status = ms_o

        for certificate in certificate_data:
            certificate_o = Certificate.objects.create(**certificate)
            candidate.certificate.add(certificate_o)

        candidate.save()
        return candidate

    class Meta:
        model = Candidate
        fields = '__all__'
        depth = 1


class CandidacySerializer(serializers.ModelSerializer):
    candidate = CandidateSerializer()
    vacancy = VacancySerializer()
    work_region = RegionSerializer()

    def create(self, validated_data):
        candidate_s = CandidateSerializer()
        candidate_data = validated_data.pop('candidate')

        vacancy_data = validated_data.pop('vacancy')
        work_region_data = validated_data.pop('work_region')

        vac_o = Vacancy.objects.get(name=vacancy_data['name'])
        wr_o = Region.objects.get(name=work_region_data['name'])
        candidate_o = candidate_s.create(validated_data=candidate_data)
        validated_data.update({
            'candidate': candidate_o,
            'vacancy': vac_o,
            'work_region': wr_o
        })
        candidacy = Candidacy.objects.create(**validated_data)
        return candidacy

    class Meta:
        model = Candidacy
        fields = '__all__'
        depth = 1

目前,我可以使用发布请求创建它。我需要明确检查还是可以在序列化程序中实现?

【问题讨论】:

  • 你的意思是如果记录已经在数据库中,就像一个唯一的验证器一样,还是......?
  • 在你的CandidateSerializer.create 你可以这样做:candidate = Candidate.objects.update_or_create(pin=validated_data.get('pin'), defaults=validated_data)
  • @BrianDestura 当我收到 400(错误请求)后,它说具有此 pin 的候选人已经存在
  • 你能说明你使用了什么代码吗?
  • 抱歉没看懂,能否详细说明一下,“代码”到底是什么意思?

标签: python django serialization django-rest-framework


【解决方案1】:

首先,您可以像这样在CandidateSerializer 中使用update_or_create

class CandidateSerializer(serializers.ModelSerializer):
    marital_status = MaritalStatusSerializer(required=False)
    certificate = CertificateSerializer(many=True, required=False)

    def create(self, validated_data):
        marital_status_data = validated_data.pop("marital_status")
        certificate_data = validated_data.pop("certificate")
        candidate, created = Candidate.objects.update_or_create(
            pin=validated_data['pin'],
            **validated_data
        )

        ms_o = MaritalStatus.objects.get(name=marital_status_data["name"])
        candidate.marital_status = ms_o

        for certificate in certificate_data:
            certificate_o = Certificate.objects.create(**certificate)
            candidate.certificate.add(certificate_o)

        candidate.save()
        return candidate

    class Meta:
        model = Candidate
        fields = '__all__'
        depth = 1

其次,你不应该直接调用方法create()。您必须改用save()。你必须更换:

candidate_s = CandidateSerializer()
candidate_o = candidate_s.create(validated_data=candidate_data)

通过

candidate_s = CandidateSerializer(data=candidate_data)
candidate_o = candidate_s.save()

您可以阅读有关保存实例的更多信息here

【讨论】:

  • 非常感谢您的回答。我会测试它。
【解决方案2】:

所以你有一个更直接的选择。有一个名为 get 或 create 的函数,它将检查对象是否存在并返回它,否则将其返回。 similar question can be found here Another use of the same question 顺便说一句,如果这个 pin 是敏感的,我建议加密它。

【讨论】:

  • 我试过了,但是没用!同样的例外。
  • 你得到的错误是什么版本的Django rest框架?
【解决方案3】:

因为你已经用

制作了别针
pin = models.CharField(max_length=16, unique=True)

不可能有两个相似的别针。现在要根据 pin 检查候选人,您必须在 create 方法中手动执行类似的操作。

if Candidate.objects.filter(pin = revievedPinData):
    here candidate is already present so update the information information
    and again check if Canditate is in Candidacy or not
    first get the candidate object
    c = Candidate.objects.get(pin = revievedPinData)
    then
    if Candidacy.objects.filter(candidate = c):
       if true candidate is already assigned and the updated value of candidate will reflect here
    else: create the Candidacy with the current candidate and other values
else:
    if candidate is not there (from the given pin)
    create a new candidate
    aa = candidate.objects.create()
    create a new Candidacy with candidate aa
    Candidacy.objects.create(candidate=aa, **otherdata)
     

  

【讨论】:

  • 创建方法没有出错。没用!我从验证中得到了一个例外。
  • 验证器有哪些例外?
  • 您是否在候选人创建、候选人更新或候选人创建中遇到错误?
  • 候选人创建
  • 错误是什么?
猜你喜欢
  • 2012-07-22
  • 1970-01-01
  • 1970-01-01
  • 2013-11-20
  • 2021-11-30
  • 2012-03-23
  • 1970-01-01
  • 2020-11-11
  • 2016-12-30
相关资源
最近更新 更多