私はブログ用のタグ付けシステムで作業しています。 Flaskアプリオブジェクトと関連するPost
とTag
モデルを作成するコードを取り除いたものです。多対多関係:取得または作成
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.ext.associationproxy import association_proxy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.sqlite'
db = SQLAlchemy(app)
post_tags = db.Table('post_tags',
db.Column('post_id', db.Integer,
db.ForeignKey('posts.id'),
nullable=False),
db.Column('tag_id', db.Integer,
db.ForeignKey('tags.id'),
nullable=False),
db.PrimaryKeyConstraint('post_id', 'tag_id'))
class Tag(db.Model):
__tablename__ = 'tags'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(30), nullable=False, unique=True)
@classmethod
def get_or_create(cls, name):
return cls.query.filter_by(name=name).scalar() or cls(name=name)
class Post(db.Model):
__tablename__ = 'posts'
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(80), nullable=False)
content = db.Column(db.Text, nullable=False)
_tags = db.relationship('Tag', secondary=post_tags)
tags = association_proxy('_tags', 'name', creator=Tag.get_or_create)
def __init__(self, title, content, tags=None):
self.title = title
self.content = content
self.tags = tags
私は文字列のリストを渡すと、それはTag
オブジェクトのリストに変換する必要があり使用できるようにassociation_proxy
を使用しています。文字列Tag
の変換は、Post
オブジェクトにtags
プロパティが設定されているときに発生します(たとえば、Post
オブジェクトがインスタンス化された時点)。
、Pythonのコンソールで次の作品以上のモジュールからすべてをインポートした後:
>>> app.app_context().push()
>>> db.create_all()
>>> post1 = Post('Test', 'A test post', tags=['Test', 'Foo'])
>>> db.session.add(post1)
>>> db.session.commit()
>>> post2 = Post('A second test', 'Another test post', tags=['Test'])
>>> db.session.add(post2)
>>> db.session.commit()
を次のように、しかし、失敗します。
>>> app.app_context().push()
>>> db.create_all()
>>> post1 = Post('Test', 'A test post', tags=['Test', 'Foo'])
>>> post2 = Post('A second test', 'Another test post', tags=['Test'])
>>> db.session.add(post1)
>>> db.session.add(post2)
>>> db.session.commit()
最後の行は、上のUNIQUE
制約と文句を言いTag.name
が失敗する:
sqlalchemy.exc.IntegrityError: (sqlite3.IntegrityError) UNIQUE constraint failed:
tag.name [SQL: 'INSERT INTO tag (name) VALUES (?)'] [parameters: ('Test',)]
なぜこのようなことが起こるのですか?最初のケースではTest
という名前のTag
はpost2
が作成された時点ですでにデータベースにあります。 2番目の場合、db.session.new
には、その名前のオブジェクトがコミット時に保持されていない2つのオブジェクトが含まれています。
私はそれを修正する方法がわかりません。 before_flush
SQLAlchemyイベントを使用してオブジェクトをdb.session.new
に統合しようと思ったが、動作させることができなかった。それが正しい戦略であるかどうかはわかりません。
StackOverflow集合知は洞察力や推奨事項を持っていますか?
とても簡単です!ありがとう! –