Populating tastypie for multitasking Django model inheritance

Given the following code, I was wondering how to populate RecordsResource with each real record:

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() 
+6
source share
3 answers

Ok, I just decided. I have simplified the code.

Given the following code ...

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

Exit

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

What i want to achieve

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

Decision:

 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 
+7
source

In the RecordsResource class, you also need to add a model field (see 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
source

Explanation from the start:

There are three inheritance styles that are possible in Django.

  • Often you just want to use the parent class to store information that you do not want to print for each child model. This class will never be used in isolation, so Abstract base classes are what you need.

  • If you subclass an existing model (perhaps something from another application completely) and want each model to have its own database table. Multiple table inheritance is the way to go.

  • Finally, if you want to change the behavior at the level of the Python model, without changing the model fields anyway, you can use Proxy models.

The choice here is to inherit multiple tables.

Multiple Table Inheritance The second type of model inheritance supported by Django is when each model in the hierarchy is itself a model. Each model corresponds to its own database table and can be requested and created individually. The inheritance interaction introduces links between the child model and each of its parents (via the automatically created OneToOneField) Ref

To go from Record to Recordx , where 1 <= x <= n do a_example_record = Record.objects,get(pk=3) , and then check what type of Recordx it uses with something like below

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

So, now that we know how to get the children from the parent, and we need to provide the TastyPie queryset in our meta, you need to write a custom queryset , supported by a custom manager in Record , which takes all your records (Read more here Custom QuerySet and Manager, without breaking DRY? ), checks what type of this child is and adds it to the query set or list. You can read about the addition here. How to combine two or more requests in a Django view?

+1
source

Source: https://habr.com/ru/post/922675/


All Articles