【发布时间】:2021-11-20 22:58:12
【问题描述】:
我是新来的 Flask-Admin,我正在尝试自定义一个模型编辑表单。我的用户模型有一个roles 属性,它是一个relationship 通过role_users 表到Role.name,具有外键约束。
到目前为止一切正常,除了 Flask-Admin 默认用户编辑表单将roles 呈现为字符串字段。我想将其呈现为 QuerySelectMultipleField。我的模型是:
from flask import current_app
from flask_login import UserMixin
from werkzeug.security import check_password_hash, generate_password_hash
from app import db, login_manager
roles = db.Table(
'role_users',
db.Column('user_id', db.String(64), db.ForeignKey('users.username')),
db.Column('role_id', db.String(80), db.ForeignKey('roles.name')),
db.PrimaryKeyConstraint('user_id', 'role_id')
)
class User(UserMixin, db.Model):
__tablename__ = 'users'
username = db.Column(db.String(64), primary_key=True)
password_hash = db.Column(db.String(128))
firstname = db.Column(db.String(64))
lastname = db.Column(db.String(64))
roles = db.relationship('Role', secondary=roles, backref=db.backref('users', lazy='dynamic'))
def __init__(self, username='', password=''):
default = Role.query.filter_by(name='View_contact').one()
self.roles.append(default)
self.username = username
self.password = password
def __repr__(self):
return '<User {}>'.format(self.username)
def set_password(self, password):
self.password_hash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
@property
def password(self):
raise AttributeError('Password is not a readable attribute.')
@password.setter
def password(self, password):
self.set_password(password)
# Required for user_loader with non-integer User PK not named 'id'
def get_id(self):
return self.username
def grant_role(self, role_name):
if not self.has_role(role_name):
role = Role.query.filter_by(name=role_name).first()
self.roles.append(role)
db.session.commit()
def revoke_role(self, role_name):
if self.has_role(role_name):
role = Role.query.filter_by(name=role_name).first()
self.roles.remove(role)
def has_role(self, role_name):
for role in self.roles:
if role.name == role_name:
return True
return False
@login_manager.user_loader
def load_user(username):
return User.query.get(str(username))
class Role(db.Model):
__tablename__ = 'roles'
role_list = [
'View_contact',
'Add_contact',
'Edit_contact',
'Delete_contact',
'View_user',
'Add_user',
'Edit_user',
'Delete_user',
'Admin',
]
name = db.Column(db.String(80), primary_key=True)
description = db.Column(db.String(255))
def __init__(self, name):
self.name = name
def __repr__(self):
return '<Role {}>'.format(self.name)
@classmethod
def load_roles(cls):
for role_name in cls.role_list:
role = Role.query.filter_by(name=role_name).first()
if role is None:
role = Role(name=role_name)
db.session.add(role)
db.session.commit()
我的自定义 ModelView 是
from flask_admin.contrib.sqla import ModelView
from flask_admin.contrib.sqla.fields import QuerySelectMultipleField, QuerySelectField
from flask_admin.form import Select2TagsWidget, Select2Widget
from wtforms import PasswordField
from app import db
from app.models import Role, User
class UserView(ModelView):
column_display_pk = True
form_extra_fields = {
'password': PasswordField('Password'),
'role_sel': QuerySelectMultipleField(
label='Roles',
query_factory=lambda: Role.query.all,
widget=Select2TagsWidget()
)
}
form_columns = (
'username',
'password',
'firstname',
'lastname',
'role_sel',
)
def on_model_change(self, form, User, is_created):
if form.password.data != '':
User.set_password(form.password.data)
但是当我尝试访问 admin/user/new/ 或 admin/user/edit 时,Flask 会抛出 AttributeError: 'QuerySelectMultipleField' object has no attribute '_value'。
如果我尝试从 QuerySelectMultipleField & Select2TagsWidget 更改为 QuerySelectField & Select2Widget Flask throws TypeError: 'method' object is not iterable。
谁能告诉我我做错了什么? _value() 是我需要实现的方法吗?我正在使用 Flask-Admin 1.5.8。
【问题讨论】:
标签: python flask flask-admin