2012-12-07 10 views
5

pracuję nad API dla projektu i mam relacjami Order/produktów poprzez OrderProducts tak:django-tastypie: Delegowanie do zasobu mającego dziedzinie ManytoMany z pośrednictwem relacji

W 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) 
    ... 

teraz, kiedy załadować zamówieniu przez API chciałbym uzyskać related Products, tak więc to próbowałem (z django tastypie):

W zamówieniu/api.py

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

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

Wszystko działa na liście Zamów zasoby. Dostaję zasoby zamówień z osadzonymi danymi produktu.

Problem polega na tym, że nie mogę tworzyć ani edytować obiektów zamówienia za pomocą api. Ponieważ używam modelu Through w relacji ManytoMany, produkty ManyToManyField (products) nie mają metod .add(). Ale tastypie próbuje wywołać .add() na polu produktów w OrderResource podczas wysyłania/umieszczania w nim danych.

{"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"} 
+0

To pytanie może Ci pomóc: http://stackoverflow.com/questions/10629047/django-tastypie-and-many-to-many-through-relationships – msc

Odpowiedz

3

Rozwiązanie polega na zastąpienie metody save_m2m() na źródło. W moim przypadku potrzebowałem pola manytomany tylko do wpisania, więc przesłoniłem metodę save_m2m(), aby nic nie robić.

5

Ponieważ potrzebne pole manytomany tylko za wystawianie, lepszym rozwiązaniem jest dodanie readonly=True na products dziedzinie OrderResource „s. To eliminuje konieczność nadpisywania metody. Dla kompletności:

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

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

Jeśli wolno modyfikować , dodając auto_created = True może rozwiązać problemu, to znaczy

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

Jeśli nie można zmienić , spróbuj następujące tastypie poprawkę.

---------------------------- 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): 
     """ 

W Django 1.7, komunikat o błędzie zostanie zmieniona na „nie można ustawić wartości na ManyToManyField który określa model pośredni”. Rozwiązanie jest takie samo.

Powiązane problemy