2014-11-20 97 views
4

我有一個表示房子的模型:DRF:操作串行領域的佈局

class House(models.Model): 
    name = models.CharField(...) 
    long = models.FloatField(...) 
    lat = models.FloatField(...) 

和串行到他們最基本表示返回的房屋列表:

class HouseSerializer(serializers.ModelSerializer): 
    class Meta: 
     model = House 
     fields = ('id', 'name')  

和視圖

class HouseList(generics.ListAPIView): 
    queryset = House.objects.all() 
    serializer_class = HouseSerializer 

這工作正常。我可以訪問/api/house/,我看到房子的JSON列表:

{ 
    'id': 1, 
    'name': 'Big House' 
}, 
{ 
    'id': 1 
    'name': 'Small House', 
}... 

現在,我想在/api/maps/markers/返回我的房子作爲格式的谷歌地圖友好的標記列表,創建第二個視圖/資源:

{ 
    'id': 1, 
    'long': ..., 
    'lat': ..., 
    'houseInfo': { 
     'title': "Big House", 
    } 
} ... 

我可以預見兩種方法:

  • 執行此作爲一個單獨的串行器(使用與前面相同的視圖)和映射出替代字段佈局。
  • 執行此作爲一個單獨的視圖(如前使用相同的串行器)和創建Response

之前簡單地佈局領域,但在這兩種方法都不是我清楚如何去了解它,也沒有哪一種方法最好?

回答

4

回答1

在我看來像你既需要 - 不同的觀點和串行器。

只是因爲視圖端點不是第一個的子網址,所以它們是不相關的 - 不同的視圖,即使它們使用相同的模型。

和不同的串行器 - 因爲你有不同的字段佈局。

不太清楚你的情況有多複雜,但任何代碼重複都可以通過mixin解決。

答案2

根據不同的使用情況:

  • ,如果你還需要使用相同的結構來寫數據,您需要定義自己的領域類,並處理正確地分析
  • 如果只是讀取數據時,你應該罰款與此:

    class HouseGoogleSerializer(HouseSerializer): 
        houseInfo = serializers.SerializerMethodField('get_house_info') 
    
        class Meta: 
         model = House 
         fields = [...] 
    
        def get_house_info(self, obj): 
         return {'title': obj.name} 
    

    其中HouseSerializer是您的基地序列化程序。

+0

我怎樣才能在串行操作領域的佈局,雖然所以我有一個嵌套的'houseInfo'對象? – 2014-12-11 15:28:46

+0

@ TimmyO'Mahony看到我的更新,希望它有幫助。我可以找到幾種操作佈局的方法,這種方法看起來最靈活,最乾淨。 – mariodev 2014-12-11 22:32:59

1

這個代碼來自正在運行的項目和somethig提供更多的,你問 ,但可以很容易地適應您的需求,如果你想刪除一些功能。 目前implemetation允許你:

  • 只使用一個URL一個串行器和一個視圖
  • 使用查詢字符串參數(串行=性病?)

如何在代碼中使用選擇輸出:

案例1(一個URL能夠選擇通過查詢字符串序列化能力)

class HouseSerializer(HouseSerializer): 
    houseInfo = serializers.SerializerMethodField('get_house_info') 

    class Meta: 
     model = House 

    def get_house_info(self, obj): 
     return {'title': obj.name} 


class HouseList(DynamicSerializerMixin, generics.ListAPIView): 
    queryset = House.objects.all() 
    serializer_class = HouseSerializer 
    serializers_fieldsets = {'std': ('id', 'name'), 
           'google' : ('id', 'long', 'lat', 'houseInfo')} 

案例2(不同意見)

class HouseList(DynamicSerializerMixin, generics.ListAPIView): 
    queryset = House.objects.all() 
    serializer_class = HouseSerializer 
    serializers_fieldsets = {'std': ('id', 'name')} 

class GoogleHouseList(DynamicSerializerMixin, generics.ListAPIView): 
    queryset = House.objects.all() 
    serializer_class = HouseSerializer 
    serializers_fieldsets = {'std': ('id', 'long', 'lat', 'houseInfo')} 

==============

def serializer_factory(model, base=BaseHyperlinkedModelSerializer, 
         fields=None, exclude=None): 
    attrs = {'model': model} 
    if fields is not None: 
     attrs['fields'] = fields 
    if exclude is not None: 
     attrs['exclude'] = exclude 

    parent = (object,) 
    if hasattr(base, 'Meta'): 
     parent = (base.Meta, object) 
    Meta = type(str('Meta'), parent, attrs) 
    if model: 
     class_name = model.__name__ + 'Serializer' 
    else: 
     class_name = 'Serializer' 
    return type(base)(class_name, (base,), {'Meta': Meta, }) 


class DynamicSerializerMixin(object): 
    """ 
    Mixin that allow to limit the fields returned 
    by the serializer. 

    Es. 
     class User(models.Model): 
      country = models.ForeignKey(country) 
      username = models.CharField(max_length=100) 
      email = models.EmailField() 

     class UserSerializer(BaseHyperlinkedModelSerializer): 
      country = serializers.Field(source='country.name') 


     class MyViewSet(DynamicSerializerViewSetMixin, BaseModelViewSet): 
      model = User 
      serializer_class = UserSerializer 
      serializers_fieldsets = {'std': None, 
             'brief' : ('username', 'email') 
             } 
    this allow calls like 

     /api/v1/user/?serializer=brief 

    """ 
    serializers_fieldsets = {'std': None} 
    serializer_class = ModelSerializer 

    def get_serializer_class(self): 
     ser = self.request.QUERY_PARAMS.get('serializer', 'std') 

     fields = self.serializers_fieldsets.get(ser, 'std') 

     return serializer_factory(self.model, 
            self.serializer_class, 
            fields=fields)