Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
783 views
in Technique[技术] by (71.8m points)

python - Flask-SQLAlchemy: sqlite3 IntegrityError

I'm creating an application to replace current tab managers in the browser. I've created a simple one-to-many relationship between groups - table Topic, and tabs - table Tab. I want to be able to automatically delete topic's children if I delete it. This is what I currently have:

from flask import request, redirect, url_for, render_template, Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import exc
from flask_whooshee import Whooshee
from datetime import datetime

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db = SQLAlchemy(app)
whooshee = Whooshee(app)

@whooshee.register_model('topic_name')
class Topic(db.Model):
    __tablename__ = 'topic'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    topic_name = db.Column(db.String, unique=True, nullable=False)
    topic_created = db.Column(db.DateTime, default=datetime.utcnow)
    topic_changed = db.Column(db.DateTime, default=datetime.utcnow)
    topic_tabs = db.relationship('Tab', backref='topic', cascade='all, delete-orphan', lazy='dynamic')

@whooshee.register_model('tab_name', 'tab_link', 'tab_description')
class Tab(db.Model):
    __tablename__ = 'tab'
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    tab_name = db.Column(db.String, nullable=False)
    tab_link = db.Column(db.String, unique=True, nullable=False)
    tab_favicon = db.Column(db.String)
    tab_description = db.Column(db.String)
    tab_created = db.Column(db.DateTime, default=datetime.utcnow)
    tab_changed = db.Column(db.DateTime, default=datetime.utcnow)
    topic_id = db.Column(db.Integer, db.ForeignKey('topic.id'))

@app.route('/', methods=['GET'])
def index():
    return "Test"

if __name__ == '__main__':
    db.create_all()
    try:
        db.session.commit()
    except exc.IntegrityError as e:
        print(str(e))
        db.session.rollback()

    top = Topic(topic_name='Test')
    db.session.add(top)
    try:
        db.session.commit()
    except exc.IntegrityError as e:
        print(str(e))
        db.session.rollback()

    top2 = Topic(topic_name='Test2')
    db.session.add(top2)
    try:
        db.session.commit()
    except exc.IntegrityError as e:
        print(str(e))
        db.session.rollback()

    t1 = Tab(tab_name='t1', tab_link='t1l', tab_favicon='t1f', tab_description='t1d', topic_id=top.id)
    t2 = Tab(tab_name='t2', tab_link='t2l', tab_favicon='t2f', tab_description='t2d', topic_id=top.id)
    t3 = Tab(tab_name='t3', tab_link='t3l', tab_favicon='t3f', tab_description='t3d', topic_id=top.id)

    db.session.add(t1)
    db.session.add(t2)
    db.session.add(t3)
    try:
        db.session.commit()
    except exc.IntegrityError as e:
        print(str(e))
        db.session.rollback()
    import uuid
    app.secret_key = str(uuid.uuid4())
    app.run(debug=True)

The problem is that I get integrity errors, when I'm trying to add something in the database and I'm not sure what can go wrong. I also want to save previous records in the database if I stop the server, how do I implement that as well?

UPD: the behaviour below happens even if I delete my database entirely. I get this error after simply running the script python script_name.py in an empty folder.

UPD2: if anyone needs to check whether a database exists, there is a special helper function https://sqlalchemy-utils.readthedocs.io/en/latest/database_helpers.html#database-exists

(sqlite3.IntegrityError) UNIQUE constraint failed: topic.topic_name [SQL: 'INSERT INTO topic (topic_name, topic_created, topic_changed) VALUES (?, ?, ?)'] [parameters: ('Test', '2018-09-03 05:21:08.728564', '2018-09-03 05:21:08.728564')] (Background on this error at: http://sqlalche.me/e/gkpj)

(sqlite3.IntegrityError) UNIQUE constraint failed: topic.topic_name [SQL: 'INSERT INTO topic (topic_name, topic_created, topic_changed) VALUES (?, ?, ?)'] [parameters: ('Test2', '2018-09-03 05:21:08.730562', '2018-09-03 05:21:08.730562')] (Background on this error at: http://sqlalche.me/e/gkpj)

(sqlite3.IntegrityError) UNIQUE constraint failed: tab.tab_link [SQL: 'INSERT INTO tab (tab_name, tab_link, tab_favicon, tab_description, tab_created, tab_changed, topic_id) VALUES (?, ?, ?, ?, ?, ?, ?)'] [parameters: ('t1', 't1l', 't1f', 't1d', '2018-09-03 05:21:08.733561', '2018-09-03 05:21:08.733561', None)] (Background on this error at: http://sqlalche.me/e/gkpj)

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Your script is the WSGI application, hence runs as __main__. If you use debug=True as argument to app.run() the server will start, set debug mode: on and restart with stat, executing the __name__ == '__main__' block again (and again every time you make changes to your script and save it while the server is running).

When you start your app on an empty/deleted DB, the first time the __name__ == '__main__' block is executed, it creates the DB and inserts the two Topic and three Tab objects you create in that block. Then it sets debug mode and restarts, again executing that block, attempting to insert these five objects a second time.

from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello_world():
    return "Hello, World!"

if __name__ == '__main__':
    print(__name__)
    app.run(debug=True)

Output:

__main__ # <-- fist time around it creates DB and objects
 * Serving Flask app "main" (lazy loading)
 * Environment: production
   WARNING: Do not use the development server in a production environment.
   Use a production WSGI server instead.
 * Debug mode: on
 * Restarting with stat # <-- re-executing your script
__main__ # <-- trying to create the same objects again, violating the UNIQUE constraint
 * Debugger is active!
 * Debugger PIN: 302-544-855
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...