Использование библиотеки python flask-rest-jsonapi без идентификатора в качестве первичного ключа - PullRequest
2 голосов
/ 15 апреля 2019

Я использую библиотеку Python flask-rest-jsonapi для разработки API.В библиотеке используются колба-sqlalchemy и зефир .Зефир имеет обязательное наличие в схеме обязательного поля «id» и «type».

Таблицы базы данных, для которых я разрабатываю API, не имеют столбца «id».Две таблицы, которые я пытаюсь определить, называются «Отдел» и «Учитель», где на одном отделе работают несколько преподавателей, поэтому между отделом и учителем существует отношение один ко многим.Их столбцы первичных ключей называются «Department_Unique_ID» и «Teacher_Unique_ID».

Вот мой код:

from flask import Flask
from flask_rest_jsonapi import Api, ResourceDetail, ResourceList, ResourceRelationship
from flask_rest_jsonapi.exceptions import ObjectNotFound
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.orm.exc import NoResultFound
from marshmallow_jsonapi.flask import Schema, Relationship
from marshmallow_jsonapi import fields
import connectDB

# Create the Flask application
app = Flask(__name__)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

app = connectDB.connectToDb(app)

db = SQLAlchemy(app)

class Department(db.Model):
    db.Model.metadata.schema = 'UNIVERSITY'
    __tablename__ = 'Department'
    Department_Unique_ID = db.Column(db.String, primary_key=True)
    Department_Name = db.Column(db.String)
    uni_teacher = db.relationship('Teacher', backref=db.backref('Department'))

    __mapper_args__ = {
        "order_by":Department_Unique_ID
    }

class Teacher(db.Model):
    db.Model.metadata.schema = 'UNIVERSITY'
    __tablename__ = 'Teacher'
    Teacher_Unique_ID = db.Column(db.String, primary_key=True)
    Teacher_Name = db.Column(db.String)
    Department_ID_Unique = db.Column(db.String, db.ForeignKey('Department.Department_Unique_ID'))

    __mapper_args__ = {
        "order_by":Teacher_Unique_ID
    }

class DepartmentSchema(Schema):
    class Meta:
        type_ = 'uni_department'
        self_view = 'uni_department_detail'
        self_view_kwargs = {'id': '<Department_Unique_ID>'}
        self_view_many = 'uni_department_list'
        strict = True
        __model__ = Department

    id = fields.Integer(as_string=True, many=True, dump_only=True) #not used, if I remove this, I get an error "Must have an 'id' field"

    Department_Unique_ID = fields.Str()
    Department_Name = fields.Str()
    uni_teacher = Relationship(self_view='uni_department_uni_teacher',
                             self_view_kwargs={'id':'<Department_Unique_ID>'},
                             related_view='uni_teacher_list',
                             related_view_kwargs={'id':'<Department_Unique_ID>'},
                             many=True,
                             schema='TeacherSchema',
                             type_='uni_teacher',
                              id_field='Teacher_Unique_ID')

class TeacherSchema(Schema):
    class Meta:
        type_ = 'uni_teacher'
        self_view = 'uni_teacher_detail'
        self_view_kwargs = {'id': '<Teacher_Unique_ID>'}
        self_view_many = 'uni_teacher_list'
        strict = True
        __model__ = Teacher

    id = fields.Integer(as_string=True, many=True, dump_only=True) #not used, if I remove this, I get an error "Must have an 'id' field"

    Teacher_Unique_ID = fields.Str()
    Teacher_Name = fields.Str()
    owner = Relationship(attribute='uni_department',
                         self_view='uni_teacher_uni_department',
                         self_view_kwargs={'id':'<Teacher_Unique_ID>'},
                         related_view='uni_department_detail',
                         related_view_kwargs={'id':'<Department_Unique_ID>'},
                         schema='DepartmentSchema',
                         type_='uni_department')

class DepartmentList(ResourceList):
    schema = DepartmentSchema
    data_layer = {'session': db.session,
                  'model': Department}


class TeacherList(ResourceList):
    def query(self, view_kwargs):
        query_ = self.session.query(Teacher)
        if view_kwargs.get('Teacher_Unique_ID') is not None:
            try:
                self.session.query(Department).filter_by(Teacher_Unique_ID=view_kwargs['Teacher_Unique_ID']).one()
            except NoResultFound:
                raise ObjectNotFound({'parameter': 'Teacher_Unique_ID'}, "Teacher: {} not found".format(view_kwargs['Teacher_Unique_ID']))
            else:
                query_ = query_.join(Department).filter(Department.id == view_kwargs['Teacher_Unique_ID'])
        return query_

    def before_create_object(self, data, view_kwargs):
        if view_kwargs.get('Teacher_Unique_ID') is not None:
            uni_department = self.session.query(Department).filter_by(Teacher_Unique_ID=view_kwargs['Department_Unique_ID']).one()
            data['Department_Unique_ID'] = uni_department.Department_Unique_ID

    schema = TeacherSchema
    data_layer = {'session': db.session,
                  'model': Teacher}

class DepartmentDetail(ResourceDetail):
    def before_get_object(self, view_kwargs):
        if view_kwargs.get('Teacher_Unique_ID') is not None:
            try:
                uni_teacher = self.session.query(Teacher).filter_by(Department_Unique_ID=view_kwargs['Department_Unique_ID']).one()
            except NoResultFound:
                raise ObjectNotFound({'parameter': 'Department_Unique_ID'},
                                     "Teacher: {} not found".format(view_kwargs['Department_Unique_ID']))
            else:
                if uni_teacher.uni_department is not None:
                    view_kwargs['Department_Unique_ID'] = uni_teacher.uni_department.Department_Unique_ID
                else:
                    view_kwargs['Department_Unique_ID'] = None

    schema = DepartmentSchema
    data_layer = {'session': db.session,
                  'model': Department}


class TeacherDetail(ResourceDetail):
    schema = TeacherSchema
    data_layer = {'session': db.session,
                  'model': Teacher}

class DepartmentRelationship(ResourceRelationship):
    schema = DepartmentSchema
    data_layer = {'session': db.session,
                  'model': Department}

class TeacherRelationship(ResourceRelationship):
    schema = TeacherSchema
    data_layer = {'session': db.session,
                  'model': Teacher}

api = Api(app)
api.route(DepartmentList, 'uni_department_list', '/uni_department')
api.route(TeacherList, 'uni_teacher_list', '/uni_teacher', '/uni_teacher/<int:Department_Unique_ID>/uni_teacher')

api.route(DepartmentDetail, 'uni_department_detail', '/uni_department/<int:Department_Unique_ID>', '/uni_teacher/<int:Department_ID_Unique>/owner')
api.route(TeacherDetail, 'uni_teacher_detail', '/uni_teacher/<int:Teacher_Unique_ID>')

api.route(DepartmentRelationship, 'uni_department_uni_teacher', '/uni_department/<int:Department_Unique_ID>/relationships/uni_teacher')
api.route(TeacherRelationship, 'uni_teacher_uni_department', '/uni_teacher/<int:Teacher_Unique_Department>/relationships/owner')

if __name__ == '__main__':
    # Start application
    app.debug = True
    app.run()

Я следую примеру из flask-rest-jsonapi .Буду признателен за любую помощь.

EDIT1- Вот код connectDB.py в соответствии с просьбой-

import yaml

def readDbDetails():
    with open('database_config.yaml', 'r') as stream:
        return (yaml.load(stream))


dbDetails = readDbDetails()


def connectToDb(app):

    database_host = dbDetails['database_host']
    database_username = dbDetails['database_username']
    database_name = dbDetails['database_name']
    database_password = dbDetails['database_password']
    database_port = dbDetails['database_port']
    print(database_host)
    print(database_name)
    print(database_username)
    print(database_password)
    print(database_port)

    app.config[
        'SQLALCHEMY_DATABASE_URI'] = 'mssql+pymssql://'+database_username+':'+database_password+'@'+database_host+':'+database_port+'/'+database_name+''

    return app
...