跨表序列化Django REST框架

sam*_*888 1 django geodjango geojson django-rest-framework

我有两个具有多对多关系的模型,我试图通过使用Django REST框架返回一些geojson.我想要返回的数据是pub_date和坐标(由GeoDjango中的PointField表示).每当我尝试返回geojson时,我都会收到错误Field name 'city' is not valid for model 'Article'.我是django/geodjango的新手,这是我第一次使用Django REST Framework.我已经完成了文档,但无法解决我出错的地方(或者甚至可能从哪里开始).

这是我的模型和序列化器.

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'
Run Code Online (Sandbox Code Playgroud)

serializers.py

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

我想要的输出:

{
"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
            ]
        }
    }
Run Code Online (Sandbox Code Playgroud)

提前致谢!

UPDATE!我设法在查询集中嵌入原始SQL查询,但这不是很正确:

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',))
Run Code Online (Sandbox Code Playgroud)

结果是这样的:

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

Tod*_*dor 5

DRF序列化程序可以做两件事:

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

    serializer = CommentSerializer(comment)
    serializer.data
    # {'email': u'leila@example.com', 'content': u'foo bar', 'created': datetime.datetime(2012, 8, 22, 16, 20, 9, 822774)}
    
    Run Code Online (Sandbox Code Playgroud)
  2. 从本机Python数据类型反序列化数据

    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)}
    
    Run Code Online (Sandbox Code Playgroud)

在你的情况下

我想要的是返回所有文章pub_dates及其相应的文章坐标lat/long(来自pointField).

你将不得不做两件事:

  1. 使用a object,a list或a对象创建复杂的数据结构queryset.

    在您的情况下,这非常简单,您只需要一个包含所有文章和prefetched位置的查询集,以防止每个文件都有不必要的db命中location.

    Article.objects.all().prefetch_related('locations')[:10]
    
    Run Code Online (Sandbox Code Playgroud)
  2. 创建一个序列化程序,可以序列化此查询集.

    由于您具有嵌套数据结构(article可以有多个locations),因此最好将其拆分为两个单独的序列化程序.

    第一个将知道如何locations仅序列化,第二个将知道如何articles仅序列化,但它将使用第一个article.locations序列化.

    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')
    
    Run Code Online (Sandbox Code Playgroud)

最后,你可以结合12通过视图集

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]
Run Code Online (Sandbox Code Playgroud)