首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用DRF序列化django中的一些嵌套关系模型?

如何使用DRF序列化django中的一些嵌套关系模型?
EN

Stack Overflow用户
提问于 2020-12-19 09:14:07
回答 2查看 221关注 0票数 1

我有一些不同关系的Django模型-- Many-to-manyForeignkey。通过这种方式,我希望使用djnago-rest来序列化它们。

以下是模型:

代码语言:javascript
复制
class CommonFieldsAbstract(models.Model):
    name = models.CharField(max_length=30, unique=True)

class ServerModel(CommonFieldsAbstract):
    server_ip = models.GenericIPAddressField(default='172.17.0.1')
    server_port = models.IntegerField(default='9001')

class SNMPLineModel(CommonFieldsAbstract):
    ip_address = models.GenericIPAddressField()
    port = models.IntegerField(default=161)

class SNMPModel(CommonFieldsAbstract):  # target
    line = models.ForeignKey(SNMPLineModel, on_delete=CASCADE)
    servers = models.ManyToManyField(ServerModel)

class MetaDataModel(models.Model):
    key = models.CharField(max_length=20)
    value = models.CharField(max_length=20)
    snmp_device = models.ForeignKey(SNMPModel, on_delete=CASCADE)

在此之前,我曾使用以下方法手动创建JSON:

代码语言:javascript
复制
def meta_data_json(meta_data):
    meta_data_list = []
    for meta in meta_data:
        meta_data_list.append({
            meta.key: meta.value
        })
    return meta_data_list

def server_json(servers):
    return [{'ip': server.server_ip,
             'port': server.server_port}
            for server in servers]

def create_json():
    snmp = SNMPModel.objects.filter(name__contains='a-name')
    return {
        'name': snmp.name,
        'address': snmp.line.ip_address,
        'port': snmp.line.port,
        'servers': server_json(snmp.servers.all()),
        'meta_data': meta_data_json(MetaDataModel.objects.filter(
                snmp_device=snmp.pk
            )
        ),
        'device_pk': snmp.pk
    }

我的问题是:

现在,我如何通过django-rest-framework创建这样一个这样的json呢?

我对多到多领域没有任何问题。事实上,我的问题是foreignkey

以下是我迄今所做的工作:

代码语言:javascript
复制
# serializers.py

from rest_framework import serializers

class MetaDataSerializer(serializers.ModelSerializer):
    class Meta:
        fields = [
            'id',
            'key',
            'value',
            ]
        model = MetaDataModel

class ServerSerializer(serializers.ModelSerializer):
    class Meta:
        fields = [
            'id',
            'server_ip',
            'server_port',
            ]
        model = ServerModel

class LineSerializer(serializers.ModelSerializer):
    port = serializers.RelatedField(many=True)

    class Meta:
        fields = '__all__'
        model = SNMPLineModel

class SNMPSerializer(serializers.ModelSerializer):
    servers = ServerSerializer(many=True, read_only=True)  # It is ok
    meta_data = MetaDataSerializer(many=True, read_only=True)  # It's not ok
    line = LineSerializer(many=True, read_only=True)  # It's not ok
    address = serializers.CharField(source=SNMPLineModel.ip_address)  # It's not ok
    port = serializers.CharField(source=SNMPLineModel.port)  # It's not ok

    class Meta:
        fields = [
            'id',
            'servers',
            'name',
            'address',
            'port',
            'line',
            'meta_data'
            ]
        model = SNMPModel
代码语言:javascript
复制
# views.py

from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse, JsonResponse

@csrf_exempt
def snippet_detail(request, name):
    try:
        snmp_conf = SNMPModel.objects.filter(name__contains=name)
    except SNMPModel.DoesNotExist:
        return HttpResponse(status=404)

    if request.method == 'GET':
        serializer = SNMPSerializer(snmp_conf, many=True)
        return JsonResponse(serializer.data, status=200, safe=False)
代码语言:javascript
复制
# urls.py

from django.urls import path

urlpatterns = [
    path('snippets/<name>/', views.snippet_detail)
]

任何帮助都将不胜感激。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-12-19 09:56:03

serializers.SerializerMethodField()是添加这样的关系的一种有用方法。get_meta_data()有点神奇,通过计算字段名来调用该方法。

地址和端口似乎是一个简单的关系,line.FOO应该可以工作。

代码语言:javascript
复制
class SNMPSerializer(serializers.ModelSerializer):
    servers = ServerSerializer(many=True, read_only=True)  # It is ok
    meta_data = serializers.SerializerMethodField()
    line = serializers.SerializerMethodField()
    address = serializers.CharField(source="line.ip_address", read_only=True)
    port = serializers.CharField(source="line.port" , read_only=True)

    class Meta:
        fields = ['id', 'servers', 'name', 'address', 'port', 'line', 'meta_data']
        model = SNMPModel

    def get_meta_data(self, instance):
        metadatamodels = MetaDataModel.objects.filter(snmp_device=instance)
        serializer = MetaDataSerializer(instance=metadatamodels, many=True, read_only=True)

        return serializer.data

    def get_line(self, instance):
        serializer = LineSerializer(instance.line, read_only=True)

        return serializer.data
票数 1
EN

Stack Overflow用户

发布于 2022-05-19 22:15:02

为了解决上述问题,我做了以下解决方案:

对于正向密钥,您不需要many=True

  • For,需要使用related-model_set的反向Foreignkey,而您还没有定义related_name.

  • For --一个额外的字段--您只需要精确的查询集.

因此,我在没有使用.SerializerMethodField()的情况下达到了下面的代码片段,就像Michael在他的答案中使用的那样:

代码语言:javascript
复制
class SNMPSerializer(serializers.ModelSerializer):
    servers = ServerSerializer(many=True)
    meta_data = MetaDataSerializer(many=True, source="metadatamodel_set")
    line = LineSerializer()
    address = serializers.CharField(source="line.ip_address")
    port = serializers.CharField(source="line.port")

    class Meta:
        fields = (
            "id",
            "servers",
            "name",
            "address",
            "port",
            "line",
            "meta_data",
        )
        model = SNMPModel
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65368285

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档