通过嵌套表单创建模型会产生DetachedInstanceError

时间:2016-01-20 01:27:03

标签: python flask flask-sqlalchemy

通过表单创建员工和照片模型时,我遇到上述错误的问题。

我的方案是我使用Flask-Admin创建一个Employee模型,其中包含我创建的嵌套表单的关联Photo(个人资料图片)。当我通过表单创建一个Employee及其关联的Photo时,我没有收到任何错误。但是,当我尝试通过表单创建另一个Employee和Photo时,我收到此错误:

DetachedInstanceError: Instance <Photo at 0x106eca0d0> is not bound to a Session; attribute refresh operation cannot proceed

我已经阅读了关于SQLAlchemy的关于Session expunge expunge_all() flush和级联的文档,但我仍然无法使其正常工作。我仍然收到同样的错误,我不确定还有什么可以尝试。

-----------编辑(代码和完整跟踪错误)----------------

这是表单代码

forms.py

class PhotoForm(Form):
-------conditional logic that determines s3 config or not -------

     image = S3ImageUploadField(base_path=app.config['UPLOAD_FOLDER'],
                           namegen = photo_name_generator,
                           storage_type = '',
                           storage_type_field = '',
                           bucket_name = '',
                           bucket_name_field = '',
                           access_key_id = '',
                           access_key_secret = '',
                           static_root_parent = app.config['UPLOAD_FOLDER'])

 DEPARTMENTS = ['place a series of tuples indicating department choices']

class EmployeeForm(Form):
    name = StringField('Full Name', validators=[DataRequired()])
    title = StringField('Job Title', validators=[DataRequired()])
    email = StringField('Company Email', validators=[DataRequired()])
    department = SelectField('Department', choices=DEPARTMENTS)
    photo = FormField(PhotoForm)

这是型号代码

models.py

#-----photo_name_generator grabs the filename and changes it to the employees name------
def photo_name_generator(obj,file_data):
    parts = path.splitext(file_data.filename)
    return secure_filename(str(obj.employee[0].name) + str(parts[1]))

class Photo(db.Model):
    __tablename__ = 'photos'
    id = db.Column(db.Integer, primary_key=True)
    image = db.Column(db.String(200))
    storage_type_field = db.Column(db.String(255), default='')
    bucket_name_field = db.Column(db.String(255), default='')

    def __init__(self, image='', storage_type_field='', bucket_name_field=''):
        self.image = image
        self.storage_type_field = storage_type_field
        self.bucket_name_field = bucket_name_field

    def __repr__(self):
        return '<Photo %r>' % self.image

class Employee(db.Model):
    __tablename__ = 'employees'
    id = db.Column(db.Integer, primary_key=True)
    photo_id = db.Column(db.Integer, db.ForeignKey(Photo.id))
    photo = db.relationship("Photo", backref='employee', cascade='all, delete-orphan', single_parent=True, uselist=False)
    name = db.Column(db.String(200))
    title = db.Column(db.String(200))
    email = db.Column(db.String(200))
    department = db.Column(db.String(200))

    def __init__(self, name='', title='', email='', department='', photo=Photo()):
        self.name = name
        self.title = title
        self.email = email
        self.department = department
        self.photo = photo

    def __repr__(self):
        return '<User %r>' % self.name

这是管理员代码

admin.py

class EmployeeView(ModelView):
    form = EmployeeForm

    def _list_thumbnail(view, context, model, name):
        return Markup('<img height="100" width="100" src="%s">' % url_for('static',
                                              filename= 'images/' + model.photo.image))

    column_formatters = {
        'photo': _list_thumbnail
    }

    form_extra_fields = {
        'photo': ImageUploadField('Image', base_path=app.config['UPLOAD_FOLDER'])
    }

    def on_model_delete(self,model):
        os.remove(app.config['UPLOAD_FOLDER'] + model.photo.image)

    def is_accessible(self):
        return flask_login.current_user.is_authenticated

 admin.add_view(EmployeeView(Employee, db.session))

跟踪错误:

    sqlalchemy.orm.exc.DetachedInstanceError
DetachedInstanceError: Instance <Photo at 0x1060d50d0> is not bound to a Session; attribute refresh operation cannot proceed

Traceback (most recent call last)
File "/Users/drubio/Desktop/blackduckflock/venv/lib/python2.7/site-packages/flask/app.py", line 1836, in __call__
    return self.wsgi_app(environ, start_response)
File "/Users/drubio/Desktop/blackduckflock/venv/lib/python2.7/site-packages/flask/app.py", line 1820, in wsgi_app
    response = self.make_response(self.handle_exception(e))
File "/Users/drubio/Desktop/blackduckflock/venv/lib/python2.7/site-packages/flask/app.py", line 1403, in handle_exception
    reraise(exc_type, exc_value, tb)
File "/Users/drubio/Desktop/blackduckflock/venv/lib/python2.7/site-packages/flask/app.py", line 1817, in wsgi_app
    response = self.full_dispatch_request()
File "/Users/drubio/Desktop/blackduckflock/venv/lib/python2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request
    rv = self.handle_user_exception(e)
File "/Users/drubio/Desktop/blackduckflock/venv/lib/python2.7/site-packages/flask/app.py", line 1381, in handle_user_exception
    reraise(exc_type, exc_value, tb)
File "/Users/drubio/Desktop/blackduckflock/venv/lib/python2.7/site-packages/flask/app.py", line 1475, in full_dispatch_request
    rv = self.dispatch_request()
File "/Users/drubio/Desktop/blackduckflock/venv/lib/python2.7/site-packages/flask/app.py", line 1461, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
File "/Users/drubio/Desktop/blackduckflock/venv/lib/python2.7/site-packages/flask_admin/base.py", line 68, in inner
    return self._run_view(f, *args, **kwargs)
File "/Users/drubio/Desktop/blackduckflock/venv/lib/python2.7/site-packages/flask_admin/base.py", line 359, in _run_view
    return fn(self, *args, **kwargs)
File "/Users/drubio/Desktop/blackduckflock/venv/lib/python2.7/site-packages/flask_admin/model/base.py", line 1674, in create_view
    model = self.create_model(form)
File "/Users/drubio/Desktop/blackduckflock/venv/lib/python2.7/site-packages/flask_admin/contrib/sqla/view.py", line 1004, in create_model
    if not self.handle_view_exception(ex):
File "/Users/drubio/Desktop/blackduckflock/venv/lib/python2.7/site-packages/flask_admin/contrib/sqla/view.py", line 987, in handle_view_exception
    return super(ModelView, self).handle_view_exception(exc)
File "/Users/drubio/Desktop/blackduckflock/venv/lib/python2.7/site-packages/flask_admin/contrib/sqla/view.py", line 999, in create_model
    form.populate_obj(model)
File "/Users/drubio/Desktop/blackduckflock/venv/lib/python2.7/site-packages/wtforms/form.py", line 96, in populate_obj
    field.populate_obj(obj, name)
File "/Users/drubio/Desktop/blackduckflock/venv/lib/python2.7/site-packages/wtforms/fields/core.py", line 807, in populate_obj
    self.form.populate_obj(candidate)
File "/Users/drubio/Desktop/blackduckflock/venv/lib/python2.7/site-packages/wtforms/form.py", line 96, in populate_obj
    field.populate_obj(obj, name)
File "/Users/drubio/Desktop/blackduckflock/venv/lib/python2.7/site-packages/flask_admin_s3_upload.py", line 58, in populate_obj
    field = getattr(obj, name, None)
File "/Users/drubio/Desktop/blackduckflock/venv/lib/python2.7/site-packages/sqlalchemy/orm/attributes.py", line 237, in __get__
    return self.impl.get(instance_state(instance), dict_)
File "/Users/drubio/Desktop/blackduckflock/venv/lib/python2.7/site-packages/sqlalchemy/orm/attributes.py", line 573, in get
    value = state._load_expired(state, passive)
File "/Users/drubio/Desktop/blackduckflock/venv/lib/python2.7/site-packages/sqlalchemy/orm/state.py", line 480, in _load_expired
    self.manager.deferred_scalar_loader(self, toload)
File "/Users/drubio/Desktop/blackduckflock/venv/lib/python2.7/site-packages/sqlalchemy/orm/loading.py", line 610, in load_scalar_attributes
    (state_str(state)))
DetachedInstanceError: Instance <Photo at 0x1060d50d0> is not bound to a Session; attribute refresh operation cannot proceed

1 个答案:

答案 0 :(得分:-1)

我能够通过在__init__.py中指定以下代码来解决此问题。

db = SQLAlchemy(app,session_options={
  'expire_on_commit': False
})