Ошибка при записи данных в БД
Я пытаюсь записать в таблицу данные, внизу код из файлов. Отношения в бд one-to-many. One user, many documents. views.py Функция, которая обрабатывает запрос создания новой записи в БД
@aiohttp_jinja2.template('document_edit.html')
async def add_document(request) -> Dict[str, str]:
"""Записывает данные в бд"""
if request.method == 'POST':
async with request.app['db'].acquire() as conn:
data = await request.post()
try:
await db.add_document(conn=conn, new_document=data)
except db.AddNewFileProblem as e:
raise web.HTTPNotFound(text=str(e.message))
location = request.app.router['get_document_list'].url_for()
raise web.HTTPFound(location=location)
return {'document': ''}
db.py
import aiopg.sa
from sqlalchemy import (
MetaData, Table, Column, ForeignKey,
Integer, String, DateTime
)
from datetime import datetime
meta = MetaData()
user = Table(
'user', meta,
Column('id', Integer, primary_key=True),
Column('username', String(200), nullable=False),
Column('password_hash', String(100), nullable=False)
)
document = Table(
'document', meta,
Column('id', Integer, primary_key=True),
Column('file_name', String(200), nullable=False),
Column('publish_date', DateTime, nullable=False),
Column('url', String(200), nullable=False),
Column('user_id',
Integer,
ForeignKey('user.id', ondelete='CASCADE'))
)
async def init_pg(app):
conf = app['config']['postgres']
engine = await aiopg.sa.create_engine(
database=conf['database'],
user=conf['user'],
password=conf['password'],
host=conf['host'],
port=conf['port'],
minsize=conf['minsize'],
maxsize=conf['maxsize'],
)
app['db'] = engine
async def close_pg(app):
app['db'].close()
await app['db'].wait_closed()
class AddNewFileProblem(Exception):
"""Возникли проблемы при добавлении записи в БД"""
def __init__(self, message):
self.message = message
async def add_document(conn, new_document):
"""Добавляет элемент в БД"""
await conn.execute(document.insert(), [
{'file_name': str(new_document.get('filename')),
'publish_date': datetime.now(),
'url': str(new_document.get('url')),
'user_id': int(new_document.get('user_id'))}
])
routes.py
from .views import add_document
def setup_routes(app):
app.router.add_get('/document/new/', add_document, name='add_document')
app.router.add_post('/document/new/', add_document, name='add_document')
Отрисовка страницы происходит, и передача данных в тело функции тоже. Но дальше выдается ошибка.
Error handling request
Traceback (most recent call last):
File "/home/ian/Passion/testing_aiohttp/venv/lib/python3.7/site-packages/aiohttp/web_protocol.py", line 418, in start
resp = await task
File "/home/ian/Passion/testing_aiohttp/venv/lib/python3.7/site-packages/aiohttp/web_app.py", line 458, in _handle
resp = await handler(request)
File "/home/ian/Passion/testing_aiohttp/venv/lib/python3.7/site-packages/aiohttp_jinja2/__init__.py", line 122, in wrapped
context = await coro(*args)
File "/home/ian/Passion/testing_aiohttp/test_web_server/views.py", line 46, in add_document
await db.add_document(conn=conn, new_document=data)
File "/home/ian/Passion/testing_aiohttp/test_web_server/db.py", line 82, in add_document
'user_id': int(new_document.get('user_id'))}
File "/home/ian/Passion/testing_aiohttp/venv/lib/python3.7/site-packages/aiopg/sa/connection.py", line 97, in _execute
compiled_parameters = [compiled.construct_params(dp)]
File "/home/ian/Passion/testing_aiohttp/venv/lib/python3.7/site-packages/aiopg/sa/engine.py", line 19, in construct_params
pd = super().construct_params(params, _group_number, _check)
File "/home/ian/Passion/testing_aiohttp/venv/lib/python3.7/site-packages/sqlalchemy/sql/compiler.py", line 693, in construct_params
code="cd3x",
sqlalchemy.exc.InvalidRequestError: A value is required for bind parameter 'id' (Background on this error at: http://sqlalche.me/e/cd3x)
Если перейти по ссылке, то описывается случай, который вообще не помогает. Гуглил sqlalchemy one-to-many - там все примеры описаны в декларативном стиле(через классы), что не рекомендуется в документации aiohttp.
It is possible to configure tables in a declarative style ... But it doesn’t give much benefits later on. SQLAlchemy ORM doesn’t work in asynchronous style and as a result aiopg.sa doesn’t support related ORM expressions such as
Question.query.filter_by(question_text='Why').first() or session.query(TableName).all().
Как создать отношения one-to-many не в декларативном стиле или какую ошибку я допускаю, определяя БД таким образом?
Ответы (1 шт):
Ошибка оказалась простая
Должно быть в файле db.py
async def add_document(conn, new_document):
await conn.execute(
document.insert().values(
{'file_name': str(new_document.get('file_name')),
'publish_date': datetime.now(),
'url': str(new_document.get('url')),
'user_id': int(new_document.get('user_id'))}))
Так написано в официальной документации SQLAlchemy