首页 > 解决方案 > Flask_wtf - UnmappedInstanceError:类未映射

问题描述

我正在使用一个不太简单的数据库构建一个相对简单的 Flask 应用程序。我有很多模型来处理和关联数据库中所有需要的信息。

出于某种原因,我收到了标题错误。

我开始认为这与我的数据库模型/关系有什么关系。

因此,模型的实现如下:

from app import db, login
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import UserMixin
import datetime

class User(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), index=True, unique=True)
    email = db.Column(db.String(120), index=True, unique=True)
    password = db.Column(db.String(128))

    def set_password(self, password):
        self.password = generate_password_hash(password)

    def check_password(self, passwd):
        return check_password_hash(self.password, passwd)

    def __repr__(self):
        return '<User {}>'.format(self.username)

class airFeedVariator(db.Model):
    variatorID = db.Column(db.Integer, db.ForeignKey('variator.id',onupdate='RESTRICT',ondelete='RESTRICT'), primary_key=True)
    airFeedID = db.Column(db.Integer, db.ForeignKey('air_feed.id',onupdate='RESTRICT',ondelete='RESTRICT'), primary_key=True)
    variatorRel = db.relationship('Variator', backref='variators',lazy='joined')
    freq = db.Column(db.Integer)


class Variator(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(30))
    machineID = db.Column(db.Integer)
    baudrate  = db.Column(db.Integer)
    addedAt = db.Column(db.DateTime, default=datetime.datetime.utcnow) # the current timestamp

class Air_feed(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    timeOn = db.Column(db.Integer)
    timeOff = db.Column(db.Integer)
    desc = db.Column(db.String)
    digital = db.relationship('Pin_function', backref='analog_or_digital', lazy=True)
    airFeedTypeId = db.relationship('Air_feed_type', backref='air_feed_type_id', lazy=True, uselist=False) #This allow the usage for a single element. 1-1 Rel.
    #variators = db.relationship('Variator', secondary=airFeedVariator, lazy='subquery',backref=backref('airfeedvariators', lazy=True))
    variators = db.relationship('airFeedVariator', lazy='dynamic')

表格如下:

from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, BooleanField, SubmitField, IntegerField, DateTimeField
from wtforms.validators import ValidationError, DataRequired, Email, EqualTo
from flask_babel import lazy_gettext as _l #compile in runtime only.

#Utilizado para converter directamente os modelos em forms.
#from wtforms_alchemy import ModelForm

from app import models

from wtforms_alchemy import model_form_factory

BaseModelForm = model_form_factory(FlaskForm)

class ModelForm(BaseModelForm):
    @classmethod
    def get_session(self):
        print('Session: ', db.session)
        return db.session

class LoginForm(FlaskForm):
    username = StringField(_l('Utilizador'), validators=[DataRequired()])
    password = PasswordField(_l('Password'), validators=[DataRequired()])
    remember_me = BooleanField(_l('Lembrar-me'))
    submit = SubmitField(_l('Submeter'))

class RegistrationForm(FlaskForm):
    username = StringField('Username', validators=[DataRequired()])
    email = StringField('Email', validators=[DataRequired(), Email()])
    password = PasswordField('Password', validators=[DataRequired()])
    password2 = PasswordField(
        'Repetir Password', validators=[DataRequired(), EqualTo('password')])
    submit = SubmitField(l_('Registo'))

    #Validate on submit check for this. The rise allow to write a message directly on the webpage!
    def validate_username(self, username):
        user = models.User.query.filter_by(username=username.data).first()
        if user is not None:
            raise ValidationError(_l('Utilizador já existente!'))

    def validate_email(self, email):
        user = models.User.query.filter_by(email=email.data).first()
        if user is not None:
            raise ValidationError(_l('Email já existente!'))

class VariatorForm(FlaskForm):
    name = StringField(_l('Nome'), validators=[DataRequired()])
    machineID = IntegerField(_l('Identificador'), validators=[DataRequired()])
    baudrate  = IntegerField(_l('Valocidade Comm'), validators=[DataRequired()])
    addedAt = DateTimeField(_l('Preenchimento automatico')) # the current timestamp

    def validate_machineID(self, machineID):
        user = models.Variator.query.filter_by(machineID=machineID.data).first()
        if user is not None:
            raise ValidationError(_l('Já existente um variador registado neste endereço!'))

我确实意识到我在其他人身上有一个 FlaskForm 表单和 ModelForm,我只是在测试。

我的问题如下:

 File "c:\app\routes.py", line 49, in SaveVariator
    db.session.add(var)   File "c:\gburner\lib\site-packages\sqlalchemy\orm\scoping.py", line 153, in do
    return getattr(self.registry(), name)(*args, **kwargs)   File "c:\gburner\lib\site-packages\sqlalchemy\orm\session.py", line 1833, in add
    raise exc.UnmappedInstanceError(instance) sqlalchemy.orm.exc.UnmappedInstanceError: Class 'app.forms.VariatorForm' is not mapped

* 添加 Problatic route.py 部分 *

@app.route('/savevariator', methods=['POST'])
def SaveVariator():
    var = VariatorForm(request.form)
    if var.validate_on_submit():
        print('Variator form submit accepted!')

### I was doing this ### Trying to add the FORM to the session!
        db.session.add(var)
        db.session.commit()
#############################
###  INSTEAD I Should be doing this: ######
        variator = Variator(name=var.name, machineID=var.machineID, baudrate=var.baudrate)
        db.session.add(variator)
        db.session.commit()
##############################
        resp = jsonify(success=True)
    else:
        print('Variator form submit NOT accepted!')
        resp = jsonify(success=False)

    return resp

我认为不需要 html 代码,因为在调用保存数据库信息之前一切正常。

我是否缺少有关数据库中映射关系的某些内容,因为我有 3 个用于多对多关系的表?

任何解决问题的帮助将不胜感激。谢谢你。

* 编辑 * 感谢Joost指出我这个简单但难以实现的点!(我可能应该更频繁地暂停)。

标签: flaskflask-sqlalchemyflask-wtforms

解决方案


问题出在路线部分:

@app.route('/savevariator', methods=['POST'])
def SaveVariator():
    var = VariatorForm(request.form)
    if var.validate_on_submit():
        print('Variator form submit accepted!')

### I was doing this ### Trying to add the FORM to the session!
        db.session.add(var)
        db.session.commit()
#############################
###  INSTEAD I Should be doing this: ######
        variator = Variator(name=var.name, machineID=var.machineID, baudrate=var.baudrate)
        db.session.add(variator)
        db.session.commit()
##############################
        resp = jsonify(success=True)
    else:
        print('Variator form submit NOT accepted!')
        resp = jsonify(success=False)

    return resp

感谢Joost,我能够理解问题出在哪里。再次感谢!

我意识到这是一个简单的错误,但我找不到有关错误和解决方案的太多信息。但是,如果管理员认为不值得保留,请随时将其删除。

谢谢你。


推荐阅读