Flask多对多关系sqlalchemy.exc.InvalidRequestError:找不到名称

时间:2017-12-08 22:38:13

标签: python flask-sqlalchemy

当试图让多对多的关系工作时,我不断收到以下错误:

sqlalchemy.exc.InvalidRequestError:一个或多个映射器无法初始化 - 无法继续初始化其他映射器。触发映射器:'Mapper | User | Users'。原始异常是:初始化映射器Mapper | User | Users时,表达式“Device”无法找到名称(“name'Device'未定义”)。如果这是一个类名,请考虑在定义了两个依赖类之后将此关系()添加到类中。

我查看了所有sqlalchemy文档并查看了多个链接,但没有运气。我确定它是一个命名或导入问题,但尚未找到解决方案

我删除了一些我认为不相关的代码

Users.py

from random import SystemRandom
from backports.pbkdf2 import pbkdf2_hmac, compare_digest
from flask_login import UserMixin
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import relationship
from devices.models import Device

user_device = db.Table('UserDevice', db.Model.metadata,
                   db.Column('userID', db.Integer, db.ForeignKey('Users.userID')),
                   db.Column('deviceID', db.Integer, db.ForeignKey('Device.deviceID')))


class User(UserMixin, db.Model):

  __tablename__ = 'Users'
  __table_args__ = {'mysql_engine': 'InnoDB',
                  'extend_existing': True}

  id = db.Column('userID', db.Integer, primary_key=True)
  # Relationship to UserDevice association table
  user_device = relationship('Device',
                             secondary=user_device,
                             backref=db.backref('users', lazy='dynamic'))

Device.py

class Device(db.Model):

  __tablename__ = 'Device'
  __table_args__ = {'mysql_engine': 'InnoDB',
                  'extend_existing': True}

  id = db.Column('deviceID', db.Integer, primary_key=True)
  date_created = db.Column('deviceDateCreated', db.DateTime, default=db.func.current_timestamp())
  date_modified = db.Column('deviceDateModified', db.DateTime, default=db.func.current_timestamp(), onupdate=db.func.current_timestamp())
  device_created_user = db.Column('deviceCreatedUser', db.String, default='App Server')
  device_last_updated_user = db.Column('deviceLastUpdatedUser', db.String, default='App Server', onupdate=current_user)

  #Serial Number
  serial_number = db.Column('deviceSerialNumber', db.Integer, nullable=False, unique=True)

  #Sampling Interval
  sampling_interval = db.Column('deviceSamplingInterval', db.Integer, default=60, nullable=False)

  # Relationship to Device Status Table
  device_status_id = db.Column('deviceStatusID', db.Integer, db.ForeignKey('DeviceStatus.deviceStatusID'))

  # New instance instantiation procedure
  def __init__(self, serial_number):
    self.serial_number = serial_number
    self.device_status_id = 1

  def __repr__(self):
    return '<Device %r>' % self.serial_number

数据库模型图片:

Image of Database Model

1 个答案:

答案 0 :(得分:1)

原来我没有提供足够的信息来解决这个问题。问题是使用通过调用SQLAlchemy创建的db变量。我为名为database.py的数据库创建了一个python文件。我犯的错误是在User \ models.py中我调用了以下从数据库导入db 导入,在Device \ models.py中调用了来自app import db 的。这导致db.Model无法正常运行,并且在调用create_all()时也不会创建用户表。希望这可以帮助将来的某个人。

<强> Database.py

from flask_influxdb import InfluxDB
from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()
influx_db = InfluxDB()
influx_db_client = None


def init_db():
    # import all modules here that might define models so that
    # they will be registered properly on the metadata.  Otherwise
    # you will have to import them first before calling init_db()
    from users.models import User, UserStatus, UserDevice
    from devices.models import Device, DeviceStatus
    db.Model.metadata.drop_all(bind=db.engine)
    db.Model.metadata.create_all(bind=db.engine)

设备\ models.py

from app import db
from flask_login import current_user
from sqlalchemy.orm import relationship
import enum


class DeviceStatusType(enum.Enum):
    INACTIVE = "Inactive"
    ACTIVE = "Active"

# Define a Device model
class Device(db.Model):

    __tablename__ = 'Device'
    __table_args__ = {'extend_existing': True}

    id = db.Column('deviceID', db.Integer, primary_key=True)
    date_created = db.Column('deviceDateCreated', db.DateTime, default=db.func.current_timestamp())
    date_modified = db.Column('deviceDateModified', db.DateTime, default=db.func.current_timestamp(), onupdate=db.func.current_timestamp())
    device_created_user = db.Column('deviceCreatedUser', db.String(128), default='App Server')
    device_last_updated_user = db.Column('deviceLastUpdatedUser', db.String(128), default='App Server', onupdate=current_user)

    #Serial Number
    serial_number = db.Column('deviceSerialNumber', db.Integer, nullable=False, unique=True)

    #Sampling Interval
    sampling_interval = db.Column('deviceSamplingInterval', db.Integer, default=60, nullable=False)

    # Relationship to Device Status Table
    device_status_id = db.Column('deviceStatusID', db.Integer, db.ForeignKey('DeviceStatus.deviceStatusID'))

    users = relationship("User", secondary="userDevice")

    # New instance instantiation procedure
    def __init__(self, serial_number):
        self.serial_number = serial_number
        self.device_status_id = 1

    def __repr__(self):
        return '<Device %r>' % self.serial_number

用户\ models.py

from random import SystemRandom
from backports.pbkdf2 import pbkdf2_hmac, compare_digest
from flask_login import UserMixin, current_user
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import relationship, backref
from devices.models import Device

import enum

# Import the database object (db) from the main application module
# We will define this inside /app/__init__.py in the next sections.
from app import db


class UserStatusType(enum.Enum):
    INACTIVE = "Inactive"
    ACTIVE = "Active"


# Define a User model
class User(UserMixin, db.Model):

    __tablename__ = 'User'
    __table_args__ = {'extend_existing': True}

    id = db.Column('userID', db.Integer, primary_key=True)
    date_created = db.Column('userDateCreated', db.DateTime, default=db.func.current_timestamp())
    date_modified = db.Column('userDateModified', db.DateTime, default=db.func.current_timestamp(), onupdate=db.func.current_timestamp())
    user_created_user = db.Column('userCreatedUser', db.String(128), default=current_user)
    user_last_updated_user = db.Column('userLastUpdatedUser', db.String(128), default=current_user, onupdate=current_user)

    # First Name
    first_name = db.Column('userFirstName', db.String(128), nullable=False)

    # Last Name
    last_name = db.Column('userLastName', db.String(128), nullable=False)

    # User Name
    user_name = db.Column('userUserName', db.String(128), nullable=False, unique=True)

    # Email
    email = db.Column('userEmailAddress', db.String(128), nullable=False, unique=True)

    # Password
    _password = db.Column('userPassword', db.LargeBinary(128))
    _salt = db.Column('userSalt', db.LargeBinary(128))

    # Relationship to User Status table
    user_status_id = db.Column('userStatusID', db.Integer, db.ForeignKey('UserStatus.userStatusID'))

    # Relationship to UserDevice association table
    devices = relationship("Device", secondary="userDevice")

    @hybrid_property
    def password(self):
        return self._password

    # In order to ensure that passwords are always stored
    # hashed and salted in our database we use a descriptor
    # here which will automatically hash our password
    # when we provide it (i. e. user.password = "12345")
    @password.setter
    def password(self, value):
        # When a user is first created, give them a salt
        if self._salt is None:
        self._salt = bytes(SystemRandom().getrandbits(8))
        self._password = self._hash_password(value)

    def is_valid_password(self, password):
        """Ensure that the provided password is valid.

        We are using this instead of a ``sqlalchemy.types.TypeDecorator``
        (which would let us write ``User.password == password`` and have the incoming
        ``password`` be automatically hashed in a SQLAlchemy query)
        because ``compare_digest`` properly compares **all***
        the characters of the hash even when they do not match in order to
        avoid timing oracle side-channel attacks."""
        new_hash = self._hash_password(password)
        return compare_digest(new_hash, self._password)

    def _hash_password(self, password):
        pwd = password.encode("utf-8")
        salt = bytes(self._salt)
        buff = pbkdf2_hmac("sha512", pwd, salt, iterations=100000)
        return bytes(buff)

    # New instance instantiation procedure
    def __init__(self, first_name, last_name, user_name, email, password):
        self.first_name = first_name
        self.last_name = last_name
        self.user_name = user_name
        self.email = email
        self.password = password
        self.user_status_id = 2

    def __repr__(self):
        return "<User #{:d}>".format(self.id)