2011-11-18 19 views
9

Tengo el modelo de página con GFK.Django tastypie y GenericForeignKey

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 conseguí.

Ayúdeme por favor para 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

+1

¿Alguna vez ha funcionado sin aplicar los parches a tastypie? –

Respuesta

7

Hay actualmente no hay manera fácil usando las relaciones genéricas en tastypie. Se han enviado algunos parches al tastypie github page, pero no se han fusionado al momento de escribir estas líneas.

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 en la línea de:

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.

+0

Estoy tratando de implementar esto ahora. ¿Podrían proporcionarme un poco más de contexto para ayudarme a entenderlo? Tengo un Aditivo, que tiene una relación genérica con Atributos. Me gustaría obtener todos los atributos para un aditivo dado. en su ejemplo, ¿a qué se refieren 'mis recursos', 'contrib/contenttype', 'modelo'? Gracias. –

+0

Solo una nota de algo que me estaba molestando sobre la implementación de esto: si está usando relaciones genéricas inversas, no puede olvidar usar fieldss.ToManyField en el modelo que está accediendo al recurso genérico. – Wilerson

5

La opción "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 representa este recurso. 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 vas a necesitar para registrar ContentTypeResource en su urls.py como que tiene con todos sus otros recursos:

from myapp.api import ContentTypeResource 

v1_api = Api(api_name='v1') 
v1_api.register(ContentTypeResource()) 

El "miaplicacion" es poco más la aplicación con la API código que contiene ContentTypeResource.

Espero que esto aclare las cosas. Acabo de hacerlo funcionar ...

1

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 
0

Hemos conseguido el obtener el URI del objeto de contenido, si tuviera 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 '' 
2

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": "" 
}, 
0

De hecho, han añadido 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 modelos de comentario incorporadas de Django donde consigo una relación inversa a los comentarios del objeto comentado:

Esto, unido al modelo que los comentarios se vinculan con:

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

y los recursos mira esto:

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 
Cuestiones relacionadas