我正在尝试使用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()
在我的models.py中,我有:
class RevisionToApply(models.Model):
patch = models.ForeignKey(PatchRequest)
revision = models.PositiveIntegerField()
applied = models.BooleanField(default = False)
我的问题是RevisionToApply模型(对于django)使用int来修改。
如何告诉tastypie使用RevisionToApplyResource的revision字段作为指向RevisionResource的指针?如果ToXxxxField仅用于链接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)
答案 0 :(得分:2)
这是我将如何做到的。看一下ToOneField
类是如何工作的,你会注意到水合物/脱水方法对负责获取和设置实际的相关实例。通过继承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
。我没有对它进行过测试,但我相信这种方法听起来很简单,而且可以完成工作。