Джанго вкусный пирог и GenericForeignKey - PullRequest
9 голосов
/ 18 ноября 2011

У меня есть модель страницы с 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')

и

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

Я делаю Page.objects.get (pk = 1) .content_object и получил его.

Помогите мне, пожалуйста, показать ссылку (или вывод в JSON), который привязал объект в REST.

class PageResource(ModelResource):
    content_object = fields.?????

    class Meta:
        queryset = Page.objects.all()
        resource_name = 'page'

Как это сделать правильно?

Спасибо!

Vitaliy

Ответы [ 7 ]

7 голосов
/ 13 декабря 2011

В настоящее время нет простого способа использования общих отношений в вкусном пироге.На на странице вкусного github были представлены некоторые исправления, но они не были объединены на момент написания этой статьи.

Самый простой способ сделать это - определить ресурс типа контента и использовать его для ресурсов.имеющий родовое отношение.Что-то вроде:

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'

Надеюсь, это поможет.

5 голосов
/ 29 февраля 2012

«myresources» - это приложение, которое содержит ContentTypeResource.Если оно находится в том же приложении, что и другие ваши ресурсы, вам не нужно его квалифицировать.Удалено в приведенном ниже коде.

"contrib / contenttype" - это имя ресурса.Установка собственного имени не является обязательной.Tastypie создаст его для вас, если вы не укажете его.Я удалил его в приведенном ниже коде обновления.

Раздел fields = ['model'] ограничивает доступные поля модели, которую представляет этот ресурс.Если вы посмотрите на определение модели ContentType в коде Django, то увидите, что в нем есть поле с именем 'model'.

Я думаю, что в исходном ответе были перепутаны имена полей.Вы пытаетесь создать новый ресурс для content_type и подключить его к внешнему ключу content_type в вашей модели.Приведенный выше код сортирует это.

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'

Вам также необходимо зарегистрировать ContentTypeResource в вашем urls.py, как и во всех других ресурсах:

from myapp.api import ContentTypeResource

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

Бит "myapp" снова является приложением с кодом API, содержащим ContentTypeResource.

Надеюсь, это прояснит ситуацию.Я сам все заработал ...

3 голосов
/ 18 сентября 2012

Похоже, это было официально добавлено в Tastypie месяц назад, посмотрите пример здесь.

https://github.com/toastdriven/django-tastypie/blob/master/docs/content_types.rst

2 голосов
/ 31 июля 2012

Мы взломали код!

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 ''

В результате чего-то вроде:

"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": ""
},
1 голос
/ 16 мая 2012

Это дает вам поле content_object как вложенный объект.Все просто, работает и (к сожалению) настолько эффективно, насколько позволяет технология.

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 голосов
/ 03 марта 2013

Они фактически добавили поддержку этого, как предложил Марио. Так как это потребовало вечности, я подумал, что это может помочь некоторым людям. Вот пример использования встроенных моделей комментариев Django, где я получаю обратную связь с комментариями из объекта с комментариями:

Добавьте это к модели, к которой прикрепляются комментарии:

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

и ресурсы выглядят так:

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
0 голосов
/ 31 июля 2012

Нам удалось получить URI объекта содержимого, если у него был соответствующий ModelResource:

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 ''
...