Flask_wtf - UnmappedInstanceError: класс не сопоставлен - PullRequest
0 голосов
/ 22 января 2019

Я создаю относительно простое приложение 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

* Добавлена ​​пробелатическая часть 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 за указание на этот простой, но трудный для понимания момент! (Я, наверное, должен чаще останавливаться).

1 Ответ

0 голосов
/ 22 января 2019

Проблема была в разделе маршрута:

@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 Я смог понять, где проблема.Еще раз спасибо!

Я понимаю, что это простая ошибка, но я не мог найти много информации относительно ошибки и решения.Однако, если администраторы решат, что их не стоит оставлять, смело удаляйте их.

Спасибо.

...