django-tastypie: связывание ModelResource с ресурсом

#django #django-models #tastypie

#django #django-модели #tastypie

Вопрос:

В настоящее время я пытаюсь django-tastypie разработать RESTful api. Я столкнулся с проблемой:

 # the RevisionObject retrieve commits info through pysvn
# This Resource is fully functionnal (RevisionObject code is not here)
class RevisionResource(Resource):
    id = fields.CharField(attribute='revision')
    description = fields.CharField(attribute='message')
    author = fields.CharField(attribute='author')
    changed_path = fields.ListField(attribute='changed_paths')

    class Meta:
        object_class = RevisionObject
        allowed_methods = ['get']
        resource_name = 'revision'

class RevisionToApplyResource(ModelResource):
    #### here's the problem
    revision = fields.ToManyField(RevisionResource, 'revision')
    ####
    class Meta:
        queryset = RevisionToApply.objects.all()
  

В моих моделях.у меня есть:

 class RevisionToApply(models.Model):
    patch = models.ForeignKey(PatchRequest)
    revision = models.PositiveIntegerField()
    applied = models.BooleanField(default = False)
  

Моя проблема в том, что RevisionToApply models (для django) использует int для ревизии.

Как я могу сказать tastypie использовать поле ревизии RevisionToApplyResource в качестве указателя на RevisionResource? Если TOXXXFIELD предназначено только для связывания с моделями django, каков идеальный момент для вставки ResourceObject ?

Спасибо.

 class NoForeignKeyToOneField(ToOneField):
    def dehydrate(self, bundle):
        try:
            obj_key = getattr(bundle.obj, self.attribute)
            foreign_obj = self.to_class().obj_get(pk=obj_key)
        except ObjectDoesNotExist:
            foreign_obj= None

        if not foreign_obj:
            if not self.null:
                raise ApiFieldError("The model '%r' has an empty attribute"
                   "'%s' and doesn't allow null value." % (bundle.obj,
                   self.attribute))
            return None

        self.fk_resource = self.get_related_resource(foreign_obj)
        fk_bundle = Bundle(obj=foreign_obj, request=bundle.request)
        return self.dehydrate_related(fk_bundle, self.fk_resource)
  

Ответ №1:

Вот как я бы это сделал. Взглянув на то, как ToOneField работает класс, вы заметите, что пара методов hydrate / dehydrate заботится о получении и настройке фактического связанного экземпляра. Разделяя ToOneField и переопределяя эти два метода, вы можете воспользоваться преимуществами автоматической обработки ресурсов Tastypie без фактического внешнего ключа.

(Я имею в ToOneField виду, а не ToManyField потому, что в вашей модели данное RevisionToApply может указывать только на одну ревизию, кажется.)

Это будет выглядеть примерно так:

 class NoForeignKeyToOneField(ToOneField):

    def dehydrate(self, bundle):
        # Look up the related object manually
        try:
            obj_key = getattr(bundle.obj, self.attribute)
            ###
            # Get the revision object here. If you want to make it generic,
            # maybe pass a callable on __init__ that can be invoked here
            ###
            foreign_obj = revision_object
        except ObjectDoesNotExist:
            foreign_obj = None
        # The rest remains the same
        if not foreign_obj:
            if not self.null:
                raise ApiFieldError("The model '%r' has an empty attribute '%s' and doesn't allow a null value." % (bundle.obj, self.attribute))
            return None

        self.fk_resource = self.get_related_resource(foreign_obj)
        fk_bundle = Bundle(obj=foreign_obj, request=bundle.request)
        return self.dehydrate_related(fk_bundle, self.fk_resource)

    def hydrate(self, bundle):
        value = super(NoForeignKeyToOneField, self).hydrate(bundle)

        if value is None:
            return value

        # Here, don't return the full resource, only the primary key
        related_resource = self.build_related_resource(value, request=bundle.request)
        return related_resource.pk
  

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

Комментарии:

1. Это работает для метода обезвоживания. спасибо за советы. У меня все еще возникают проблемы с гидратным.