Выставлять виртуальное поле во вкусном виде?

Я хочу создать представление с помощью deliciouspie для отображения определенных объектов того же типа, но со следующими поворотами two:

  1. Мне нужно получить объекты, используя три отдельных запроса;
  2. Мне нужно добавить поле, которого нет в базовой модели, и значение этого поля зависит от того, из какого запроса оно пришло; а также
  3. Данные будут для каждого пользователя (поэтому мне нужно подключиться к одному из методов, который получает запрос).

Я не понимаю, как подключиться к жизненному циклу deliciouspie, чтобы добиться этого. Рекомендуемый способ добавления «виртуального» поля — это метод dehydrate, который знает только о пакете, с которым он работает.

Хуже того, нет официального способа присоединиться к наборам запросов.

Моя проблема исчезла бы, если бы я мог заставить deliciouspie принимать что-то, кроме набора запросов. В этом случае я мог бы передать ему список подклассов моего объекта с добавлением дополнительного поля.

Я открыт для любого другого разумного решения.

Изменить: добавлен поворот 3 - данные для каждого пользователя.


person Marcin    schedule 11.06.2011    source источник


Ответы (4)


В последней версии вы должны переопределить метод обезвоживания, например.

def dehydrate(self, bundle):
    bundle.data['full_name'] = bundle.obj.get_full_name()
    return bundle
person matley    schedule 29.06.2011
comment
Фактическая проблема заключается в том, что не всегда возможно получить доступ к request в dehydrate(). Запрос должен храниться в bundle.request, а его там фактически не было раньше, сейчас это исправлено? - person Anton Strogonoff; 02.07.2011
comment
использование bundle.request работает в версии для разработки на сегодняшний день - person ashwoods; 10.11.2011

Наткнулся на аналогичную проблему здесь. В моем случае элементы в списке могут быть «проверены» пользователем.

  • Когда элемент извлекается с помощью AJAX, его проверенный статус возвращается с ресурсом в виде обычного поля.
  • Когда элемент сохраняется на сервере, «отмеченное» поле из ресурса сохраняется в сеансе пользователя.

Сначала я думал, что методы hydrate() и dehydrate() лучше всего подходят для этой работы, но оказалось, что в них есть проблемы с доступом к объекту request. Так что я пошел с alter_data_to_serialize() и obj_update(). Я думаю, что нет необходимости переопределять obj_create(), поскольку я думаю, что элемент нельзя проверить при его первом создании.

Вот код, но обратите внимание, что он еще не был должным образом протестирован.

class ItemResource(ModelResource):
    def get_object_checked_status(self, obj, request):
        if hasattr(request, 'session'):
            session = request.session
            session_data = session.get(get_item_session_key(obj), dict())
            return session_data.get('checked', False)
        return False

    def save_object_checked_status(self, obj, data, request):
        if hasattr(request, 'session'):
            session_key = get_item_session_key(obj)
            session_data = request.session.get(session_key, dict())
            session_data['checked'] = data.pop('checked', False)
            request.session[session_key] = session_data

    # Overridden methods
    def alter_detail_data_to_serialize(self, request, bundle):
        # object > resource
        bundle.data['checked'] = \
            self.get_object_checked_status(bundle.obj, request)
        return bundle

    def alter_list_data_to_serialize(self, request, to_be_serialized):
        # objects > resource
        for bundle in to_be_serialized['objects']:
            bundle.data['checked'] = \
                self.get_object_checked_status(bundle.obj, request)
        return to_be_serialized

    def obj_update(self, bundle, request=None, **kwargs):
        # resource > object
        save_object_checked_status(bundle.obj, bundle.data, request)
        return super(ItemResource, self)\
            .obj_update(bundle, request, **kwargs)

def get_item_session_key(obj): return 'item-%s' % obj.id
person Anton Strogonoff    schedule 25.06.2011

Итак, это мое решение. Код ниже.

Обратите внимание:

  1. В основном вся работа выполняется в obj_get_list. Вот где я запускаю свои запросы, имея доступ к запросу.
  2. Я могу вернуть список из obj_get_list.
  3. Мне, вероятно, пришлось бы переопределить все остальные методы obj_*, соответствующие другим операциям (например, obj_get, obj_create и т. д.), если бы я хотел, чтобы они были доступны.
  4. Поскольку у меня нет queryset в Meta, мне нужно предоставить object_class, чтобы сообщить самоанализу вкусняшки, какие поля предлагать.
  5. Чтобы открыть мой «виртуальный» атрибут (который я создаю в obj_get_list), мне нужно добавить для него объявление поля.
  6. Я закомментировал фильтры и лимиты авторизации, потому что они мне сейчас не нужны. Мне нужно было бы реализовать их самостоятельно, если бы они мне понадобились.

Код:

from tastypie.resources import ModelResource
from tastypie import fields
from models import *
import logging

logger = logging.getLogger(__name__)


class CompanyResource(ModelResource):
    role = fields.CharField(attribute='role')


    class Meta:
        allowed_methods = ['get']
        resource_name = 'companies'
        object_class = CompanyUK
        # should probably have some sort of authentication here quite soon


    #filters does nothing. If it matters, hook them up
    def obj_get_list(self, request=None, **kwargs):
#         filters = {}

#         if hasattr(request, 'GET'):
#             # Grab a mutable copy.
#             filters = request.GET.copy()

#         # Update with the provided kwargs.
#         filters.update(kwargs)
#         applicable_filters = self.build_filters(filters=filters)

        try:
            #base_object_list = self.get_object_list(request).filter(**applicable_filters)
            def add_role(role):
                def add_role_company(link):
                    company = link.company
                    company.role = role
                    return company
                return add_role_company

            director_of = map(add_role('director'), DirectorsIndividual.objects.filter(individual__user=request.user))
            member_of   = map(add_role('member'),   MembersIndividual.objects.filter(individual__user=request.user))
            manager_of  = map(add_role('manager'),  CompanyManager.objects.filter(user=request.user))

            base_object_list = director_of + member_of + manager_of
            return base_object_list #self.apply_authorization_limits(request, base_object_list)
        except ValueError, e:
            raise BadRequest("Invalid resource lookup data provided (mismatched type).")
person Marcin    schedule 12.06.2011
comment
Наткнулся на аналогичную проблему здесь. Просто хочу отметить, что вы также можете переопределить alter_detail_data_to_serialize() и alter_list_data_to_serialize() для добавления виртуальных полей. - person Anton Strogonoff; 25.06.2011

Вы можете сделать что-то вроде этого (не проверено):

def alter_list_data_to_serialize(self, request, data):

    for index, row in enumerate(data['objects']):

        foo = Foo.objects.filter(baz=row.data['foo']).values()
        bar = Bar.objects.all().values()

        data['objects'][index].data['virtual_field'] = bar

    return data
person dan-klasson    schedule 07.07.2013