跨表序列化Django REST Framework [英] Cross-table serialization Django REST Framework

查看:248
本文介绍了跨表序列化Django REST Framework的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个具有多对多关系的模型,我正在尝试使用Django REST Framework返回一些geojson。我试图返回的数据是pub_date和坐标(由GeoDjango中的PointField表示)。每次尝试返回geojson时,都会出现错误字段名称 city对于模型 Article 无效。我对django / geodjango相当陌生,这是我第一次使用Django REST Framework。我遍历了文档,但无法弄清楚哪里出了问题(甚至可能从哪里开始)。



这里是我的模型和序列化器。 / p>

models.py:

  class Location(models.Model): 
城市=模型.CharField(max_length = 200)
国家=模型.CharField(max_length = 200)
大洲=模型.CharField(max_length = 200)
点=模型。 PointField(srid = 4326)
对象=模型.GeoManager()

def __unicode __(self):
return u'%s'%(self.point)

class Meta:
db_table ='location'

class class(models.Model):
authors = models.ManyToManyField(Author)
的位置= models.ManyToManyField(Location,related_name ='places')
article_title = models.CharField(max_length = 200,unique_for_date = pub_date)
pub_date = models.DateTimeField('datedate')
article_keywords = ArrayField(ArrayField(models.CharField(max_ length = 20,blank = True),size = 10),size = 10,)
title_id = models.CharField(max_length = 200)
section_id = models.CharField(max_length = 200)

def __unicode __(self):
返回u'%s%s%s'%(self.article_title,self.pub_date,self.article_keywords)

类元:
db_table ='article'

serializers.py

 类ArticleSerializer(serializers.ModelSerializer):
位= serializers.PrimaryKeyRelatedField(many = True,read_only = True)
类Meta:
模型=文章
字段=('地方')

输出像这样:

  {
type: FeatureCollection,
features:[
{
type: Feature,
properties:{
time: 2013-01-22 08:42:26 + 01
},
geometry:{
type: Point,
坐标:[
7.582512743,
51.933292258,
1
]
}
},
{
type :功能,
属性:{
time: 2013-01-22 10:00:26 + 01
},
geometry: {
type: Point,
coordinates:[
7.602516645,
51.94962073,
1
]
}
}

谢谢!



更新!我设法通过在查询集中嵌入原始SQL查询到达某个地方,但这不是很正确:

  serialize('geojson ',Article.objects.raw('
从文章a
中选择a.id,a.pub_date,al.location_id,l.point
加入a.id = al的article_locations al。 article_id
al.location_id = l.id')上的加入位置l,
geometry_field ='point',
fields =('pub_date','locations',))

结果是这样的:

  {
type: FeatureCollection,
crs:{
type: name,
properties:{
名称: EPSG:4326
}
},
功能:[
{
geometry:null,
类型:功能,
属性:{
pub_date: 2015-04-06T20:38:59Z,
位置:[
3
]
}
}


解决方案

DRF秒erializer可以做两件事:


  1. 将复杂数据(例如查询集)序列化为本地Python数据类型

      serializer = CommentSerializer(评论)
    serializer.data
    #{'电子邮件':u'leila @ example.com','content':u'foo bar','created':datetime.datetime(2012,8,22,16,20,9,822774)}


  2. 从本机Python数据类型反序列化数据

      serializer = CommentSerializer(data = data)
    serializer.is_valid()
    #真
    serializer.validated_data
    #{'content':'foo bar','email': 'leila@example.com','created':datetime.datetime(2012,08,22,16,20,09,822243)}


在您的情况下


所有我想要返回的是所有文章pub_dates及其对应的
文章经纬度坐标(来自pointField)。


必须做两个铰链:


  1. 使用对象创建复杂的数据结构,对象的列表查询集



    在您的情况很简单,您只需要一个包含所有文章并带有 已预取 位置,以防止每个位置不必要的数据库命中。

      Article.objects.all()。prefetch_related('locations')[:10] 


  2. 创建一个可以序列化此查询集的序列化器。



    由于您已嵌套数据结构(一个文章可以有很多个位置最好将其拆分为两个单独的序列化器。



    第一个只知道如何序列化位置,第二个只知道如何序列化<$仅用于c $ c> articles ,但它将对 article.locations 序列化使用第一个。

     类LocationSerializer(serializers.ModelSerializer):
    类元:
    模型=位置
    字段=('point',)


    类ArticleSerializer(serializers.ModelSerializer):
    #这种方式我们将覆盖默认的序列化
    #此字段的行为。
    位置= LocationSerializer(很多=真)

    类元:
    模型=文章
    字段=('pub_date','locations')


最后,您可以合并 1 2 通过 ViewSet

  class ArticleViewSet(viewsets.ModelViewSet):
serializer_class = ArticleSerializer
#阅读有关分页的知识,以便将其拆分为页面
queryset = Article.objects.all()。prefetch_related('locations')[:10]


I have two models with a many-to-many relationship and I am trying to return some geojson by using the Django REST Framework. The data I am trying to return is th pub_date and coordinates (represented by a PointField in GeoDjango). Everytime I try and return the geojson I get the error Field name 'city' is not valid for model 'Article'. I'm pretty new to django/geodjango and this is the first time I've used the Django REST Framework. I've gone through the docs but can't work out where I'm going wrong (or maybe even where to start).

Here my models and serializers.

models.py:

class Location(models.Model):
    city = models.CharField(max_length=200)
    country = models.CharField(max_length=200)
    continent = models.CharField(max_length=200)
    point = models.PointField(srid=4326)
    objects = models.GeoManager()

    def __unicode__(self):
        return u'%s' % (self.point)

    class Meta:
        db_table = 'location'

class Article(models.Model):
    authors = models.ManyToManyField(Author)
    locations = models.ManyToManyField(Location, related_name='places')
    article_title = models.CharField(max_length=200, unique_for_date="pub_date")
    pub_date = models.DateTimeField('date published')
    article_keywords = ArrayField(ArrayField(models.CharField(max_length=20, blank=True), size=10), size=10,)
    title_id = models.CharField(max_length=200)
    section_id = models.CharField(max_length=200)

    def __unicode__(self):
        return u'%s %s %s' % (self.article_title, self.pub_date, self.article_keywords)     

    class Meta:
        db_table = 'article'

serializers.py

class ArticleSerializer(serializers.ModelSerializer):
    places = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
    class Meta:
        model = Article
        fields = ('places')

And the output I would like:

{
"type": "FeatureCollection",
"features": [
    {
        "type": "Feature",
        "properties": {
            "time": "2013-01-22 08:42:26+01"
        },
        "geometry": {
            "type": "Point",
            "coordinates": [
                7.582512743,
                51.933292258,
                1
            ]
        }
    },
    {
        "type": "Feature",
        "properties": {
            "time": "2013-01-22 10:00:26+01"
        },
        "geometry": {
            "type": "Point",
            "coordinates": [
                7.602516645,
                51.94962073,
                1
            ]
        }
    }

Thanks in advance!

UPDATE! I managed to get somewhere with a raw SQL query embeded in a queryset but this is not not quite right:

serialize('geojson', Article.objects.raw('
select a.id, a.pub_date, al.location_id, l.point 
from article a 
join article_locations al on a.id = al.article_id 
join location l on al.location_id = l.id'),
geometry_field = 'point',
fields=('pub_date','locations',))

The result is this:

{  
"type":"FeatureCollection",
"crs":{  
    "type":"name",
    "properties":{  
        "name":"EPSG:4326"
    }
},
"features":[  
    {  
        "geometry":null,
        "type":"Feature",
        "properties":{  
            "pub_date":"2015-04-06T20:38:59Z",
            "locations":[  
                3
            ]
        }
    }

解决方案

DRF serializers can do two things:

  1. Serialize complex data (such as querysets) to native Python datatypes

    serializer = CommentSerializer(comment)
    serializer.data
    # {'email': u'leila@example.com', 'content': u'foo bar', 'created': datetime.datetime(2012, 8, 22, 16, 20, 9, 822774)}
    

  2. Deserialize data from native Python datatypes

    serializer = CommentSerializer(data=data)
    serializer.is_valid()
    # True
    serializer.validated_data
    # {'content': 'foo bar', 'email': 'leila@example.com', 'created': datetime.datetime(2012, 08, 22, 16, 20, 09, 822243)}
    

In your case where

All I want is to return all article pub_dates and their corresponding article coordinates lat/long's (from the pointField).

You will have to do two things:

  1. Create a complex data structure using either an object, a list of objects or a queryset.

    In your case this is pretty easy, you just need a queryset with all articles and with prefetched locations in order to prevent unnecessary db hits for each location.

    Article.objects.all().prefetch_related('locations')[:10]
    

  2. Create a serializer which can serialize this queryset.

    Since you have nested data structure (one article can have many locations) you better split this into two separate serializers.

    The first one will know how to serialize locations only, and the second one will know how to serialize articles only, but it will use the first one for the article.locations serialization.

    class LocationSerializer(serializers.ModelSerializer):
        class Meta:
            model = Location
            fields = ('point',)
    
    
    class ArticleSerializer(serializers.ModelSerializer):
        #this way we override the default serialization 
        #behaviour for this field.
        locations = LocationSerializer(many=True)
    
        class Meta:
            model = Article
            fields = ('pub_date', 'locations')
    

Finally you can combine 1 and 2 via a ViewSet

class ArticleViewSet(viewsets.ModelViewSet):
    serializer_class = ArticleSerializer
    #read about pagination in order to split this into pages
    queryset = Article.objects.all().prefetch_related('locations')[:10]

这篇关于跨表序列化Django REST Framework的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆