我正在爲博客的標記系統工作。這是一個精簡版的代碼,用於創建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
我使用的是association_proxy
能夠使用傳遞的字符串列表,並把它轉化爲Tag
對象的列表。請注意,字符串至Tag
轉換髮生在tags
屬性設置爲Post
對象時(例如,在實例化對象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',)]
我明白爲什麼會發生這種情況:在第一種情況下,當post2
被創建時,名稱爲Test
的Tag
已經在數據庫中;在第二個中,db.session.new
包含兩個Tag
對象,該對象在提交時沒有被保存。
我不知道的是如何解決它。我想過使用before_flush
SQLAlchemy事件來整合db.session.new
中的Tag
對象,但我無法使其工作。我不確定這是否是正確的策略。
StackOverflow集體智慧是否有任何見解或建議?
太簡單了!謝謝! –