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.
精彩评论