用 Tastypie 覆盖模型字段

Posted

技术标签:

【中文标题】用 Tastypie 覆盖模型字段【英文标题】:Overriding model fields with Tastypie 【发布时间】:2013-07-11 05:09:55 【问题描述】:

在我的一个观点中,我定义了一个 mixin 来根据用户的会话详细信息动态设置多个模型(包括客户端模型)的 techoperator 字段,这样用户就不需要手动填写。这个mixin如下:

class GetTechMixin(object):
    """
    View mixin that when the form is saved, sets the
    site_user and operator.
    """
    def form_valid(self, form):
        # Get user
        user = self.request.user

        # Get tech for this user
        site_user = SiteUser.objects.get(user=user)

        # Override the tech and operator fields
        form.instance.tech = site_user
        form.instance.operator = site_user.operator

        # Save the object
        self.object = form.save()

        # Return success URL
        return HttpResponseRedirect(self.get_success_url())

我还设置了以下 Tastypie API 资源,目的是做同样的事情:

class ClientResource(AbstractModelResource):
    class Meta(AbstractModelResource.Meta):
        queryset = Client.objects.all()
        resource_name = 'client'

    def obj_create(self, bundle, **kwargs):
        # Get tech for this user
        site_user = SiteUser.objects.get(user=bundle.request.user)

        # Override the tech and operator fields
        bundle.obj.tech = site_user
        bundle.obj.operator = site_user.operator

        super(ClientResource, self).obj_create(bundle, **kwargs)

但是,这似乎不起作用。使用 PDB 运行它时,我可以将字段添加到 bundle OK,但是当我让它运行时,它会吐出以下错误:

"error_message": "(1048, \"列'operator_id'不能为空\")", "traceback": "Traceback (最近一次调用最后一次):\n\n 文件 \"/home/matthew/Projects/Myproject/venv/local/lib/python2.7/site-packages/tastypie/resources.py\", 第 217 行,在包装器中\n response = callback(request, *args, **kwargs)\n\n 文件\"/home/matthew/Projects/Myproject/venv/local/lib/python2.7/site-packages/tastypie/resources.py\", 第 459 行,在 dispatch_list\n return self.dispatch('list', request, **kwargs)\n\n 文件\"/home/matthew/Projects/Myproject/venv/local/lib/python2.7/site-packages/tastypie/resources.py\", 第 491 行,在 dispatch\n response = method(request, **kwargs)\n\n File \"/home/matthew/Projects/Myproject/venv/local/lib/python2.7/site-packages/tastypie/resources.py\", 第 1357 行,在 post_list\n updated_bundle = self.obj_create(bundle, **self.remove_api_resource_names(kwargs))\n\n 文件 \"/home/matthew/Projects/Myproject/app_api/api.py\",第 49 行,在 obj_create\n super(ClientResource, self).obj_create(bundle, **kwargs)\n\n 文件\"/home/matthew/Projects/Myproject/venv/local/lib/python2.7/site-packages/tastypie/resources.py\", 第 2150 行,在 obj_create\n 返回 self.save(bundle)\n\n 文件 \"/home/matthew/Projects/Myproject/venv/local/lib/python2.7/site-packages/tastypie/resources.py\", 第 2296 行,在 save\n bundle.obj.save()\n\n 文件中 \"/home/matthew/Projects/Myproject/venv/local/lib/python2.7/site-packages/django/db/models/base.py\", 第 546 行,保存\n force_update=force_update, update_fields=update_fields)\n\n 文件 \"/home/matthew/Projects/Myproject/venv/local/lib/python2.7/site-packages/django/db/models/base.py\", 第 650 行,在 save_base\n 结果 = manager._insert([self], fields=fields, return_id=update_pk, using=using, raw=raw)\n\n 文件 \"/home/matthew/Projects/Myproject/venv/local/lib/python2.7/site-packages/django/db/models/manager.py\", 第 215 行,在 _insert\n 中返回 insert_query(self.model, objs, fields, **kwargs)\n\n 文件\"/home/matthew/Projects/Myproject/venv/local/lib/python2.7/site-packages/django/db/models/query.py\", 第 1661 行,在 insert_query\n 返回 query.get_compiler(using=using).execute_sql(return_id)\n\n 文件 \"/home/matthew/Projects/Myproject/venv/local/lib/python2.7/site-packages/django/db/models/sql/compiler.py\", 第 937 行,在 execute_sql\n cursor.execute(sql, params)\n\n 文件中 \"/home/matthew/Projects/Myproject/venv/local/lib/python2.7/site-packages/django/db/backends/util.py\", 第 41 行,在执行中\n 返回 self.cursor.execute(sql, params)\n\n 文件 \"/home/matthew/Projects/Myproject/venv/local/lib/python2.7/site-packages/django/db/backends/mysql/base.py\", 第 127 行,在执行\n Six.reraise(utils.IntegrityError, utils.IntegrityError(*tuple(e.args)), sys.exc_info()[2])\n\n 文件 \"/home/matthew/Projects/Myproject/venv/local/lib/python2.7/site-packages/django/db/backends/mysql/base.py\", 第 120 行,在执行中\n 返回 self.cursor.execute(query, args)\n\n 文件 \"/home/matthew/Projects/Myproject/venv/local/lib/python2.7/site-packages/MySQLdb/cursors.py\", 第 201 行,在执行中\n self.errorhandler(self, exc, value)\n\n 文件 \"/home/matthew/Projects/Myproject/venv/local/lib/python2.7/site-packages/MySQLdb/connections.py\", 第 36 行,在 defaulterrorhandler\n 中引发错误类, errorvalue\n\nIntegrityError: (1048, \"列 'operator_id' 不能 空\")\n"

添加字段后,无论是否使用 bundle.obj.save(),我都尝试过,但似乎没有什么不同。

obj_create 是覆盖这些值的正确位置吗?如果是这样,任何人都可以指出我哪里出错了。如果没有,我应该在哪里寻找?

【问题讨论】:

检查site_user.operator的值 【参考方案1】:

如果有人发现这个,我找到了解决方案。最简单的做法就是用一个新方法覆盖 obj_create 方法,如下所示:

def obj_create(self, bundle, **kwargs):
    # Get tech for this user
    site_user = SiteUser.objects.get(user=bundle.request.user)

    bundle.obj = self._meta.object_class()

    for key, value in kwargs.items():
        setattr(bundle.obj, key, value)

    # Override the tech and operator fields
    setattr(bundle.obj, 'tech', site_user)
    setattr(bundle.obj, 'operator', site_user.operator)

    self.authorized_create_detail(self.get_object_list(bundle.request), bundle)
    bundle = self.full_hydrate(bundle)
    return self.save(bundle);

【讨论】:

以上是关于用 Tastypie 覆盖模型字段的主要内容,如果未能解决你的问题,请参考以下文章

使用 TastyPie 过滤不同的字段

Django 模型:覆盖字段返回值

如何覆盖抽象模型的 null 和空白字段属性

如何创建作为多个查询联合的 Django 模型字段,以实现覆盖字段?

如何在 django rest 框架 ModelSerializer 中覆盖模型字段验证

Django-Tastypie 过滤所有字段