2013-07-18 54 views
2

我正在用Tastypie構建一個API,並且在保存多對多字段時遇到了一個問題。用Tastypie保存M2M字段

我有一個叫Pest的模型調用,另一個叫Call,Call有個叫pests的字段,代表可以應用到一個調用中的有害生物。這些已經存在,用戶可以選擇一個或多個應用於該呼叫 - 無意與Call對象同時創建它們。

默認情況下,我得到以下錯誤,當我試圖通過POST創建一個新的呼叫:

{"error_message": "Cannot resolve keyword 'url' into field. Choices are: baitpoint, call, description, id, name, operator", "traceback": "Traceback (most recent call last):\n\n File \"/home/matthew/Projects/Pestability/venv/local/lib/python2.7/site-packages/tastypie/resources.py\", line 217, in wrapper\n response = callback(request, *args, **kwargs)\n\n File \"/home/matthew/Projects/Pestability/venv/local/lib/python2.7/site-packages/tastypie/resources.py\", line 459, in dispatch_list\n return self.dispatch('list', request, **kwargs)\n\n File \"/home/matthew/Projects/Pestability/venv/local/lib/python2.7/site-packages/tastypie/resources.py\", line 491, in dispatch\n response = method(request, **kwargs)\n\n File \"/home/matthew/Projects/Pestability/venv/local/lib/python2.7/site-packages/tastypie/resources.py\", line 1357, in post_list\n updated_bundle = self.obj_create(bundle, **self.remove_api_resource_names(kwargs))\n\n File \"/home/matthew/Projects/Pestability/venv/local/lib/python2.7/site-packages/tastypie/resources.py\", line 2150, in obj_create\n return self.save(bundle)\n\n File \"/home/matthew/Projects/Pestability/venv/local/lib/python2.7/site-packages/tastypie/resources.py\", line 2300, in save\n m2m_bundle = self.hydrate_m2m(bundle)\n\n File \"/home/matthew/Projects/Pestability/venv/local/lib/python2.7/site-packages/tastypie/resources.py\", line 964, in hydrate_m2m\n bundle.data[field_name] = field_object.hydrate_m2m(bundle)\n\n File \"/home/matthew/Projects/Pestability/venv/local/lib/python2.7/site-packages/tastypie/fields.py\", line 853, in hydrate_m2m\n m2m_hydrated.append(self.build_related_resource(value, **kwargs))\n\n File \"/home/matthew/Projects/Pestability/venv/local/lib/python2.7/site-packages/tastypie/fields.py\", line 653, in build_related_resource\n return self.resource_from_uri(self.fk_resource, value, **kwargs)\n\n File \"/home/matthew/Projects/Pestability/venv/local/lib/python2.7/site-packages/tastypie/fields.py\", line 573, in resource_from_uri\n obj = fk_resource.get_via_uri(uri, request=request)\n\n File \"/home/matthew/Projects/Pestability/venv/local/lib/python2.7/site-packages/tastypie/resources.py\", line 838, in get_via_uri\n return self.obj_get(bundle=bundle, **self.remove_api_resource_names(kwargs))\n\n File \"/home/matthew/Projects/Pestability/venv/local/lib/python2.7/site-packages/tastypie/resources.py\", line 2125, in obj_get\n object_list = self.get_object_list(bundle.request).filter(**kwargs)\n\n File \"/home/matthew/Projects/Pestability/venv/local/lib/python2.7/site-packages/django/db/models/query.py\", line 655, in filter\n return self._filter_or_exclude(False, *args, **kwargs)\n\n File \"/home/matthew/Projects/Pestability/venv/local/lib/python2.7/site-packages/django/db/models/query.py\", line 673, in _filter_or_exclude\n clone.query.add_q(Q(*args, **kwargs))\n\n File \"/home/matthew/Projects/Pestability/venv/local/lib/python2.7/site-packages/django/db/models/sql/query.py\", line 1266, in add_q\n can_reuse=used_aliases, force_having=force_having)\n\n File \"/home/matthew/Projects/Pestability/venv/local/lib/python2.7/site-packages/django/db/models/sql/query.py\", line 1134, in add_filter\n process_extras=process_extras)\n\n File \"/home/matthew/Projects/Pestability/venv/local/lib/python2.7/site-packages/django/db/models/sql/query.py\", line 1332, in setup_joins\n \"Choices are: %s\" % (name, \", \".join(names)))\n\nFieldError: Cannot resolve keyword 'url' into field. Choices are: baitpoint, call, description, id, name, operator\n"} 

所以我當時一看,發現this answer,這似乎涵蓋了類似的情況。我加入了hydrate_pests方法將CallResource類,如下所示:

class AbstractModelResource(ModelResource): 
    class Meta: 
     authorization = DjangoAuthorization() 
     authentication = ApiKeyAuthentication() 
     cache = SimpleCache(timeout=10) 
     always_return_data = True 


class FilteredByOperatorAbstractModelResource(AbstractModelResource): 
    def authorized_read_list(self, object_list, bundle): 
     user = bundle.request.user 
     site_user = SiteUser.objects.get(user=user) 
     return object_list.filter(operator=site_user.operator) 


class PestResource(FilteredByOperatorAbstractModelResource): 
    class Meta(AbstractModelResource.Meta): 
     queryset = Pest.objects.all() 
     resource_name = 'pest' 
     allowed_methods = ['get'] 


class CallResource(AbstractModelResource): 
    client = fields.ForeignKey(ClientResource, 'client') 
    operator = fields.ForeignKey(OperatorResource, 'operator') 
    pests = fields.ManyToManyField(PestResource, 'pests', null=True) 

    class Meta(AbstractModelResource.Meta): 
     queryset = Call.objects.all() 
     resource_name = 'call' 

    def hydrate_pests(self, bundle): 
     pests = bundle.data.get('pests', []) 
     pest_ids = [] 
     for pest in pests: 
      m = re.search('\/api\/v1\/pests\/(\d+)\/', str(pest)) 
      try: 
       id = m.group(1) 
       pest_ids.append(id) 
      except AttributeError: 
       pass 

     bundle.data['pests'] = Pest.objects.filter(id__in=pest_ids) 
     return bundle 

pests場得到通過如下決議:

0: "/api/v1/pests/6/" 
1: "/api/v1/pests/7/" 

而且害蟲網址的正確顯示出來,當我運行bundle.data.get('pests', []) - 如果我使用PDB設置跟蹤,我可以驗證URL是否正在通過,並且Pest.objects.filter(id__in=pest_ids)正在返回正確的項目。但是,雖然HTTP POST請求成功,但是,不會更新害蟲字段以反映新數據。

任何人都可以看到我出錯了嗎?我是否正確地將Pest對象列表傳遞給bundle.data ['pests'],或者這不是我應該如何將這些數據傳遞給該字段?

什麼是真正獲得通過傳遞給bundle.data如下:

{'pests': [<Pest: Rats>, <Pest: Mice>], 'notes': u'Blah', 'first_choice_visit_time': u'2013-07-18T02:02', 'client': u'/api/v1/client/28/', 'date': u'2013-07-18', 'second_choice_visit_time': u'2014-03-03T03:02'} 

回答

2

包數據保存字典。您正在向它傳遞一個QuerySet對象列表。嘗試追加.values()到您的查詢集。

+0

沒有,沒有快樂。我將該行更改爲'bundle.data ['pests'] = Pest.objects.filter(id__in = pest_ids).values()',但這並沒有成功。我已經將'bundle.data'的值添加到了我的問題中,因爲這可能有所幫助。 –

+0

我會嘗試將其轉換爲字典列表,然後。 –