【问题标题】:Populating a tastypie resource for a multi-table inheritance Django model为多表继承 Django 模型填充一个美味的资源
【发布时间】:2012-08-09 01:58:01
【问题描述】:

鉴于以下代码,我想知道如何使用每个真实记录数据填充 RecordsResource

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()

【问题讨论】:

    标签: django django-models tastypie


    【解决方案1】:

    好的,我刚刚解决了。我已经简化了代码。

    给定以下代码...

    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()
    

    输出

    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/"
        }
      ]
    }
    

    好的

    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/"
        }
      ]
    }
    

    好的

    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/"
        }
      ]
    }
    

    我想要达到的目标

    {
      "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/"
        }
      ]
    }
    

    解决方案:

    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
    

    【讨论】:

      【解决方案2】:

      在 RecordsResource 类中,您还需要添加模型字段(参见https://github.com/tomchristie/django-rest-framework/blob/master/djangorestframework/resources.py#L232-234

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

      【讨论】:

        【解决方案3】:

        从头解释:

        three styles of inheritance 在 Django 中是可能的。

        1. 通常,您只想使用父类来保存 您不想为每个孩子输入的信息 模型。这个类永远不会被孤立地使用,所以 抽象基类就是你所追求的。

        2. 如果您要对现有模型进行子类化(可能来自 完全是另一个应用程序)并希望每个模型都有自己的 数据库表,多表继承才是王道。

        3. 最后,如果你只想修改一个 Python 级别的行为 模型,无需以任何方式更改模型字段,您可以使用 代理模型。

        这里的选择是多表继承

        多表继承 Django 支持的第二种模型继承类型是层次结构中的每个模型都是单独的模型。每个模型对应自己的数据库表,可以单独查询和创建。继承关系引入了子模型与其每个父模型之间的链接(通过自动创建的 OneToOneField) Ref

        要从Record 转到Recordx,其中1 <= x <= na_example_record = Record.objects,get(pk=3),然后使用something like below 检查Recordx 的类型

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

        既然我们知道如何从父级获取子级,并且我们需要在其元数据中为TastyPie 提供queryset,您需要在@ 上编写由自定义管理器支持的自定义queryset 987654335@ 模型,它获取您的所有记录(更多此处为Custom QuerySet and Manager without breaking DRY?),检查它是什么类型的孩子并将其附加到查询集或列表中。您可以阅读有关在此处附加 How to combine 2 or more querysets in a Django view?

        【讨论】:

          猜你喜欢
          • 2012-04-20
          • 2012-09-25
          • 2012-04-03
          • 2013-04-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-09-13
          相关资源
          最近更新 更多