start how framework ejemplo create django rest django-models tastypie

ejemplo - how to start a django rest framework



Django tastypie y GenericForeignKey (7)

Tengo un modelo de página con GFK.

class Page(models.Model): title = models.CharField(max_length=200) content_type = models.ForeignKey(ContentType,null=True,blank=True) object_id = models.CharField(max_length=255,null=True,blank=True) content_object = generic.GenericForeignKey(''content_type'', ''object_id'')

y

class TextContent(models.Model): content = models.TextField(null=True, blank=True) pages = generic.GenericRelation(Page)

Hago Page.objects.get (pk = 1) .content_object y lo tengo.

Ayúdeme por favor a mostrar un enlace (o salida a JSON) que ancló el objeto en REST.

class PageResource(ModelResource): content_object = fields.????? class Meta: queryset = Page.objects.all() resource_name = ''page''

¿Cómo hacerlo bien?

¡Gracias!

Vitaliy


Actualmente no hay una manera fácil de usar relaciones genéricas en tastypie. Se han enviado algunos parches en la página de tastypie github, pero no se han fusionado al momento de escribir este artículo.

La forma más fácil de hacerlo es definir un recurso de tipo de contenido y usarlo para los recursos que tienen una relación genérica. Algo como:

class ContentTypeResource(ModelResource): class Meta: queryset = ContentType.objects.all() resource_name = "contrib/contenttype" fields = [''model''] detail_allowed_methods = [''get'',] list_allowed_methods = [''get''] class PageResource(ModelResource): content_object = fields.ToOneField(''myresources.ContentTypeResource'', ''content_object'') class Meta: queryset = Page.objects.all() resource_name = ''page''

Espero que esto ayude.


El elemento "mis recursos" es la aplicación que contiene ContentTypeResource. Si está en la misma aplicación que sus otros recursos, no necesita calificar. Eliminado en el código a continuación.

El "contrib / contenttype" es el nombre del recurso. Establecer su propio nombre es opcional. Tastypie creará uno para ti si no lo especificas. Lo he eliminado en el código de actualización a continuación.

La sección fields = [''model''] limita los campos accesibles del modelo que este recurso representa. Si observas la definición del modelo ContentType en el código Django, verás que tiene un campo llamado ''modelo''.

Creo que la respuesta original tenía sus nombres de campo mezclados. Está intentando crear un nuevo recurso para content_type y conectarlo a la clave externa content_type en su modelo. El código de arriba ordena esto.

class ContentTypeResource(ModelResource): class Meta: queryset = ContentType.objects.all() fields = [''model''] detail_allowed_methods = [''get'',] list_allowed_methods = [''get''] class PageResource(ModelResource): content_type = fields.ToOneField(''ContentTypeResource'', ''content_type'') class Meta: queryset = Page.objects.all() resource_name = ''page''

También necesitará registrar ContentTypeResource en su urls.py como lo hizo con todos sus otros recursos:

from myapp.api import ContentTypeResource v1_api = Api(api_name=''v1'') v1_api.register(ContentTypeResource())

El bit "myapp" vuelve a ser la aplicación con el código api que contiene ContentTypeResource.

Espero que esto aclare las cosas. Lo conseguí trabajando solo ...


Esto le da el campo content_object como un objeto anidado. Es simple, funciona, y (desafortunadamente) es tan eficiente que la tecnología lo permite.

class PageResource(ModelResource): def full_dehydrate(self, bundle): new_bundle = super(PageResource, self).full_dehydrate(bundle) new_bundle.data[''content_object''] = get_serializable(bundle.obj.content_object) return new_bundle class Meta: queryset = Page.objects.all() def get_serializable(model): data = {''type'': model.__class__.__name__} for field in model._meta.fields: data[field.name] = getattr(model, field.name) return data


¡Hemos descifrado el código!

class ContentTypeResource(ModelResource): class Meta: queryset = ContentType.objects.all() resource_name = ''content_type'' allowed_methods = [''get'',] class PageObjectResource(ModelResource): content_object = fields.CharField() content_type = fields.ToOneField( ContentTypeResource, attribute = ''content_type'', full=True) class Meta: queryset = models.PageObject.objects.all() resource_name = ''page_object'' allowed_methods = [''get'',] def dehydrate_content_object(self, bundle): for resource in api._registry.values(): if resource._meta.object_class == bundle.obj.content_object.__class__: return resource.full_dehydrate(resource.build_bundle(obj=bundle.obj.content_object, request=bundle.request)).data return ''''

Lo que resulta en algo como:

"page_objects": [ { "content_object": { "id": "186", "look_stills": [ { "_image": "/static/media/uploads/looks/DSC_0903_PR_MEDIUM_QUALITY_RGB_FA.jpg", "aspect": "front", "id": "186", "look_still_icons": [ { "colour_code": "58", "enabled": true, "id": "186", "in_stock_only": true, "look_product": { "colour_code": "58", "enabled": true, "id": "186", "resource_uri": "/api/look_product/186/", "style_code": "420215" }, "resource_uri": "/api/look_still_icon/186/", "x_coord": 76, "y_coord": 5 } ], "ordering": 1, "resource_uri": "/api/look_still/186/" } ], "resource_uri": "/api/look_still_set/186/", "slug": "" }, "content_type": { "app_label": "looks_beta", "id": "97", "model": "lookstillset", "name": "look still set", "resource_uri": "/api/content_type/97/" }, "id": "2", "object_id": 186, "resource_uri": "/api/page_object/2/" } ], "page_order": 3, "page_template": "look_still", "resource_uri": "/api/page/2/", "slug": "", "spread_number": 2, "title": "" },


Logramos obtener el uri del objeto de contenido, si tenía un ModelResource correspondiente:

class ContentTypeResource(ModelResource): class Meta: queryset = ContentType.objects.all() resource_name = ''content_type'' allowed_methods = [''get'',] class PageObjectResource(ModelResource): content_object_uri = fields.CharField() content_type = fields.ToOneField( ContentTypeResource, attribute = ''content_type'', full=True) class Meta: queryset = models.PageObject.objects.all() resource_name = ''page_object'' allowed_methods = [''get'',] def dehydrate_content_object_uri(self, bundle): for resource in api._registry.values(): if resource._meta.object_class == bundle.obj.content_object.__class__: return resource.get_resource_uri(bundle.obj.content_object) return ''''



De hecho, han agregado soporte para esto como Mario sugirió. Como tardó una eternidad en descubrirse, pensé que esto podría ayudar a algunas personas. Aquí hay un ejemplo usando los modelos de comentarios incorporados de Django donde obtengo una relación inversa con los comentarios del objeto comentado:

Agregue esto al modelo al que se adjuntan los comentarios:

class CmntedObject(models.Model): comments = generic.GenericRelation(Comment, content_type_field=''content_type'', object_id_field=''object_pk'')

y los recursos se ven así:

class UserResource(ModelResource): what ever you need here.... class CmntedObjectResource(ModelResource): comments = fields.ToManyField(''path.to.api.CmntedObjectResource'', ''comments'', full=True, null=True) class Meta: queryset = CmntedObject.objects.all() resource_name = ''cmntedobject'' allowed_methods = [''get'', ''post'', ''delete''] authorization = DjangoAuthorization() class CommentResource(ModelResource): user = fields.ToOneField(''path.to.api.UserResource'', ''user'', full=True) content_type_id = fields.CharField(attribute = ''content_type_id'') site_id = fields.CharField(attribute = ''site_id'') content_object = GenericForeignKeyField({ CmntedObject: CmntedObjectResource, #shown above OtherCmntedObject: OtherCmntedObjectResource, #optional }, ''content_object'', null=True) class Meta: queryset = Comment.objects.all() resource_name = ''cmnt'' allowed_methods = [''get'', ''post'', ''delete''] authorization = DjangoAuthorization() def obj_create(self, bundle, **kwargs): #here we get the current authenticated user as the comment user. bundle = super(CmntResource, self).obj_create(bundle, user=bundle.request.user) return bundle