【问题标题】:DRF Create new object and link to (but not create) it's related items (nested serializer)?DRF 创建新对象并链接到(但不创建)它的相关项(嵌套序列化程序)?
【发布时间】:2021-11-12 18:37:22
【问题描述】:

我正在尝试将多个项目(子域)链接到正在创建的项目(证据)。

我的表单提交正常 - 但我正在尝试找出解决此问题的“最佳”方法。

According to the docs 我必须重写 create 方法 - 但他们的示例显示他们“创建”相关对象。

我不想那样做。我只想将这些相关项目添加到我正在创建的证据中(以创建关系)

这是我的序列化程序:

class SubdomainSerializer(serializers.ModelSerializer):
    class Meta:
        model = Subdomain
        fields = [
            "id",
            "domain",
            "short_description",
            "long_description",
            "character_code",
        ]


class EvidenceSerializer(serializers.ModelSerializer):
    """
    """

    created_by = serializers.HiddenField(
        default=serializers.CurrentUserDefault()
    )
    updated_by = serializers.HiddenField(
        default=serializers.CurrentUserDefault()
    )
    absolute_url = serializers.SerializerMethodField()
    created_by_name = serializers.SerializerMethodField()
    updated_by_name = serializers.SerializerMethodField()
    subdomains = SubdomainSerializer(many=True)

    class Meta:
        model = Evidence
        fields = "__all__"
        extra_kwargs = {
            "subdomains": {
                "error_messages": {
                    "null": "This field is required.",
                    "blank": "This field is required.",
                }
            },
        }

    def get_absolute_url(self, obj):
        return obj.get_absolute_url()

    def get_created_by_name(self, obj):
        return obj.created_by.full_name

    def get_updated_by_name(self, obj):
        return obj.updated_by.full_name

    def create(self, validated_data):
        subdomains_data = validated_data.pop("subdomains")
        evidence = Evidence.objects.create(**validated_data)
        for subdomain in subdomains_data:
            # This is where I want to add the subdomains to the evidence - not create ones - how best to accomplish that?
            Subdomain.objects.create(**subdomain)
        return evidence

    def update(self, instance, validated_data):
        # Add the requestor as the updater in a PATCH request
        request = self.context["request"]
        validated_data["updated_by"] = request.user
        return super().update(instance, validated_data)

有没有更好的方法来设置我的序列化程序?我应该做一些不同的事情来使这更容易实现吗?

编辑添加我的模型:

class Subdomain(CreateUpdateMixin):
    """

    """

    domain = models.ForeignKey(Domain, on_delete=models.PROTECT)
    short_description = models.CharField(max_length=100)
    long_description = models.CharField(max_length=250)
    character_code = models.CharField(max_length=5)
    proficiency_levels = models.ManyToManyField(SubdomainProficiencyLevel)

    class Meta:
        verbose_name = "Subdomain"
        verbose_name_plural = "Subdomains"

    def __str__(self):
        """Unicode representation of Subdomain."""
        return f"{self.character_code}"

class Evidence(CreateUpdateMixin, CreateUpdateUserMixin, SoftDeletionModel):
    """

    """

    subdomains = models.ManyToManyField(Subdomain, related_name="evidences")
    evaluation = models.ForeignKey(
        Evaluation, related_name="evidences", on_delete=models.PROTECT
    )
    published = models.BooleanField(default=False)
    comments = models.CharField(max_length=500)

    class Meta:
        ordering = ["-created_at"]
        verbose_name = "Evidence"
        verbose_name_plural = "Evidence"

    def __str__(self):
        """Unicode representation of Evidence."""
        return f"{self.subdomain} : {self.comments}"

    def get_absolute_url(self):
        """Return absolute url for Evidence."""
        return reverse("evidence-detail", args=[str(self.id)])

【问题讨论】:

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


    【解决方案1】:

    在这里您想将subdomain ForeignKey 设置为新创建的evidence。 为此,您只需检索子域并像这样更新他的证据字段:

    def create(self, validated_data):
        subdomains_data = validated_data.pop("subdomains")
        evidence = Evidence.objects.create(**validated_data)
        for subdomain in subdomains_data:
            # Retrieve the subdomain and update the evidence attribute
            sub_id = subdomain['id']
            sub = Subdomain.objects.get(id=sub_id)
            sub.evidence = evidence
            sub.save()
        return evidence
    

    注意:我使用默认的反向 ForeignKey 关系:sub.evidence

    【讨论】:

    • 所以subdomain['id'],虽然存在于 POST 数据中,但永远不会进入 create 方法 - 这显然是设计使然。您必须包含 extra_kwargs = {"id": {"read_only": False}} 才能从 POST 数据中获取 ID,但这对我来说似乎非常糟糕。
    猜你喜欢
    • 2020-10-03
    • 1970-01-01
    • 2016-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-31
    相关资源
    最近更新 更多