django tastypie:通过关系发布到具有多个字段的资源

django tastypie:通过关系发布到具有多个字段的资源,django,tastypie,Django,Tastypie,我正在为一个项目开发API,我通过OrderProducts与OrderProducts建立了如下关系: 在models.py中 class Product(models.Model): ... class Order(models.Model): products = models.ManyToManyField(Product, verbose_name='Products', through='OrderProducts') ... class OrderPro

我正在为一个项目开发API,我通过OrderProducts与OrderProducts建立了如下关系:

在models.py中

class Product(models.Model):
    ...

class Order(models.Model):
    products = models.ManyToManyField(Product, verbose_name='Products', through='OrderProducts')
    ...

class OrderProducts(models.Model):
    order = models.ForeignKey(Order)
    product = models.ForeignKey(Product)
    ...
现在,当我通过API加载订单时,我也想获得相关的产品,所以我尝试了这个(使用django tastypie):

按顺序/api.py

class OrderResource(ModelResource):
    products = fields.ToManyField('order.api.ProductResource', products, full=True)

    class Meta:
        queryset = Order.objects.all()
        resource_name = 'order'
一切都适用于列出订单资源。我获得嵌入产品数据的订单资源

问题是我无法使用api创建或编辑订单对象。由于我在ManytoMany关系中使用的是直通模型,所以ManyToManyField(products)没有.add()方法。但是,当向OrderResource发布/放置数据时,tastypie正在尝试在products字段上调用.add()

{"error_message": "'ManyRelatedManager' object has no attribute 'add'", "traceback": "Traceback (most recent call last):\n\n  File \"/Library/Python/2.7/site-packages/tastypie/resources.py\", line 192, in wrapper\n    response = callback(request, *args, **kwargs)\n\n  File \"/Library/Python/2.7/site-packages/tastypie/resources.py\", line 397, in dispatch_list\n    return self.dispatch('list', request, **kwargs)\n\n  File \"/Library/Python/2.7/site-packages/tastypie/resources.py\", line 427, in dispatch\n    response = method(request, **kwargs)\n\n  File \"/Library/Python/2.7/site-packages/tastypie/resources.py\", line 1165, in post_list\n    updated_bundle = self.obj_create(bundle, request=request, **self.remove_api_resource_names(kwargs))\n\n  File \"/Library/Python/2.7/site-packages/tastypie/resources.py\", line 1784, in obj_create\n    self.save_m2m(m2m_bundle)\n\n  File \"/Library/Python/2.7/site-packages/tastypie/resources.py\", line 1954, in save_m2m\n    related_mngr.add(*related_objs)\n\nAttributeError: 'ManyRelatedManager' object has no attribute 'add'\n"}

解决方案在于覆盖资源上的save_m2m()方法。在我的例子中,我只需要列出manytomany字段,因此重写save_m2m()方法而不执行任何操作

因为您只需要在列表中使用manytomany字段,所以更好的解决方案是在
OrderResource
产品
字段中添加
readonly=True
。这样就不需要重写
save_m2m
方法。完整性:

class OrderResource(ModelResource):
    products = fields.ToManyField('order.api.ProductResource', products, 
                                  readonly=True, full=True)

    class Meta:
        queryset = Order.objects.all()
        resource_name = 'order'

如果允许您修改
类OrderProducts
,添加
auto_created=True
可能会解决您的问题,即

class OrderProducts(models.Model): 
    class Meta:
        auto_created = True
如果无法更改
类OrderProducts
,请尝试以下tastypie修补程序

---------------------------- tastypie/resources.py ----------------------------
index 2cd869e..aadf874 100644
@@ -2383,7 +2383,20 @@ class BaseModelResource(Resource):
                     related_resource.save(updated_related_bundle)
                 related_objs.append(updated_related_bundle.obj)

-            related_mngr.add(*related_objs)
+            if hasattr(related_mngr, 'through'):
+                through = getattr(related_mngr, 'through')
+                if not through._meta.auto_created:
+                    for related_obj in related_objs:
+                        args = dict()
+                        args[related_mngr.source_field_name] = bundle.obj
+                        args[related_mngr.target_field_name] = related_obj
+                        through_obj = through(**args)
+                        through_obj.save()
+                else:
+                    related_mngr.add(*related_objs)
+            else:
+                related_mngr.add(*related_objs)

     def detail_uri_kwargs(self, bundle_or_obj):
         """
在Django 1.7中,错误消息更改为“无法在指定中间模型的ManyToManyField上设置值”。答案是一样的。

这个问题可能会帮助您: