Как исправить ошибку с более чем 3 кавычками при сохранении в базу

При сохранении данных в базу у меня возникает ошибка:

SyntaxError: EOF while scanning triple-quoted string literal

Данные, которые пытаюсь сохранить:

Остров гоага '''
1000 символов и одна святая ложка ''""

Полностью:

products_dict = {('category', 'key:15', 'title:PYTHON'): {'#677': {'title': 'Остров гоага '''', 'description': '1000 символов и одна святая ложка ''""', 'price': '19'}}}

Мой sql-запрос для сохранения (sqlite3):

sql.execute(f'''UPDATE products SET products = "{products_dict}"''')

save.commit()

Какие есть способы решения этой проблемы с сохранением и извлечением?

Для чего это нужно? - я должен иметь возможность сохранять любой текст в базу, с разными кавычками и разным количеством кавычек.


Ответы (2 шт):

Автор решения: gil9red

Странный словарь и странное использование базы данных :)

Странный словарь потому что выглядит очень подозрительно строка 'title': 'Остров гоага '''', почему тройные одинарные кавычки закрывают только справа, а слева их нет? Т.е., у вас просто синтаксически неправильный код, наверняка, в этом месте ошибка скрипта

Исправил словарь, чтобы не было проблем:

products_dict = {
    ('category', 'key:15', 'title:PYTHON'): {
        '#677': {
            'title': 'Остров гоага',
            'description': '1000 символов и одна святая ложка',
            'price': '19'
        }
    }
}

UPD. Варианты исправления синтаксиса с сохранением кавычек в строках:

products_dict = {('category', 'key:15', 'title:PYTHON'): {'#677': {'title': 'Остров гоага \'\'\'', 'description': '1000 символов и одна святая ложка ''""', 'price': '19'}}}

products_dict = {('category', 'key:15', 'title:PYTHON'): {'#677': {'title': "Остров гоага '''", 'description': '1000 символов и одна святая ложка ''""', 'price': '19'}}}

products_dict = {('category', 'key:15', 'title:PYTHON'): {'#677': {'title': """Остров гоага '''""", 'description': '1000 символов и одна святая ложка ''""', 'price': '19'}}}

Насчет базы данных... Первое, что бросается в глаза - вы словарь помещаете в запрос как есть, а синтаксис словаря не поддерживается SQL, поэтому будет такая ошибка:

sqlite3.OperationalError: near "products": syntax error

И не нужно вручную формировать запрос с параметрами, нужно использовать биндинга, вот так:

sql.execute('UPDATE products SET products=?', [products_dict])

Но это полбеды, т.к. sqlite3 не поддерживает тип словаря, будет такая ошибка:

sqlite3.InterfaceError: Error binding parameter 0 - probably unsupported type.

Можно попробовать сохранить словарь в строку, например через JSON, но и тут будет фигня, т.к. у вас словарь специфичный, его ключ составной, поэтому при сохранении в JSON будет ошибка, т.к. в ключах словаря лучше использовать простые типы:

TypeError: keys must be str, int, float, bool or None, not tuple

Это можно обойти, но это будет костылями. Получить строковое представление словаря через str(products_dict), но возникнет проблем парсинга, если понадобится получить обратно, придется парсить чем-то вроде ast.literal_eval из модуля ast:

sql.execute('UPDATE products SET products=?', [str(products_dict)])

Думаю, правильным решением будет создание нескольких таблиц в базе и заполнения их от этого словаря.

Например, таблицы:

  • Product (поля id, title, description, price). От вашего словаря это будут значения: id=677, title='Остров гоага', description='1000 символов и одна святая ложка', price=19
  • Category (поля key, title). Значения: key=15 и title=PYTHON

Если у одного продукта одна категория, то можно в Product хранить категорию в category_id, если категорий несколько, то создать связанную таблицу Product2Category с полями product_id и category_id

→ Ссылка
Автор решения: Roman Konoval

У вас тут комбинация двух проблем

  1. неправильное задание строковых литералов
  2. использование подстановок параметров в строку в sql запросе

Что касается строковых литералов, то для того чтобы задавать абсолюно произвольный стороковый литерал пользуйтесь простым правилом: экранируйте все символы того типа кавычек, который используете для обозначения начала и конца литерала. Вот примеры строк и то как их нужно задавать в виде строкового литерала в коде (я тут использую одинарную кавычку, но то же самое применимо и к двойным):

+----------------------------------------+----------------------------------------
 Строка                                  | Литерал                             
-----------------------------------------+----------------------------------------
 abc                                     | 'abc'                                  
 Остров гоага '''                        | 'Остров гоага \'\'\''                
 1000 символов и одна святая ложка ''""  | '1000 символов и одна святая ложка \'\'""'

Простой способ увидеть этот литерал это заставить питон конвертировать строку с помощью input() (способ годится если нет переводов строки). То есть исполнить в терминале:

>>> x=input()

Потом ввести или вставить текст:

1000 символов и одна святая ложка ''""

В переменной х теперь строка и если вывести ее представление, то она будет в экранированном виде (в таком какой нужно использовать для задания литерала):

>>> print(repr(x))
'1000 символов и одна святая ложка \'\'""'

Для сохранения в БД dict-а, как строки, нужно его сначала сериализовать. Можно делать по разному. Простой споcоб это использовать str:

products_dict_str = str(products_dict)

При загрузке из БД нужно будет строку десериализовать с помощью literal_eval:

products_dict = ast.literal_eval(products_dict_str)

Во-вторых, нужно использовать связываемые переменные, а не манипуляции со строками:

sql.execute('UPDATE products SET products=?', [products_dict_str])
→ Ссылка