1

I have a problem creating tables with SQLAlchemy in PostgreSQL.

sqlalchemy.exc.ProgrammingError: (psycopg2.ProgrammingError) there is no unique constraint matching given keys for referenced table "person". [SQL: '\nCREATE TABLE signer (\n\tid INTEGER NOT NULL, \n\tdecree VARCHAR(120), \n\tjob_title VARCHAR(120), \n\tdate_duty_start TIMESTAMP WITHOUT TIME ZONE, \n\tdate_duty_end TIMESTAMP WITHOUT TIME ZONE, \n\tperson_id INTEGER NOT NULL, \n\tcompany_id INTEGER NOT NULL, \n\tsigner_id INTEGER NOT NULL, \n\tcompany_ids INTEGER, \n\tperson_ids INTEGER, \n\tPRIMARY KEY (id, signer_id), \n\tFOREIGN KEY(person_id) REFERENCES person (id), \n\tFOREIGN KEY(company_id) REFERENCES company (id), \n\tFOREIGN KEY(company_ids) REFERENCES company (company_id), \n\tFOREIGN KEY(person_ids) REFERENCES person (person_id)\n)\n\n'] (Background on this error at: http://sqlalche.me/e/f405)

I'm trying to create a new database, so deleting all the tables does not solve the problem. Also, I cannot understand why there's no problem with creating dependencies between the company and signers tables while there is a problem with person-signers relationship....

My classes look as follows:

class Person(db.Model):
    __table_args__ = {'extend_existing': True} 
    def __init__ (self, *args, **kwargs):
        [[setattr(self, key, dict[key]) for key in dict if any(key == t for t in Person.__dict__)] for dict in args]

    person_id = db.Column(db.Integer, primary_key = True)
    first_name = db.Column(db.String(30), nullable=False)
    middle_name = db.Column(db.String(40), nullable=False)
    last_name = db.Column(db.String(60), nullable=False)
    email = db.Column(db.String(120))
    license = db.Column(db.String(120))
    address = db.Column(db.String(240))
    telephone = db.Column(db.String(30))

    #o2o
    user_id = db.Column(db.Integer, db.ForeignKey('usersd.user_id'))

    #o2m
    signers = db.relationship('Signer', backref='person_data', lazy='jioned')

    def __repr__(self):
        return f"{self.last_name.Capitalize} {self.first_name[0].Upper}. {self.middle_name[0].Upper}."

class Signer(db.Model):
    __table_args__ = {'extend_existing': True} 

    def __init__ (self, *args, **kwargs):
        [[setattr(self, key, dict[key]) for key in dict if any(key == t for t in Signer.__dict__)] for dict in args]

    signer_id = db.Column(db.Integer, primary_key = True)
    decree = db.Column(db.String(120))
    job_title = db.Column(db.String(120))
    date_duty_start = db.Column(db.DateTime)
    date_duty_end = db.Column(db.DateTime)
    #o2m

    company_ids = db.Column(db.Integer, db.ForeignKey('company.company_id'))
    person_ids = db.Column(db.Integer, db.ForeignKey('person.person_id'))
    #m2o

    def __repr__(self):
        return f"{self.job_title} at {self.company} according to {self.decree}."

class Company(db.Model):
    __table_args__ = {'extend_existing': True} 

    def __init__ (self, *args, **kwargs):
        [[setattr(self, key, dict[key]) for key in dict if any(key == t for t in Company.__dict__)] for dict in args]

    company_id = db.Column(db.Integer, primary_key = True)
    company_name = db.Column(db.String(60))
    full_title = db.Column(db.String(240))
    tin = db.Column(db.BigInteger)
    kpp = db.Column(db.Integer)
    ogrn = db.Column(db.BigInteger)
    email = db.Column(db.String(120))
    address = db.Column(db.String(240))
    telephone = db.Column(db.String(60))

    license_number = db.Column(db.String(40))
    license_date_issued = db.Column(db.DateTime) 
    license_category = db.Column(db.String(120))
    license_issued_by = db.Column(db.String(120))
    license_issued_by_tin = db.Column(db.BigInteger)
    license_issued_by_kpp = db.Column(db.Integer)
    license_issued_by_ogrn = db.Column(db.BigInteger)

    #o2m
    signers = db.relationship('Signer', backref='company', lazy='joined')


    def __repr__(self):
        return f"{self.company_name}"

----------------------
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt
from flask_login import LoginManager
import sys
import locale
import datetime





app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://postgres:XXXXXXXXXXXXX@localhost/aosr_flask_0_1'
db = SQLAlchemy(app)
bcrypt = Bcrypt(app)
login_manager = LoginManager(app)
login_manager.login_view = 'login'
login_manager.login_message_category = 'info'


------
from test_models import *
db.create_all()

I think the problem came up because I was trying to avoid columns named "id" for each class. Although I defined primary keys in every class as person_id, signer_id, company_id, etc. in my Postgres DB, there are also primary key columns "id" in each table. According to SQL given in Error, SQL Alchemy tries to create two constraints for each case... which makes it not unique.

So my question comes down to how to make SQLAlchemy not to create primary key columns (ID) on its own, when not specified.

I am trying to avoid columns named ID in the database to have fewer problems with using these objects in HTML later.

  • Why do you have __table_args__ = {'extend_existing': True} in each model? – Ilja Everilä 2 days ago
  • Out of interest have you ever taken a look at SQLACodeGen? stackoverflow.com/questions/28788186/how-to-run-sqlacodegen - see what that generates off a database schema. It will pull in all the relationships and do all the grunt work for you. It's not very clever about numeric values - but it's worth taking a look at to see if comparing the generated code vs yours has any glaring issues. – JGFMK 2 days ago
  • @IljaEverilä there are actualy more models in file. Without this, I can't get SQLAlchemy to define classes correctly. I get Error: Table 'хххх' is already defined for this MetaData instance. – Andy Oksen yesterday
  • Can you post a snippet of how you are using the metadata to create the tables? – Ian Wilson yesterday
  • @IanWilson I added code below models, I hope I this is what you meant. And updated question with my thoughts on what seems to be causing the problem. – Andy Oksen yesterday
1

As far as I see, your problem tells you didn't define a unique option for your primary key field. Your person_id should have unique=True. It will guarantee that this field willn't have repeated Ids.

person_id = db.Column(db.Integer, primary_key = True, unique=True)
  • You've helped me to pinpoint the problem. However it is a bit different. – Andy Oksen yesterday
  • When I added unique constraint manually in potrgres db to column "id" the problem went away. Adding unique to person_id column does not affect result as it is by default created in db with unique constraint. SQLAlchemy is creating an "id" column for each class that despite being primary key is not unique. And then it tries to make second relationship to it, although again I do not specify it. So the problem is how to get rid of this "id" columns I do not specify? – Andy Oksen yesterday
  • Then try to use declarative method to specify your models. Use this one: from sqlalchemy.ext.declarative import declarative_base DECLARATIVE=declarative_base and use it like class Signer(DECLARATIVE) – Evgeniy Sobolev yesterday
  • Thanks! I think this is the right way to solve the problem and I will do so. Meanwhile, I found temporary remedy by manualy setting unique constrains on each id column in postgres DB. – Andy Oksen 21 hours ago

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.