为多表继承Django模型填充tastypie资源

Populating a tastypie resource for a multi-table inheritance Django model

考虑到以下代码,我想知道如何用每个实际记录数据填充RecordsResource

江户十一〔一〕号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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

埃多克斯1〔2〕

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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()


好吧,我刚刚解决了。我简化了代码。

给出以下代码…

埃多克斯1〔9〕

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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()

埃多克斯1〔10〕

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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()

产量

江户十一〔11〕。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
 "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/"
    }
  ]
}

好啊

埃多克斯1〔12〕

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
 "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/"
    }
  ]
}

好啊

埃多克斯1〔13〕

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
 "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/"
    }
  ]
}

我想达到的目标

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
 "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/"
    }
  ]
}

解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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


在recordsresource类中,还需要添加model字段(请参见https://github.com/tomcristie/django rest framework/blob/master/djangorestframework/resources.py l232-234)

1
2
3
4
5
6
class RecordsResource(BaseRecordResource):
    model = Record

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


从一开始就解释:

Django有三种继承方式。

  • 通常,您只需要使用父类来保存您不想为每个孩子输入的信息模型。这个类不会单独使用,所以抽象基类就是你想要的。

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

  • 最后,如果只想修改模型,在不以任何方式更改模型字段的情况下,可以使用代理模型。

  • 这里的选择是多表继承

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

    RecordRecordx,在1 <= x <= n的地方,你要做a_example_record = Record.objects,get(pk=3),然后用下面的方法检查什么类型的Recordx

    1
    2
    3
    4
    if hasattr(a_example_record, 'record1'):
        # ...
    elif hasattr(a_example_record, 'record2'):
        # ...

    因此,既然我们知道了如何从父母那里得到孩子,并且我们需要向TastyPie提供元中的queryset,那么您需要在Record模型上编写一个由自定义管理器支持的自定义queryset,该模型会记录您的所有记录(更多信息,请参阅自定义查询集和管理器,而不必断开干系?),检查它是什么类型的子级,并将其附加到查询集或列表。您可以阅读关于在这里追加如何在django视图中组合2个或多个查询集的内容?