检查数据库模型的唯一性。通过Flask-SQLAlchemy实现INSERT OR IGNORE

2 投票
3 回答
1927 浏览
提问于 2025-04-18 04:21

我有个问题,想知道怎么往数据库里添加新的但又是唯一的项目。

app = Flask(__name__, template_folder='templates')
app.config.from_object('config')
db = SQLAlchemy(app)

这些类看起来像是多对多的实现:

connections = db.Table('connections', db.metadata,
    db.Column('book_id', db.Integer, db.ForeignKey('books.id')),
    db.Column('author_id', db.Integer, db.ForeignKey('authors.id'))
)

class Author(db.Model):
    __tablename__ = 'authors'
    __searchable__ = ['a_name']
    __table_args__ = {'sqlite_autoincrement': True,}

    id = db.Column(db.Integer, primary_key=True)
    a_name = db.Column(db.String(80), unique=True)

    def __repr__(self):
        return unicode(self.a_name)


class Book(db.Model):
    __tablename__ = 'books'
    __searchable__ = ['b_name']
    __table_args__ = {'sqlite_autoincrement': True,}

    id = db.Column(db.Integer, primary_key=True)
    b_name = db.Column(db.String(80), unique=True)
    authors = db.relationship('Author', secondary=lambda: connections,
                                                    backref=db.backref('books'))

    def __repr__(self):
        return unicode(self.b_name)

我只想添加唯一的数据库项目。如果我写了这段代码:

author = Author(a_name = "Author1")
book = Book(b_name = "Book1")
author.books.append(book)
db.session.add(author)
db.session.add(book)
db.session.commit()

如果我们的数据库里已经有一个作者,名字是 "Author1",那么就会出现错误。

IntegrityError: (IntegrityError) column a_name is not unique u'INSERT INTO authors (a_name) VALUES (?)' (u'\u0410\u0432\u0442\u043e\u04402',)

我需要检查这些插入的唯一性吗?如果需要的话,我该怎么做?或者有没有其他更好的解决方案?

3 个回答

1
class User(Base):
  __tablename__ = 'users'

  id = Column(Integer, primary_key=True)
  name = Column(String, unique=True)
  fullname = Column(String)
  password = Column(String)

insert_command = User.__table__.insert(
    prefixes=['OR IGNORE'],
    values=dict(name='MyName', fullname='Slim Shady', password='******')
)
session.execute(insert_command)
session.commit() 
prefixes=['OR REPLACE']

替换功能也可以使用

1

其实我找到的解决方案并不简单,而且看起来也不太美观 :),不过它确实能工作。
当然,如果我使用一个很大的数据库,我会采用这个唯一对象的做法,这是@zzzeek介绍的。

new_author = Author(a_name = request.form['author'])
new_book = Book(b_name = request.form['book'])
author_in_db = Author.query.filter_by(a_name=unicode(new_author)).first()
book_in_db = Book.query.filter_by(b_name=unicode(new_book)).first()
# both author and book are new and unique
if unicode(new_author) != unicode(author_in_db) and \
                               unicode(new_book) != unicode(book_in_db):
    new_author.books.append(new_book)
    db.session.add(new_author)
    db.session.add(new_book)
    db.session.commit()
# just book is not unique
elif unicode(new_author) != unicode(author_in_db):
    new_author.books.append(book_in_db)
    db.session.add(new_author)
    db.session.commit()
# just author is not unique
elif unicode(new_book) != unicode(book_in_db):
    author_in_db.books.append(new_book)
    db.session.add(new_book)
    db.session.commit()
1

这个ORM(对象关系映射)不支持“合并”这种方法(比如“插入或替换”等等),而且这些方法也有很多复杂的地方。我通常会使用唯一对象的做法,或者类似的变种。当我需要处理大量数据合并时,我会提前把要处理的所有对象加载到一个字典里,这样只需要执行一次SELECT语句来加载它们,然后在后续操作中直接查这个字典就可以了。

撰写回答