【问题标题】:Saving M2M field with Tastypie用 Tastypie 保存 M2M 领域
【发布时间】:2013-07-17 04:45:01
【问题描述】:

我正在使用 Tastypie 构建 API,但在保存多对多字段时遇到了问题。

我有一个模型调用 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,似乎涵盖了类似的情况。我在 CallResource 类中添加了hydrate_pests 方法,如下:

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', []) 时,害虫 URL 正确显示 - 如果我使用 PDB 设置跟踪,我可以验证 URL 是否正在通过,并且 Pest.objects.filter(id__in=pest_ids) 正在返回正确的项目。然而,尽管 HTTP POST 请求成功,但没有更新pestic 字段以反映新数据。

谁能看到我哪里出错了?我将 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'}

【问题讨论】:

    标签: django tastypie


    【解决方案1】:

    捆绑数据包含字典。您正在向它传递一个 QuerySet 对象列表。尝试将 .values() 附加到您的查询集。

    【讨论】:

    • 不,不快乐。我将该行更改为bundle.data['pests'] = Pest.objects.filter(id__in=pest_ids).values(),但这并没有成功。我已将 bundle.data 的值添加到我的问题中,因为这可能会有所帮助。
    • 我会尝试将其转换为字典列表。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多