【问题标题】:Django ManyToMany field as json formatDjango ManyToMany 字段为 json 格式
【发布时间】:2018-05-05 07:25:07
【问题描述】:

我正在尝试以 json 格式获取数据。我有一个ManyToMany 字段,它只返回id。但我也需要那些内容。这是我的models.py

class Pricing(models.Model):
    name = models.CharField(max_length = 100)
    price = models.CharField(max_length = 100)

    def __str__(self):
        return self.name+' and '+self.price


class Service(models.Model):
    name = models.CharField(max_length=100)
    price = models.ManyToManyField(Pricing, blank=True)

    def __str__(self):
        return self.name 

还有返回 json 格式数据的 views.py

def all_service_json(request, name):
    data = serializers.serialize("json", Service.objects.filter(name__icontains=name))
    return HttpResponse(data)

现在得到如下输出

[
    {
        "model": "myapp.service", 
        "pk": 2, 
        "fields": 
        {
            "name": "Service name", 
            "price": [1, 2]
        }
    }
]

但是想要像下面这样

[
    {
        "model": "myapp.service", 
        "pk": 2, 
        "fields": 
        {
            "name": "Service name", 
            "price": 
            {
                1: "Price 1", 
                2: "Price 2"
            }
        }
    }
]

【问题讨论】:

    标签: python json django


    【解决方案1】:

    在 Django Rest Framework 中创建 ModelSerializer 对象将允许您显示嵌套对象数据:

    http://www.django-rest-framework.org/api-guide/serializers/#dealing-with-nested-objects

    # myapp/serializers.py
    ...
    from rest_framework import serializers
    
    class PricingSerializer(serializers.ModelSerializer):
    
        class Meta:
            fields = '__all__'
            model = Pricing
    
    class ServiceSerializer(serializers.ModelSerializer):
        price = PricingSerializer(read_only=True, many=True)
    
        class Meta:
            fields = '__all__'
            model = Service
    
    # myapp/views.py
    def all_service_json(request, name):
        services = Service.objects.filter(name__icontains=name)
        data = ServiceSerializer(services, many=True).data
        return HttpResponse(data)
    

    【讨论】:

    • 如果价格和服务相互引用怎么办?
    【解决方案2】:

    正如@robert 提到的,使用嵌套序列化程序将解决您的问题。

    但请注意,默认情况下嵌套的序列化程序是只读的。所以如果你 想要支持对嵌套序列化器字段的写入操作,您将 需要添加 create() 和/或 update() 方法才能显式 指定应如何保存子关系。

    可写服务序列化器

    class ServiceSerializer(serializers.ModelSerializer):
        price = PricingSerializer(many=True)
    
        class Meta:
            fields = '__all__'
            model = Service
    
        # sample create 
        def create(self, validated_data):
            prices_data = validated_data.pop('price')
            service = Service.objects.create(**validated_data)
            for price_data in prices_data:
                Price.objects.create(service=service, **price_data)
            return service
    
         # add update here
    

    myapp/views.py

    def all_service_json(request, name):
        services = Service.objects.filter(name__icontains=name)
        serializer = ServiceSerializer(services)
        return HttpResponse(serializer.data)
    

    【讨论】:

    • 感谢告知
    【解决方案3】:

    我刚刚从过去 8 小时开始学习 Django,我陷入了这种情况,即多对多关系返回 id 而不是子数据。我写了一些自定义代码。对我来说它解决了我的问题,希望这对某人有所帮助。

    from django.core.serializers import serialize
    import json 
    
    def modelToDict(model):
        jsn = serialize("json", model) # convert to json
        mydict = json.loads(jsn) # again convert to dictionary
        return mydict
    
    def all_service_json(request, name):
        data = Service.objects.filter(name__icontains=name)
        dictdata = modelToDict(data)
        for i in range(len(dictdata)):
             price = modelToDict(data[i].price.all())
             dictdata[i]['fields']['price'] = price
        return HttpResponse(json.dumps(`dictdata`), content_type="application/json")
    

    【讨论】:

      【解决方案4】:

      因此,在您的情况下,您只需添加depth = 1,您将获得嵌套表示。

      Docs

      默认的ModelSerializer 使用主键来表示关系,但是 您还可以使用depth 轻松生成嵌套表示 选项:

      class AccountSerializer(serializers.ModelSerializer):
          class Meta:
              model = Account
              fields = ['id', 'account_name', 'users', 'created']
              depth = 1
      

      【讨论】:

        猜你喜欢
        • 2012-03-13
        • 2019-04-01
        • 2020-12-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-22
        • 2011-04-26
        • 1970-01-01
        相关资源
        最近更新 更多