Django ORM необработанный запрос на удаление, не удаляющий записи - PullRequest
0 голосов
/ 02 марта 2019

Я использую raw_sql запросов для моего удобства, чтобы сохранить базу данных минимальной. Я удаляю лишние записи.По этому запросу

#d is from a loop and has values
res=MyModel.objects.raw("DELETE FROM mydb_mymodel WHERE mydb_mymodel.s_type = '%s' and mydb_mymodel.barcode = '%s' and mydb_mymodel.shopcode = '%s' and mydb_mymodel.date = '%s'" ,[d.s_type,d.barcode,d.shopcode,d.date])

Это не удаление записей в базе данных, а

, когда я выполняю res.query и запускаю его из консоли postgres, это работает!

Да, я могу использовать

MyModel.objects.filter(s_type=d.s_type,barcode=d.barcode,
shopcode=d.shopcode,date=d.date).delete()

но чего мне не хватает в raw_sql ?

1 Ответ

0 голосов
/ 02 марта 2019

A .raw(..) - это , а не выполняется с нетерпением, как и большинство запросов Django ORM, выполняемых лениво.Таким образом, он возвращает RawQuerySet объект с запросом в объекте.Например:

>>> User.objects.raw('BLA BLA BLA', [])
<RawQuerySet: BLA BLA BLA>

Запрос, подобный BLA BLA BLA, не имеет никакого смысла: в нем возникнет ошибка базы данных, но мы все равно получим RawQuerySet.

Вы можете принудительно выполнить оценкунапример, перебрав его, мы получим:

>>> list(User.objects.raw('BLA BLA BLA', []))
Traceback (most recent call last):
  File "/djangotest/env/lib/python3.6/site-packages/django/db/backends/utils.py", line 85, in _execute
    return self.cursor.execute(sql, params)
  File "/djangotest/env/lib/python3.6/site-packages/django/db/backends/mysql/base.py", line 71, in execute
    return self.cursor.execute(query, args)
  File "/djangotest/env/lib/python3.6/site-packages/MySQLdb/cursors.py", line 250, in execute
    self.errorhandler(self, exc, value)
  File "/djangotest/env/lib/python3.6/site-packages/MySQLdb/connections.py", line 50, in defaulterrorhandler
    raise errorvalue
  File "/djangotest/env/lib/python3.6/site-packages/MySQLdb/cursors.py", line 247, in execute
    res = self._query(query)
  File "/djangotest/env/lib/python3.6/site-packages/MySQLdb/cursors.py", line 412, in _query
    rowcount = self._do_query(q)
  File "/djangotest/env/lib/python3.6/site-packages/MySQLdb/cursors.py", line 375, in _do_query
    db.query(q)
  File "/djangotest/env/lib/python3.6/site-packages/MySQLdb/connections.py", line 276, in query
    _mysql.connection.query(self, query)
_mysql_exceptions.ProgrammingError: (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'BLA BLA BLA' at line 1")

Таким образом, list(..) форсирует оценку, и теперь база данных, конечно, выдает ошибку.Однако даже если бы это был действительный запрос DELETE, он все равно вызвал бы ошибку, поскольку такой запрос не возвращает никакой записи.

Для выполнения вызовов DELETEВ руководстве по Django указано, что вы должны использовать курсор [Django-doc] :

from django.db import connection

with connection.cursor() as cursor:
    cursor.execute(
        "DELETE FROM mydb_mymodel WHERE s_type = '%s' AND barcode = '%s' AND shopcode = '%s' AND date = '%s'" ,
        [d.s_type,d.barcode,d.shopcode,d.date]
    )

Но я думаю, что, вероятно, намного проще указать его следующим образом:

MyModel.objects.filter(
    s_type=d.s_type,
    barcode=d.barcode,
    shopcode=d.shopcode,
    date=d.date
).delete()

Это создаст запрос DELETE и правильно сериализует параметры.Запрос .delete() выполняется с нетерпением, поэтому вероятность совершения вышеописанных ошибок намного ниже: если ORM реализован правильно, нам не нужно об этом беспокоиться.

...