【问题标题】:Django Rest Framework - get related FK object for use in template; POST not working now?Django Rest Framework - 获取相关的 FK 对象以在模板中使用; POST现在不起作用?
【发布时间】:2021-09-07 00:13:27
【问题描述】:

我已经建立了一个表单并使用 Vue 前端和 DRF 后端。它是一种用于添加(创建)新模型的表单 - 并有一个相关模型的下拉列表,这些模型是正在创建的模型的 FK。

我需要访问所选外键项的属性。

我的序列化器如下所示:

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

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


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()

    class Meta:
        model = Evidence
        fields = "__all__"

表单是创建一个新的“证据”项,“子域”是表单上的一个下拉列表,包含所有相关的子域。

模型如下所示:

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)

class Evidence(CreateUpdateMixin, CreateUpdateUserMixin, SoftDeletionModel):
    subdomain = models.ForeignKey(Subdomain, on_delete=models.PROTECT)
    evaluation = models.ForeignKey(
        Evaluation, related_name="evidences", on_delete=models.PROTECT
    )
    published = models.BooleanField(default=False)
    comments = models.CharField(max_length=500)

在我的表单中,当用户从下拉列表中选择每个subdomain 时,我只想包含short_description - 我可能还想使用long_description

这是我呈现下拉列表的表单中的位:

                        <div class="form-group col-sm-4">
                            <label class="" for="subdomain">Subdomain</label>
                            <select name="subdomain" id="subdomain" class="form-control" v-model="element.subdomain">
                                <option v-for="choice in subdomains" :value="choice.id" >{{ choice.character_code }}</option>
                            </select>
                        </div>
                        <div class="small" v-if="element.subdomain">
                            <!-- THIS IS WHERE I WOULD LIKE TO DISPLAY THE SHORT DESCRIPTION FOR THE CHOICE IN THE DROPDOWN -->
                            {{ choice.short_description }}
                        </div>

当我 POST 时,表单数据如下所示:

evaluation: 2037
subdomain: 448
comments: Test comments to add to the subdomain
published: true
csrfmiddlewaretoken: 382796ryfuasiodfgyhakljyht37yaisdfaslk3r

我尝试过的东西 - 其中一些用于显示目的,但似乎破坏了表单/POST:

  • depth=1 添加到EvidenceSerializer 的元中,这有效但使表单不再正确提交。我认为这是因为它想要整个子域而不仅仅是 ID?我无法让它工作 - 子域总是抛出错误。

  • 将以下内容添加到我的EvidenceSerializer 中,这似乎再次破坏了 POST 操作,这将导致子域下拉列表抛出错误。

subdomain = SubdomainSerializer(read_only=True)

使用下拉列表上方的这两种方法都无法识别被选中的subdomain_id,最终都会在幕后引发此错误:

Cannot insert the value NULL into column 'subdomain_id', table 'local_app.dbo.myapp_evidence'; column does not allow nulls. INSERT fails.

任何关于如何进行的建议都会很棒。

TLDR;需要能够使用 DRF 访问 FK 关系上的属性以获取下拉列表,并能够在表单中提交该项目。

【问题讨论】:

标签: javascript django vue.js django-rest-framework


【解决方案1】:

感谢@bdbd 为我指明了正确的方向。

对于任何好奇的人,我使用这些链接解决了它 - 结果我需要稍微更改我的序列化程序:

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()
    # add the 'subdomain' as read only - but with all the attributes
    subdomain = SubdomainSerializer(read_only=True)
    # add the 'subdomain_id' as a PrimaryKeyRelatedField with the source being the subdomain
    subdomain_id = serializers.PrimaryKeyRelatedField(
        queryset=Subdomain.objects.all(), source="subdomain"
    )

    class Meta:
        model = Evidence
        fields = "__all__"

然后我稍微更新了 HTML:

                <div class="form-group col-sm-4">
                    <label class="" for="subdomain_id">Subdomain</label>
                    <select name="subdomain_id" id="subdomain" class="form-control" v-model="element.subdomain">
                        <option v-for="choice in subdomains" :value="choice" >{{ choice.character_code }}</option>
                    </select>
                </div>
                <div class="small" v-if="element.subdomain_id">
                    {{ element.subdomain.short_description }}
                </div>

然后在 ajax 调用中,我只需将 subdomain_id 分配给 subdomain.id

        data: {
            evaluation : evaluationId,
            subdomain_id : vm.element.subdomain.id,
            comments : vm.element.comments,
            published: vm.element.published,
            csrfmiddlewaretoken: vm.sharedStore.state.csrftoken,
        },

【讨论】:

    猜你喜欢
    • 2022-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-27
    • 2019-05-18
    • 2019-02-26
    • 1970-01-01
    • 2014-06-23
    相关资源
    最近更新 更多