Flask问题:如何从QuerySelectField中获取对象的主键?
问题描述
我正尝试从自引用关系的对象中获取ID,怀疑关系定义存在限制,试过各类Stack Overflow方案都无效:
- 使用
form.parent_id.data.parent_id会抛出AttributeError: 'NoneType' object has no attribute 'parent_id' - 直接用
form.parent_id.data触发sqlalchemy.exc.InterfaceError,原因是QuerySelectField返回的是对象而非ID - 在表单中设置
get_pk=lambda x: x.parent_id也会出现相同错误
routes.py
def edit_user(id): form = UserForm() user = User.query.get_or_404(id) selected_date_ids = [] upcoming_dates = TestDate.query.order_by(TestDate.date).filter(TestDate.status != 'past') tests = sorted(set(TestDate.test for TestDate in TestDate.query.all()), reverse=True) if form.validate_on_submit(): if request.method == "POST": ... user.tutor_id=form.tutor_id.data user.parent_id=form.parent_id.data
models.py
class User(UserMixin, db.Model): id = db.Column(db.Integer, primary_key=True) ... tutor_id = db.Column(db.Integer, db.ForeignKey('user.id')) students = db.relationship('User', backref=db.backref('tutor'), foreign_keys=[tutor_id], remote_side=[id]) parent_id = db.Column(db.Integer, db.ForeignKey('user.id')) children = db.relationship('User', backref=db.backref('parent'), foreign_keys=[parent_id], remote_side=[id])
forms.py
def get_tutors(): return User.query.filter_by(role='tutor') def get_parents(): return User.query.filter_by(role='parent') def full_name(User): return User.first_name + " " + User.last_name class UserForm(FlaskForm): ... tutor_id = QuerySelectField('Tutor', default=1, query_factory=get_tutors, get_label=full_name, allow_blank=True) parent_id = QuerySelectField('Parent', query_factory=get_parents, get_label=full_name, allow_blank=True) is_admin = BooleanField('Admin') submit = SubmitField('Save')
解决方法
- 修正字段赋值逻辑
QuerySelectField返回的是完整的User对象,需提取对象的id属性赋值给外键字段,同时处理空白选项的空值情况:
user.tutor_id = form.tutor_id.data.id if form.tutor_id.data else None user.parent_id = form.parent_id.data.id if form.parent_id.data else None
- 优化自引用关系定义
当前关系定义逻辑正确,可显式添加lazy参数提升可读性(默认值即为select):
students = db.relationship('User', backref=db.backref('tutor', lazy='select'), foreign_keys=[tutor_id], remote_side=[id], lazy='select') children = db.relationship('User', backref=db.backref('parent', lazy='select'), foreign_keys=[parent_id], remote_side=[id], lazy='select')
移除错误的
get_pk设置get_pk默认会取对象的id作为提交值,手动设置为x.parent_id会导致提交数据错误,直接删除该参数即可。初始化表单时填充默认值
编辑页面需将现有用户的关联数据自动填充到表单,使用obj参数即可实现:
def edit_user(id): user = User.query.get_or_404(id) form = UserForm(obj=user) # 自动填充现有用户数据 selected_date_ids = [] upcoming_dates = TestDate.query.order_by(TestDate.date).filter(TestDate.status != 'past') tests = sorted(set(TestDate.test for TestDate in TestDate.query.all()), reverse=True) if form.validate_on_submit(): if request.method == "POST": ... user.tutor_id = form.tutor_id.data.id if form.tutor_id.data else None user.parent_id = form.parent_id.data.id if form.parent_id.data else None db.session.commit() # 务必提交数据库会话
内容的提问来源于stack exchange,提问作者dannypernik
相关产品推荐
相关产品推荐

