如何在tastypie中进行POST get_or_create相关资源

时间:2014-09-04 13:31:23

标签: tastypie

我使用Tastypie为Django应用程序创建REST API,并希望能够在一个POST中创建新对象和相关对象。相关对象由用于查找它们的名称指定,如果找不到名称,我想创建新的。

鉴于这样的Django模型:

class Product(Model):
    name = CharField(max_length=32)

class Release(Model):
    product = ForeignKey(to=Product, related_name='releases')
    version = CharField(max_length=32)

这些Tastypie资源:

class ProductResource(ModelResource):
    class Meta:
        queryset = Product.objects.all()
        resource_name = 'product'

class ReleaseResource(ModelResource):
    class Meta:
        queryset = Release.objects.all()
        resource_name = 'release'

    def hydrate_product(self, bundle):
        """Replace product name with id of existing/created one."""
        product = Product.objects.get_or_create(name=bundle.data['product'])
        bundle.data['product'] = product.id
        return bundle

一个空数据库

当我将此数据发布到我的tastypie REST API时:

POST /api/release {
    "product": "Cool Widget",
    "version": "1.2.3",
}

然后我想要创建这些模型对象:

product = Product(name="Cool Widget")
release = Release(product=product, version="1.2.3")

但是我得到一个像这样的例外:

IntegrityError: null value in column "product_id" violates not-null constraint
DETAIL:  Failing row contains (1, null, 1.2.3).

并且不调用hydrate_product()方法。

当我将此类属性添加到R​​eleaseResource时:

product = fields.ToOneField(ProductResource, 'product')

然后我得到这样的东西:

NotFound: An incorrect URL was provided 'Cool Widget' for the 'ProductResource' resource.

如何使用具有该名称的已创建/现有Product对象的URI替换捆绑中的产品名称?

2 个答案:

答案 0 :(得分:3)

我认为我的错误在于试图修改关系字段的目的。如果我的资源实际包含它们,它们应该保持正常工作。

我应该将ReleaseResource.product声明为CharField,并在创建新Release.obj_create时实施Product.objects.get_or_create以使用Product作为相关的Release对象}。

class ReleaseResource(ModelResource):
    product = CharField(attribute='product__name')

    class Meta:
        queryset = Release.objects.all()
        resource_name = 'release'

    def obj_create(self, bundle, **kwargs)
        product = Product.objects.get_or_create(name=bundle.data['product'])[0]
        super(ModelResource, self).obj_create(bundle, product=product, **kwargs)

在doco中似乎不太清楚没有关系字段自动填充ModelResource,您必须明确声明所有关系字段,而不仅仅是反向的。

答案 1 :(得分:0)

下面:

class ReleaseResource(ModelResource):
    class Meta:
        queryset = Release.objects.all()
        resource_name = 'release'

    def hydrate_product(self, bundle):
        """Replace product name with id of existing/created one."""
        product = Product.objects.get_or_create(name=bundle.data['product'])
        bundle.data['product'] = product.id
        return bundle

hydrate_product将不会被触发,因为基于Tastypie字段生成的hydrate_*默认情况下不存在。

我不是100%肯定,但我会尝试这个:

class ReleaseResource(ModelResource):
    class Meta:
        queryset = Release.objects.all()
        resource_name = 'release'

    def hydrate(self, bundle):
        """Replace product name with id of existing/created one."""
        product = Product.objects.get_or_create(name=bundle.data['product'])
        bundle.obj.product = product
        return bundle

注意:我将产品对象分配给bundle.obj.product