python 2.7 + flask-sqlalchemy,flask棉花糖+ DB关系抛出错误Foreignkeyconstraint和主连接

时间:2019-05-14 11:44:46

标签: python-2.7 flask-sqlalchemy

我有一个已经具有以下表的现有数据库数据集: 具有ownerid为primary_key的所有者表

另一个表owndnis,其primary_key是相同的ownerid

另一个表,其primary_key与所有者的所有者ID相同

我想定义一个看起来像这样的关系

所有者   有      {owndnis}和   {application_parameters}

我的模型和路线文件的内容在下面给出


model.py
from marshmallow import fields
from flask import jsonify


class owners(db.Model):
    __tablename__ = 'owners'

    ownerid = db.Column('ownerid',db.String(60), nullable=False)
    name = db.Column('ownerdomainname', db.String(60),primary_key=True, nullable=False)
    spownerid = db.Column('spownerid', db.String(60))
    ownerid = db.Column(db.String(), db.ForeignKey('owndnis.ownerid'))
    dnis = db.relationship("owndnis", uselist=False, backref="owners")
#    ownerid = db.Column(db.String(), db.ForeignKey('application_parameters.ownerid'))
#    app_params = db.relationship("application_parameters", backref="owners")

class owndnis(db.Model):
    __tablename__ = 'owndnis'

    ownerid = db.Column('ownerid',db.String(60),primary_key=True)
    dnisstart = db.Column('dnisstart', db.String(20), nullable=False)
    dnisend = db.Column('dnisend', db.String(20))


class application_parameters(db.Model):
    __tablename__ = 'application_parameters'

    ownerid = db.Column('ownerid',db.String(60),primary_key=True)
    applicationid = db.Column('applicationid', db.String(60), nullable=False)
    key = db.Column('key', db.String(128), nullable=False)
    value = db.Column('value', db.String(1024), nullable=False)

###### SCHEMAS ##### 

class owndnis_schema(ma.ModelSchema):
    dnisstart = fields.String()
    dnisend = fields.String()


class app_params_schema(ma.ModelSchema):
    key = fields.String()
    value = fields.String()

class owners_schema(ma.ModelSchema):
    ownerid = fields.String()
    ownerdomainname = fields.String()
    spownerid = fields.String()
    ownerdescription = fields.String()
    dnis = fields.Nested(owndnis_schema)
    app_params = fields.Nested(app_params_schema)

routes.py
---------
from model import owners, owndnis, application_parameters,owners_schema,owndnis_schema, app_params_schema
@mod.route('/api/sp/<spdomainname>', methods=['GET'])
def findSp(spdomainname):
    ownerArr = []
    owner = owners.query.get(spdomainname)
    owner_schema = owners_schema()
    if owner:
        owners_sm_result = owner_schema.dump(owner).data
        return jsonify({'owner': owners_sm_result})


I get the output like this
{
  "owner": {
    "spownerid": "SYSTEM", 
    "ownerid": "NEWSP~ZryOZB9BGb", 
    "dnis": {
      "dnisend": "199999", 
      "dnisstart": "100000"
    }
  }
}

If I uncomment the commented lines in model.py(owners) to include another table that has foreign key same as owndnis table
but I get this run time error

File "/home/holly/python_ws/new_project_blue/blue/lib/python2.7/site-packages/sqlalchemy/orm/relationships.py", line 2383, in _determine_joins
    "specify a 'primaryjoin' expression." % self.prop
sqlalchemy.exc.NoForeignKeysError: Could not determine join condition between parent/child tables on relationship owners.dnis - there are no foreign keys linking these tables.  Ensure that referencing columns are associated with a ForeignKey or ForeignKeyConstraint, or specify a 'primaryjoin' expression.
[pid: 18308|app: 0|req: 1/1] 10.133.0.31 () {34 vars in 620 bytes} [Tue May 14 07:22:14 2019] GET /api/sp/NEW-SP => generated 0 bytes in 25 msecs (HTTP/1.1 500) 0 headers in 0 bytes (0 switches on core 0)

The requirement is to have the output like this
I get the output like this
{
  "owner": {
    "spownerid": "SYSTEM", 
    "ownerid": "NEWSP~ZryOZB9BGb", 
    "dnis": {
      "dnisend": "199999", 
      "dnisstart": "100000"
    },
   "app_params": {
   "key":"xxxxx",
   "value":"yyyy"
   }
  }
}


1 个答案:

答案 0 :(得分:0)

我将严格遵循文档中的关系模式:

https://docs.sqlalchemy.org/en/13/orm/basic_relationships.html

作为示例,假设您希望在ownersowndnis之间建立一对一的关系...

一对一

class Parent(Base):
    __tablename__ = 'parent'
    id = Column(Integer, primary_key=True)
    child = relationship("Child", uselist=False, back_populates="parent")

class Child(Base):
    __tablename__ = 'child'
    id = Column(Integer, primary_key=True)
    parent_id = Column(Integer, ForeignKey('parent.id'))
    parent = relationship("Parent", back_populates="child")

未经测试,但遵循此模式,在您的情况下,将owners作为父项:

# Treated as Parent of One to One
class owners(db.Model):
    __tablename__ = 'owners'

    ownerid = db.Column('ownerid', db.String(60), primary_key=True)  <--- changed primary key
    name = db.Column('ownerdomainname', db.String(60), nullable=False)
    spownerid = db.Column('spownerid', db.String(60))

    dnis = db.relationship("owndnis", uselist=False, back_populates="owners") <--- note change
    # child = relationship("Child",   uselist=False, back_populates="parent")

# Treated as Child of One to One
class owndnis(db.Model):
    __tablename__ = 'owndnis'

    ownerid = db.Column('ownerid', db.String(60),
      primary_key=True, db.ForeignKey('owners.ownerid'))            <-- both a PK and FK
    dnisstart = db.Column('dnisstart', db.String(20), nullable=False)
    dnisend = db.Column('dnisend', db.String(20))

    owner = relationship("owners", back_populates="owndnis") <--- added
 # parent = relationship("Parent", back_populates="child")

我使用过back_populates,但根据文档:

  

和往常一样,可以使用Relationship.backref和backref()函数来代替Relationship.back_populates方法;要在backref上指定uselist,请使用backref()函数:

class Parent(Base):
    __tablename__ = 'parent'
    id = Column(Integer, primary_key=True)
    child_id = Column(Integer, ForeignKey('child.id'))
    child = relationship("Child", backref=backref("parent", uselist=False))