如何在 Django REST 中通过多对多发布模型
Posted
技术标签:
【中文标题】如何在 Django REST 中通过多对多发布模型【英文标题】:How to POST Model with Many to Many through in Django REST 【发布时间】:2018-09-13 00:10:30 【问题描述】:我有一个具有多对多连接的模型。我想让这个模型在 Django REST 中可用。默认情况下,这样的模型是只读的,但我也想写。此外,将直通连接的信息作为嵌套模型集成到 GET 中会很棒。
...
class KeyDateCase(models.Model):
...
diagnoses_all_icd_10 = models.ManyToManyField(
'ICD10', through='CaseICD10Connection')
...
class CaseICD10Connection(models.Model):
case = models.ForeignKey('KeyDateCase', on_delete=models.CASCADE)
icd_10 = models.ForeignKey('ICD10', on_delete=models.CASCADE)
is_primary = models.BooleanField(default = False)
certainty = models.CharField(
max_length=1,
choices=CERTAINTY_CHOICES,
default='G',
)
class ICD10(models.Model):
primary_key_number = models.CharField(max_length=10, primary_key=True)
star_key_number = models.CharField(max_length=10, blank=True, null=True)
additional_key_number = models.CharField(
max_length=10, blank=True, null=True)
preferred_short_description = models.CharField(max_length=128, )
...
class KeyDateCaseViewSet(viewsets.ModelViewSet):
???
class KeyDateCaseSerializer(serializers.ModelSerializer):
???
我怎样才能做到这一点?我的视图和序列化程序应该是什么样的?
【问题讨论】:
你想如何显示diagnoses_all_icd_10
,是ids列表还是你想显示整个对象?
diagnoses_all_icd_10 = serializers.PrimaryKeyRelatedField( many=True, queryset= ICD10.objects.all(), write_only=True, required=False)
你可以定义类似的东西,你必须重写序列化程序创建方法并从验证数据中弹出 id,例如 icd_10 = valid_data.pop('diagnoses_all_icd_10')然后将其添加到 icd_10 中 icd 的模型实例```:instance.diagnoses_all_icd_10.add(ICD10.objects.get(pk=icd_10))```
我建议在使用manytomanyfield
时使用views.py
中的类,您可以查看inlineformset_factory
中的forms.py
以及jquery-formset
中的前端。
【参考方案1】:
关于创建或更新嵌套对象,the documentation actually has a great example。如果可以的话,我会给你一个更好的。如果示例中有任何令人困惑的地方,很乐意在这里解释。
如果您采用这种方法,您的GET
请求将自动为您展开嵌套对象。
【讨论】:
【参考方案2】:通常我通过POST
到through
表的间接方式解决方法并实现嵌套创建()。如果我的回答不准确,请提供更多信息。
models.py
from django.db import models
class ICD10(models.Model):
primary_key_number = models.CharField(max_length=10, primary_key=True)
star_key_number = models.CharField(max_length=10, blank=True, null=True)
additional_key_number = models.CharField(max_length=10, blank=True, null=True)
preferred_short_description = models.CharField(max_length=128, )
def __str__(self):
return f'self.primary_key_number self.star_key_number'
class CaseICD10Connection(models.Model):
case = models.ForeignKey('KeyDateCase', related_name='connections', related_query_name='key_date_cases', on_delete=models.CASCADE)
icd_10 = models.ForeignKey('ICD10', related_name='connections', related_query_name='icd_10s', on_delete=models.CASCADE)
is_primary = models.BooleanField(default=False)
certainty = models.CharField(max_length=1, default='G', )
class KeyDateCase(models.Model):
name = models.CharField(max_length=20)
diagnose_all_icd_10 = models.ManyToManyField(ICD10, related_name='icd10s', related_query_name='icd10s',
through=CaseICD10Connection)
serializers.py
from rest_framework import serializers
from keydatecases.models import KeyDateCase, ICD10, CaseICD10Connection
class KeyDateCaseSerializer(serializers.ModelSerializer):
class Meta:
model = KeyDateCase
fields = [
'id',
'name',
'diagnose_all_icd_10',
]
read_only_fields = ['id', 'diagnose_all_icd_10']
class ICD10Serializer(serializers.ModelSerializer):
class Meta:
model = ICD10
fields = [
'primary_key_number',
'star_key_number',
'additional_key_number',
'preferred_short_description',
]
class CaseICD10ConnectionSerializer(serializers.ModelSerializer):
case = KeyDateCaseSerializer()
icd_10 = ICD10Serializer()
class Meta:
model = CaseICD10Connection
fields = [
'case',
'icd_10',
'is_primary',
'certainty',
]
def create(self, validated_data) -> CaseICD10Connection:
# import ipdb;
# ipdb.set_trace()
# create key_date_case
key_date_case = KeyDateCase.objects.create(**validated_data.get('case'))
# create icd10
icd10 = ICD10.objects.create(**validated_data.get('icd_10'))
# create connection
conn = CaseICD10Connection.objects.create(
case=key_date_case, icd_10=icd10, is_primary=validated_data.get('is_primary'),
certainty=validated_data.get('certainty')
)
return conn
viewsets.py
from rest_framework import viewsets
from keydatecases.api.serializers import CaseICD10ConnectionSerializer
from keydatecases.models import CaseICD10Connection
class CaseICD10ConnectionViewSet(viewsets.ModelViewSet):
permission_classes = ()
queryset = CaseICD10Connection.objects.all()
serializer_class = CaseICD10ConnectionSerializer
我的存储库: 我与许多问题共享我的存储库。请不要介意。https://github.com/elcolie/tryDj2
【讨论】:
以上是关于如何在 Django REST 中通过多对多发布模型的主要内容,如果未能解决你的问题,请参考以下文章
在 Django Rest 框架 URL 中通过唯一 ID 但不是 PK 获取详细信息
在 Laravel 中通过多对多关系模型对 eloquent 模型进行排序
如何通过多对一关系中同一相关对象的两个属性在 django 中进行过滤?