更新查询集时使用模型字段的值进行字符串连接

时间:2017-03-21 17:36:44

标签: python mysql django

我想将某些用户的电子邮件ID更新为:“前缀”+“用户电子邮件的值”

现在我可以为一个用户执行此操作,如下所示:

User.objects.filter(pk=<id>).update(email=Concat(Value("prefix"), 'email'))

然而,只要我在pk列表上过滤,我就会收到一个令人讨厌的错误。查询是:

User.objects.filter(pk__in=<list_id>).update(email=Concat(Value("prefix"), 'email'))

错误是:

/Users/zishanahmad/Devel/Env/venv_sliderule/lib/python2.7/site-packages/django/db/models/query.pyc in update(self, **kwargs)
    561         query.add_update_values(kwargs)
    562         with transaction.atomic(using=self.db, savepoint=False):
--> 563             rows = query.get_compiler(self.db).execute_sql(CURSOR)
    564         self._result_cache = None
    565         return rows

/Users/zishanahmad/Devel/Env/venv_sliderule/lib/python2.7/site-packages/django/db/models/sql/compiler.pyc in execute_sql(self, result_type)
   1060         related queries are not available.
   1061         """
-> 1062         cursor = super(SQLUpdateCompiler, self).execute_sql(result_type)
   1063         try:
   1064             rows = cursor.rowcount if cursor else 0

/Users/zishanahmad/Devel/Env/venv_sliderule/lib/python2.7/site-packages/django/db/models/sql/compiler.pyc in execute_sql(self, result_type)
    838         cursor = self.connection.cursor()
    839         try:
--> 840             cursor.execute(sql, params)
    841         except Exception:
    842             cursor.close()

/Users/zishanahmad/Devel/Env/venv_sliderule/lib/python2.7/site-packages/django/db/backends/utils.pyc in execute(self, sql, params)
     77         start = time()
     78         try:
---> 79             return super(CursorDebugWrapper, self).execute(sql, params)
     80         finally:
     81             stop = time()

/Users/zishanahmad/Devel/Env/venv_sliderule/lib/python2.7/site-packages/django/db/backends/utils.pyc in execute(self, sql, params)
     62                 return self.cursor.execute(sql)
     63             else:
---> 64                 return self.cursor.execute(sql, params)
     65 
     66     def executemany(self, sql, param_list):

/Users/zishanahmad/Devel/Env/venv_sliderule/lib/python2.7/site-packages/django/db/utils.pyc in __exit__(self, exc_type, exc_value, traceback)
     96                 if dj_exc_type not in (DataError, IntegrityError):
     97                     self.wrapper.errors_occurred = True
---> 98                 six.reraise(dj_exc_type, dj_exc_value, traceback)
     99 
    100     def __call__(self, func):

/Users/zishanahmad/Devel/Env/venv_sliderule/lib/python2.7/site-packages/django/db/backends/utils.pyc in execute(self, sql, params)
     62                 return self.cursor.execute(sql)
     63             else:
---> 64                 return self.cursor.execute(sql, params)
     65 
     66     def executemany(self, sql, param_list):

/Users/zishanahmad/Devel/Env/venv_sliderule/lib/python2.7/site-packages/django/db/backends/mysql/base.pyc in execute(self, query, args)
    122         try:
    123             # args is None means no string interpolation
--> 124             return self.cursor.execute(query, args)
    125         except Database.OperationalError as e:
    126             # Map some error codes to IntegrityError, since they seem to be

/Users/zishanahmad/Devel/Env/venv_sliderule/lib/python2.7/site-packages/MySQLdb/cursors.pyc in execute(self, query, args)
    224         except Exception:
    225             exc, value = sys.exc_info()[:2]
--> 226             self.errorhandler(self, exc, value)
    227         self._executed = query
    228         if not self._defer_warnings: self._warning_check()

/Users/zishanahmad/Devel/Env/venv_sliderule/lib/python2.7/site-packages/MySQLdb/connections.pyc in defaulterrorhandler(***failed resolving arguments***)
     34     del connection
     35     if isinstance(errorvalue, BaseException):
---> 36         raise errorvalue
     37     if errorclass is not None:
     38         raise errorclass(errorvalue)

OperationalError: (1093, "You can't specify target table 'auth_user' for update in FROM clause")

我真的不明白错误消息试图说的是什么。任何帮助将不胜感激。

编辑: MySQL版本:5.7.12 Django:1.8

3 个答案:

答案 0 :(得分:0)

<list_id>看起来像什么? User.objects.filter(pk__in=<list_id>)的结果是什么?

在Django 1.10中,我没有遇到问题:

>>> User.objects.filter(pk=1).update(first_name='Test')
1L
>>> User.objects.filter(pk__in=[1, 2]).update(first_name='Test')
2L

至于解决方法,显然它不是那么有效,但为什么不只是缓存QuerySet然后迭代它来更新每个对象?这是(希望)一次性查询,所以我不确定SQL效率有多大关注。

答案 1 :(得分:0)

这应该有效:)

User.objects.filter(pk__in=<list_id>).update(email=Concat(Value("prefix"), F('email')))

答案 2 :(得分:0)

我遇到了同样的问题,但通过尝试将queryset list_ids转换为list()来解决,如下所示:

ids = Transactions.objects.values_list('id', flat=True)
# This may raise error:
User.objects.filter(pk__in=ids).update(first_name='Test')

# But if convert ids to a list, should work:
list_ids = list(ids)
User.objects.filter(pk__in=list_ids).update(first_name='Test')

希望它会有所帮助:)