0

こんにちは私はtastypieを使用してプロジェクトのRESTAPIを公開していて、リソースのエンドポイントを実装する方法に固執しているので、ここに私の問題があります:

私は次のモデルを持っています、

class Product(models.Model):
    # fields...

class Order(models.Model):
    products = models.ManyToManyField('Product', through='OrderProduct')
    # other fields...

class OrderProduct(models.Model):
    order      = models.ForeignKey('Order')
    product    = models.ForeignKey('Product')
    quantity   = models.IntegerField()
    unit_price = models.FloatField()

    class Meta:
        unique_together = ['order', 'product']

および次のリソース、

class ProductResource(ModelResource):
    class Meta:
        resource_name = 'products'
        queryset = Product.objects.all()
        allowed_methods = ['get']

class OrderResource(ModelResource):
    products = fields.ToManyField('agro.api.OrderProductResource', 'orderproduct_set', related_name='product', full=True)

    class Meta:
        resource_name = 'orders'
        queryset = Order.objects.all()
        list_allowed_methods = ['get', 'post']
        detail_allowed_methods = ['get', 'put', 'delete']
        authentication = Authentication() # only for testing purposes
        authorization = Authorization() # only for testing purposes

    class OrderProductResource(ModelResource):
        product = fields.ForeignKey('agro.api.ProductResource', 'product')

        class Meta:
            resource_name = 'orderproducts'
            queryset = OrderProduct.objects.all()
            allowed_methods = ['get']
            include_resource_uri = False
            authentication = Authentication() # only for testing purposes
            authorization = Authorization()  # only for testing purposes

次のリクエストデータを使用して/orders/エンドポイントにPOSTしようとすると

{
    "products": [
        {
            "product": "/products/1/",
            "quantity": 4,
            "unit_price": 5
        }
    ]
}

次のエラートレースバックが表示されます

{
    "error_message": "orderproduct.order_id may not be NULL",
    "traceback": "Traceback (most recent call last):\n\n  File \"c:\\Python27\\lib\\site-packages\\tastypie\\resources.py\", line 192, in wrapper\n    response = callback(request, *args, **kwargs)\n\n  File \"c:\\Python27\\lib\\site-packages\\tastypie\\resources.py\", line 397, in dispatch_list\n    return self.dispatch('list', request, **kwargs)\n\n  File \"c:\\Python27\\lib\\site-packages\\tastypie\\resources.py\", line 427, in dispatch\n    response = method(request, **kwargs)\n\n  File \"c:\\Python27\\lib\\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 \"c:\\Python27\\lib\\site-packages\\tastypie\\resources.py\", line 1784, in obj_create\n    self.save_m2m(m2m_bundle)\n\n  File \"c:\\Python27\\lib\\site-packages\\tastypie\\resources.py\", line 1951, in save_m2m\n    related_bundle.obj.save()\n\n  File \"c:\\Python27\\lib\\site-packages\\django\\db\\models\\base.py\", line 463, in save\n    self.save_base(using=using, force_insert=force_insert, force_update=force_update)\n\n  File \"c:\\Python27\\lib\\site-packages\\django\\db\\models\\base.py\", line 551, in save_base\n    result = manager._insert([self], fields=fields, return_id=update_pk, using=using, raw=raw)\n\n  File \"c:\\Python27\\lib\\site-packages\\django\\db\\models\\manager.py\", line 203, in _insert\n    return insert_query(self.model, objs, fields, **kwargs)\n\n  File \"c:\\Python27\\lib\\site-packages\\django\\db\\models\\query.py\", line 1593, in insert_query\n    return query.get_compiler(using=using).execute_sql(return_id)\n\n  File \"c:\\Python27\\lib\\site-packages\\django\\db\\models\\sql\\compiler.py\", line 912, in execute_sql\n    cursor.execute(sql, params)\n\n  File \"c:\\Python27\\lib\\site-packages\\django\\db\\backends\\util.py\", line 40, in execute\n    return self.cursor.execute(sql, params)\n\n  File \"c:\\Python27\\lib\\site-packages\\django\\db\\backends\\sqlite3\\base.py\", line 344, in execute\n    return Database.Cursor.execute(self, query, params)\n\nIntegrityError: orderproduct.order_id may not be NULL\n"
}

ご覧のとおり、新しいOrderProductが関連する注文を指定していません。私が達成しようとしているのは、同じPOSTリクエストで作成されたネストされたOrderProductデータを使用してOrderリソースを投稿することです。

そして、OrderProductによって参照される注文が現在作成されている注文であることをどのように指定できますか?最も慣用的なアプローチは何ですか、ハイドレートをオーバーライドします(この時点で私がdjango orm注文オブジェクトインスタンスを持っているかどうかはわかりませんが、結果的に可能ですこれを行うには)関連するモデルの順序を設定したり、hydrate_m2mまたはsave_m2mを再実装したりするために、それを行う方法についての推測はありますか?

4

1 に答える 1

0

答えてくれてありがとう、私は本当に注文がありませんが、私の場合、このデータは作成される注文と、中間テーブル OrderProduct(json products field) に入力する関連データを表す方法である必要があります。 API のユーザーは、注文に関する情報と関連データを同じリクエストで渡します。たとえば、新しい注文を作成する場合、ユーザーは次のデータとともに POST します。

{
    "products": {
        "product": "/products/1",
        "quantity": 4,
        "unit_price": 5
    }
}

これらのデータは、次のデータベース レジスタを生成する必要があります。

Order
    # with and auto generated id

OrderProduct
    order # which points to the auto generated id
    product # points to a previous registered product

注文フィールドを渡すと、現時点で有効な ID がありません (鶏卵の問題のようなものです)。注文がまだデータベースに保存されていないためです。tastypie データフローは ModelResource.obj_save メソッドに注文を保存し、そのメソッドは、例外が発生した OrderProduct レジスタを作成する ModelResource.save_m2m を呼び出します。

そのため、save_m2m が OrderProduct を保存しようとする前に、その参照を暗黙的に設定するために、どの Tastypie フックを実装する必要があるかを知る必要があります。

于 2013-01-09T16:57:12.133 に答える