2012-08-12 13 views
6

Biorąc pod uwagę następujący kod Zastanawiałem się, jak wypełnić RecordsResource z każdym rzeczywistym danych rekordu:Wypełnianie tastypie zasób dla dziedziczenia multi-table Django modelu

models.py

class Record(models.Model): 
    content_type = models.ForeignKey(ContentType, editable=False, null=True) 
    user = models.ForeignKey(User, related_name='records') 
    issued = models.DateTimeField(auto_now_add=True) 
    date = models.DateField() 

    def save(self, *args, **kwargs): 
     if not self.content_type: 
      self.content_type = ContentType.objects.get_for_model(self.__class__) 
     super(Record, self).save(*args, **kwargs) 

    def as_leaf_class(self): 
     model = self.content_type.model_class() 
     if model == self.__class__: 
      return self 
     return model.objects.get(pk=self.id) 


class Record1(Record): 
    # some fields 

# ... 

class RecordN(Record): 
    # some fields 

api.py

class BaseModelResource(ModelResource): 
    class Meta(object): 
     authentication = ApiKeyPlusWebAuthentication() 
     authorization= Authorization() 
     cache = SimpleCache() 
     throttle = CacheDBThrottle(
      throttle_at=350, 
      # 1 day 
      expiration=86400 
     ) 
     if settings.DEBUG: 
      serializer = PrettyJSONSerializer() 

    def obj_create(self, bundle, request=None, **kwargs): 
     return super(BaseModelResource, self).obj_create(bundle, request, user=request.user) 

    def apply_authorization_limits(self, request, object_list): 
     return object_list.filter(user=request.user) 


class BaseRecordResource(BaseModelResource): 
    class Meta(BaseModelResource.Meta): 
     filtering = { 
      'date': ALL 
     } 
     excludes = ['issued'] 

class RecordsResource(BaseRecordResource): 
    class Meta(BaseRecordResource.Meta): 
     resource_name = 'records' 
     queryset = Record.objects.all() 

class Record1Resource(BaseRecordResource): 
    class Meta(BaseRecordResource.Meta): 
     resource_name = 'record1' 
     queryset = Record1.objects.all() 

# ... 

class RecordNResource(BaseRecordResource): 
    class Meta(BaseRecordResource.Meta): 
     resource_name = 'recordn' 
     queryset = RecordN.objects.all() 

Odpowiedz

7

Ok, właśnie go rozwiązałem. Uprościliśmy kod.

Biorąc pod uwagę następujący kod ...

models.py

from django.db import models 
from model_utils.managers import InheritanceManager 


class Place(models.Model): 
    name = models.CharField(max_length=50) 
    address = models.CharField(max_length=80) 

    # https://github.com/carljm/django-model-utils#inheritancemanager 
    objects = InheritanceManager() 


class Restaurant(Place): 
    custom_field = models.BooleanField() 


class Bar(Place): 
    custom_field = models.BooleanField() 

api.py

from core.models import Place, Restaurant, Bar 
# http://django-tastypie.readthedocs.org/en/latest/cookbook.html#pretty-printed-json-serialization 
from core.utils import PrettyJSONSerializer 
from tastypie.resources import ModelResource 


class PlaceResource(ModelResource): 
    class Meta: 
     queryset = Place.objects.select_subclasses() 
     resource_name = 'place' 
     serializer = PrettyJSONSerializer() 


class RestaurantResource(ModelResource): 
    class Meta: 
     queryset = Restaurant.objects.all() 
     resource_name = 'restaurant' 
     serializer = PrettyJSONSerializer() 


class BarResource(ModelResource): 
    class Meta: 
     queryset = Bar.objects.all() 
     resource_name = 'bar' 
     serializer = PrettyJSONSerializer() 

Wyjście

http://localhost:8000/api/v1/bar/?format=json

{ 
    "meta": { 
    "limit": 20, 
    "next": null, 
    "offset": 0, 
    "previous": null, 
    "total_count": 1 
    }, 
    "objects": [ 
    { 
     "address": "dawdaw", 
     "custom_field": true, 
     "id": "1", 
     "name": "dwdwad", 
     "resource_uri": "/api/v1/bar/1/" 
    } 
    ] 
} 

OK

http://localhost:8000/api/v1/restaurant/?format=json

{ 
    "meta": { 
    "limit": 20, 
    "next": null, 
    "offset": 0, 
    "previous": null, 
    "total_count": 1 
    }, 
    "objects": [ 
    { 
     "address": "nhnhnh", 
     "custom_field": true, 
     "id": "2", 
     "name": "nhnhnh", 
     "resource_uri": "/api/v1/restaurant/2/" 
    } 
    ] 
} 

OK

http://localhost:8000/api/v1/place/?format=json

{ 
    "meta": { 
    "limit": 20, 
    "next": null, 
    "offset": 0, 
    "previous": null, 
    "total_count": 2 
    }, 
    "objects": [ 
    { 
     "address": "dawdaw", 
     "id": "1", 
     "name": "dwdwad", 
     "resource_uri": "/api/v1/place/1/" 
    }, 
    { 
     "address": "nhnhnh", 
     "id": "2", 
     "name": "nhnhnh", 
     "resource_uri": "/api/v1/place/2/" 
    } 
    ] 
} 

Co chcę osiągnąć

{ 
    "meta": { 
    "limit": 20, 
    "next": null, 
    "offset": 0, 
    "previous": null, 
    "total_count": 2 
    }, 
    "objects": [ 
    { 
     "address": "dawdaw", 
     "custom_field": true, 
     "id": "1", 
     "name": "dwdwad", 
     "resource_uri": "/api/v1/bar/1/" 
    }, 
    { 
     "address": "nhnhnh", 
     "custom_field": true, 
     "id": "2", 
     "name": "nhnhnh", 
     "resource_uri": "/api/v1/restaurant/2/" 
    } 
    ] 
} 

Rozwiązanie:

from core.models import Place, Restaurant, Bar 
# http://django-tastypie.readthedocs.org/en/latest/cookbook.html#pretty-printed-json-serialization 
from core.utils import PrettyJSONSerializer 
from tastypie.resources import ModelResource 

class RestaurantResource(ModelResource): 
    class Meta: 
     queryset = Restaurant.objects.all() 
     resource_name = 'restaurant' 
     serializer = PrettyJSONSerializer() 


class BarResource(ModelResource): 
    class Meta: 
     queryset = Bar.objects.all() 
     resource_name = 'bar' 
     serializer = PrettyJSONSerializer() 

class PlaceResource(ModelResource): 
    class Meta: 
     queryset = Place.objects.select_subclasses() 
     resource_name = 'place' 
     serializer = PrettyJSONSerializer() 

    def dehydrate(self, bundle): 
     # bundle.data['custom_field'] = "Whatever you want" 
     if isinstance(bundle.obj, Restaurant): 
      restaurant_res = RestaurantResource() 
      rr_bundle = restaurant_res.build_bundle(obj=bundle.obj, request=bundle.request) 
      bundle.data = restaurant_res.full_dehydrate(rr_bundle).data 
     elif isinstance(bundle.obj, Bar): 
      bar_res = BarResource() 
      br_bundle = bar_res.build_bundle(obj=bundle.obj, request=bundle.request) 
      bundle.data = bar_res.full_dehydrate(br_bundle).data 
     return bundle 
1

Wyjaśniając od początku:

Istnieje three styles of inheritance które są możliwe w Django.

  1. Często, po prostu chcą skorzystać z klasy nadrzędnej trzymać informacje, które nie chcą mieć do wpisywania się do każdego dziecka modelu. Ta klasa nie będzie nigdy używana w izolacji, więc Klasy podstawowe są tym, na co masz ochotę.

  2. Jeśli instacji istniejący model (może coś z całkowicie inna aplikacja), a każdy model chcą mieć własną tabelę bazy danych, Multi-table dziedziczenia jest droga.

  3. Wreszcie, jeśli tylko chcesz zmodyfikować zachowanie Pythona poziomu dla modelu, bez zmiany pól modeli w dowolny sposób, można użyć modele proxy.

Wybór tutaj jest Multi-table dziedziczenia

Multi-table dziedziczenia Drugi typ modelu dziedziczenia obsługiwane przez Django jest, gdy każdy model w hierarchii jest modelem wszystko sama. Każdy model odpowiada własnej tabeli bazy danych i może być sprawdzany i tworzony indywidualnie. Zależność od spadków wprowadza powiązania pomiędzy modelem dzieci i każde z rodziców (poprzez automatycznie utworzonego OneToOneField)Ref

Aby przejść z Record do Recordx gdzie 1 <= x <= n zrobić a_example_record = Record.objects,get(pk=3), a następnie sprawdzić, jaki rodzaj Recordx jest za pomocą something like below

if hasattr(a_example_record, 'record1'): 
    # ... 
elif hasattr(a_example_record, 'record2'): 
    # ... 

Więc teraz, że wiemy, jak się dzieci od rodziców i musimy zapewnić TastyPie z queryset w jego meta, trzeba napisać niestandardowy queryset poparte niestandardowy menedżer w modelu Record, który przechwytuje wszystkie twoje rekordy (Więcej tutaj Custom QuerySet and Manager without breaking DRY?), sprawdza, jaki typ dziecka jest i dołącza do kwerendy lub listy. Możesz przeczytać o dołączaniu tutaj How to combine 2 or more querysets in a Django view?

Powiązane problemy