отношения многие ко многим в sqlalchemy

Я только что переключился с MySQL на SQLalchemy и должен сказать, что понять sqlalchemy сложнее, чем я думал. В настоящее время у меня есть некоторые проблемы с отношениями «многие ко многим». У меня есть пользователи и запросы в моей модели. У пользователя может быть много запросов, и запрос предлагает новую статью для чтения каждый день. Я хочу сохранить, какой пользователь прочитал какой запрос в какую дату. Мои модели.py выглядят так

class User(db.Model):

    id = db.Column(db.Integer, primary_key=True)
    read_dates = db.relationship("ReadIndex", backref="user")

    def __repr__(self):
        return '<User %r>' % (self.id)

class Queries(db.Model):

    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))

    def __repr__(self):
        return '<Queries %r>' % (self.id)


class ReadIndex(db.Model):

    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), primary_key=True)
    query_id = db.Column(db.Integer, db.ForeignKey('queries.id'), primary_key=True)
    read_datetime = db.Column(db.DateTime)
    read_query = db.relationship("Queries", backref="user_assocs")

    def __repr__(self):
        return '<ReadIndex>'

поэтому у меня есть пользователи и запросы. Чтобы сохранить, какой пользователь прочитал какой запрос и в какую дату, у меня есть класс ReadIndex, в котором есть дополнительное поле, называемое read_datetime, где я храню дату ассоциации пользователя с запросом. Я хочу добавить такую ​​​​ассоциацию, как

user = models.User.query.filter_by(id=user_id).first()
query = models.Queries.query.filter_by(id=query_id).first()
a = models.ReadIndex(read_datetime=dt.utcnow())
a.read_query = query
user.read_dates.append(a)
db.session.commit()

где query_id и user_id — соответствующие идентификаторы для выбора моих объектов. Если я запускаю это, я получаю сообщение об ошибке

sqlalchemy.exc.IntegrityError
IntegrityError: (sqlite3.IntegrityError) NOT NULL constraint failed:
read_index.query_id [SQL: u'INSERT INTO read_index (user_id, read_datetime) 
VALUES (?, ?)'] [parameters: (1, '2015-07-29 20:55:50.898366')]

Я не уверен, в чем проблема? Кажется, я не нарушаю никаких NOT NULL

редактировать: я заметил, что я назначил query=None для a.read_query. Исправление этого немного изменило ошибку

IntegrityError: (raised as a result of Query-invoked autoflush;  
consider using a session.no_autoflush block if this flush is occurring prematurely) 
(sqlite3.IntegrityError) NOT NULL constraint failed: read_index.user_id 
[SQL: u'INSERT INTO read_index (query_id, read_datetime) VALUES (?, ?)'] 
[parameters: (1, '2015-07-29 23:11:11.934038')]

вот именно что происходит:

>>> from app import app, db, models
>>> user = models.User.query.filter_by(id=1).first()
>>> user
<User u'Florian Beutler'>
>>> query = models.Queries.query.filter_by(id=1).first()
>>> query
<Queries 1>
>>> import datetime
>>> a = models.ReadIndex(read_datetime=datetime.datetime.utcnow())
>>> a.read_query = query
>>> user.read_dates.append(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python2.7/site-    packages/sqlalchemy/orm/attributes.py", line 237, in __get__
    return self.impl.get(instance_state(instance), dict_)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/attributes.py", line 578, in get
    value = self.callable_(state, passive)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/strategies.py", line 529, in _load_for_state
    return self._emit_lazyload(session, state, ident_key, passive)
  File "<string>", line 1, in <lambda>
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/strategies.py", line 599, in _emit_lazyload
    result = q.all()
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 2399, in all
    return list(self)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/query.py", line 2515, in __iter__
    self.session._autoflush()
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 1292, in _autoflush
    util.raise_from_cause(e)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/util/compat.py", line 199, in raise_from_cause
    reraise(type(exception), exception, tb=exc_tb)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 1282, in _autoflush
    self.flush()
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 2004, in flush
    self._flush(objects)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 2122, in _flush
    transaction.rollback(_capture_exception=True)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/util/langhelpers.py", line 60, in __exit__
    compat.reraise(exc_type, exc_value, exc_tb)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/session.py", line 2086, in _flush
    flush_context.execute()
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/unitofwork.py", line 373, in execute
    rec.execute(self)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/unitofwork.py", line 532, in execute
    uow
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/persistence.py", line 174, in save_obj
mapper, table, insert)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/orm/persistence.py", line 781, in _emit_insert_statements
    execute(statement, params)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 914, in execute
    return meth(self, multiparams, params)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/sql/elements.py", line 323, in _execute_on_connection
    return connection._execute_clauseelement(self, multiparams, params)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1010, in _execute_clauseelement
    compiled_sql, distilled_params
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1146, in _execute_context
    context)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1341, in _handle_dbapi_exception
    exc_info
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/util/compat.py", line 199, in raise_from_cause
    reraise(type(exception), exception, tb=exc_tb)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/engine/base.py", line 1139, in _execute_context
    context)
  File "/usr/local/lib/python2.7/site-packages/sqlalchemy/engine/default.py", line 450, in do_execute
    cursor.execute(statement, parameters)
sqlalchemy.exc.IntegrityError: (raised as a result of Query-invoked autoflush; consider using a session.no_autoflush block if this flush is occurring prematurely) (sqlite3.IntegrityError) NOT NULL constraint failed: read_index.user_id [SQL: u'INSERT INTO read_index (query_id, read_datetime) VALUES (?, ?)'] [parameters: (1, '2015-07-29 23:17:06.013485')]

ограничение? спасибо карл


person carl    schedule 29.07.2015    source источник


Ответы (2)


Метод .first() либо возвращает первый результат, либо None, если его нет. Вы уверены, что не присваиваете a.read_query None?

person fishsticks    schedule 29.07.2015
comment
Привет, рыбка, спасибо за ответ. Действительно, изначально я присвоил None, но исправление этого не решило проблему. Я обновил сообщение выше, чтобы показать, что я имею в виду - person carl; 30.07.2015

Вы получаете эту ошибку, потому что поля user_id и query_id таблицы ReadIndex равны None. Таким образом, когда вы совершаете коммит, объект ReadIndex пытается создаться без значений в полях первичного ключа. Итак, сделай это,

user = models.User.query.filter_by(id=user_id).first()
query = models.Queries.query.filter_by(id=query_id).first()
a=models.ReadIndex(user_id=user.id,query_id=query.id,read_datetime=dt.utcnow())
db.session.add(a)
db.session.commit()

Вам не нужно вручную добавлять что-либо к отношениям. SQLAlchemy сделает это за вас автоматически. Вы можете перепроверить, если хотите,

for ud in user.read_dates:
    print(ud)

Надеюсь это поможет!

person Chandan Purohit    schedule 02.01.2017