python 2.7 + фляга-sqlalchemy, фляга-зефир + связи с БД выдает ошибку иностранного ключа ограничение и первичное соединение - PullRequest
0 голосов
/ 14 мая 2019

У меня есть существующий набор данных БД, в котором уже есть эти таблицы: таблица владельцев, для которой идентификатор владельца указан как primary_key

другая таблица owndnis, у которой primary_key такой же, как ownerid *

еще одна таблица, чей primary_key также являетсятот же владелец, что и владельцев

Я хочу определить отношение, которое выглядит следующим образом:

владельцы, имеющие {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 голосов
/ 15 мая 2019

Я бы внимательно следил за паттернами отношений в документации:

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

В качестве примера, предполагая, что вы хотели, чтобы отношения один к одному между owners и owndnis...

Один к одному

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, но в соответствии с документами:

Как всегда, вместо подхода отношениях.back_poplates могут использоваться функции relations.backref и backref ();чтобы указать список использования для backref, используйте функцию 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))
...