开发者

django-tastypie: linking a ModelResource to a Resource

开发者 https://www.devze.com 2023-04-11 07:40 出处:网络
I\'m currently trying django-tastypie to design a RESTful api. I\'m facing a problem: # the RevisionObject retrieve commits info through pysvn

I'm currently trying django-tastypie to design a RESTful api. I'm facing a problem:

# 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()

In my models.py I have:

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

My problem is that the RevisionToApply models (for django) uses an int to the revision.

How can I tell tastypie to use the revision field of RevisionToApplyResource as a pointer to a RevisionResource? If the ToXxxxField are only for linking with django models, what is the perfect moment to insert the ResourceObject?

thanks.

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"
              开发者_如何学Python     "'%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)


Here's how I would do it. Taking a look at how the ToOneField class works, you'll notice that the hydrate/dehydrate method pair takes care of getting and setting the actual related instance. By subclassing ToOneField and overriding these two methods, you can get the benefit of Tastypie's automated resource handling without an actual foreign key.

(I'm referring to ToOneField rather than ToManyField because in your model, a given RevisionToApply can only point to one revision, it seems.)

It would look something like this:

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

And then use this field type in your resource rather than the basic ToOneField. I haven't tested it , but I believe the approach is sound, simple and it'll get the job done.

0

精彩评论

暂无评论...
验证码 换一张
取 消