【问题标题】:django-tastypie: Posting to a Resource having ManytoMany field with through relationshipdjango-tastypie:通过关系发布到具有多对多字段的资源
【发布时间】:2012-11-25 21:44:42
【问题描述】:

我正在为一个项目开发一个 API,并且我通过 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 创建或编辑 Order 对象。由于我在多对多关系中使用直通模型,因此 ManyToManyField(products) 没有 .add() 方法。但是,当向 OrderResource 中的 products 字段发布/放置数据时,tastepie 会尝试调用 .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"}

【问题讨论】:

标签: django tastypie


【解决方案1】:

解决方案在于覆盖资源上的 save_m2m() 方法。在我的情况下,我需要 manytomany 字段仅用于列出,因此重写了 save_m2m() 方法以不做任何事情。

【讨论】:

    【解决方案2】:

    由于您需要 manytomany 字段仅用于列表,因此更好的解决方案是在 OrderResourceproducts 字段上添加 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'
    

    【讨论】:

      【解决方案3】:

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

      class OrderProducts(models.Model): 
          class Meta:
              auto_created = True
      

      如果您无法更改class OrderProducts,请尝试以下美味派补丁。

      ---------------------------- 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 上设置值”。解决方法是一样的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-06-24
        • 2013-04-06
        • 1970-01-01
        • 2012-02-29
        • 2018-08-01
        相关资源
        最近更新 更多