Search code examples
pythonpostgresqlflaskflask-admin

Why are some of my flask-sqlalchemy tables not setting postresql primary key to serial?


I have a postgresql database with some simple tables in it. I'm using flask-sqlalchemy as my ORM and I use flask-migrate to update when I make changes to the schema.

If I look at my tables using DBeaver I see that most of my tables have a primary key of type serial4. If I used flask-admin to create new entries in these tables it works fine. However, two of the tables show the primary key as int4, these do not show in the flask-admin interface but if I try to add rows I get the following error:

Integrity error. (psycopg2.errors.NotNullViolation) null value in column "id" of relation "priority" violates not-null constraint DETAIL: Failing row contains (P1, 4, 8, null). [SQL: INSERT INTO priority (priority, respond_by, resolve_by) VALUES (%(priority)s, %(respond_by)s, %(resolve_by)s) RETURNING priority.id] [parameters: {'priority': 'P1', 'respond_by': 4, 'resolve_by': 8}] (Background on this error at: https://sqlalche.me/e/14/gkpj)

My model looks like this:

# priority lookup table
class Priority(db.Model):
    __tablename__ = 'priority'
    id = db.Column(db.Integer, primary_key=True)
    priority = db.Column(db.String(2))
    respond_by = db.Column(db.Integer)  # response time in minutes e.g. created time + this many minutes
    resolve_by = db.Column(db.Integer)  # resolve in minutes as per above


class Classification(db.Model):
    __tablename__ = 'classifications'
    id = db.Column(db.Integer, primary_key=True)
    service = db.Column(db.String(50))
    category = db.Column(db.String(50))
    sub_category = db.Column(db.String(50))
    selectable = db.Column(db.Boolean())

Of these two the Classification table works fine, it created a serial4 primary key. The Priority table does created the primary key as int4 so is failing via flask-admin.

Why would this be? I can't see any difference between them so don't understand why one created the table with a serial4 primary key and the other did not.


Solution

  • Thanks to the comment left by a_horse_with_no_name I dug a bit deeper into this and took a punt (because not in flask-sqlalchemy docs) and added db.Identity() to my primary key like so:

    class Priority(db.Model):
        __tablename__ = 'priority'
        id = db.Column(db.Integer, db.Identity(), primary_key=True)
        priority = db.Column(db.String(2))
        respond_by = db.Column(db.Integer) 
        resolve_by = db.Column(db.Integer)  
    

    I did this for all of my tables. But flask-migratee didn't like it so I dropped all tables and recreated them like so (because I'm using blueprints)

    from app import create_app, db
    app = create_app()
    app.app_context().push()
    db.drop_all()
    db.create_all()
    

    Now looking at the tables created using DBeaver CE, I see the primary keys are all int4 (none are serial anymore) and if I go to my flask-admin page /admin and select any table, I can now created entries without a problem.

    I don't know why, when I created the tables previously without the db.Identity() option some were created as serial and others were not. But problem fixed so no point dwelling on it.