Flask中forms.py里current_user为NoneType的原因及解决方法
问题:Flask表单定义时current_user为NoneType的原因及解决方法
报错信息
Traceback (most recent call last): File "/home/profscrew/Desktop/Progetto_Basi_Dati-master/Codice/__init__.py", line 12, in <module> from .artist.routes import artist File "/home/profscrew/Desktop/Progetto_Basi_Dati-master/Codice/artist/routes.py", line 6, in <module> from Codice.artist.forms import * File "/home/profscrew/Desktop/Progetto_Basi_Dati-master/Codice/artist/forms.py", line 28, in <module> class SongForm(FlaskForm): File "/home/profscrew/Desktop/Progetto_Basi_Dati-master/Codice/artist/forms.py", line 41, in SongForm album = SelectField("Album", choices=Album.get_albums(current_user.username), validate_choice=True ) AttributeError: 'NoneType' object has no attribute 'username'
相关代码
forms.py
from flask_wtf import FlaskForm from wtforms import StringField, PasswordField,DateField,SubmitField,SelectField,EmailField from flask_login import current_user from wtforms.validators import DataRequired, Length, Email, Optional from Codice.models import * from Codice.database import * from Codice.artist.forms import * # 循环导入,需删除 class SongForm(FlaskForm): name = StringField("Name", validators=[DataRequired(),Length(max=40)]) cover = StringField("Cover", validators=[DataRequired(),Length(max=120)]) content=StringField("Content", validators=[DataRequired(),Length(max=120)]) release_date=DateField("Release Date", validators=[DataRequired()]) genre=SelectField("Genre", choices=Genre.list) album = SelectField("Album", choices=Album.get_albums(current_user.username), validate_choice=True ) premium = SelectField("Premium", choices=[' ','The song will be premium','The song will be available to everyone'], validate_choice=True ) submit = SubmitField("Upload")
routes.py
from flask import Blueprint, render_template, redirect, url_for, flash from flask_login import login_user, logout_user, login_required, current_user from Codice.models import * from Codice.database import * from Codice.artist.forms import * # Blueprint Configuration artist = Blueprint('artist', __name__, static_folder='static', template_folder='templates') @artist.route('/insertsong', methods=['GET','POST']) @login_required def insertsong(): form = SongForm() return render_template('insertsong.html', form = form, user = current_user)
models.py(Album类部分)
class Album(Base): __tablename__ = 'albums' # obbligatorio idalbum = Column(Integer, primary_key=True) name = Column(String) cover = Column(String) artist = Column(String, ForeignKey(Artist.username)) artists = relationship(Artist, backref=backref( "albums", cascade="all, delete, delete-orphan")) def get_albums(temp_username): albums = Session_artist.query(Album).filter(Album.artist == temp_username).all() return albums
原因分析
- 表单加载时机问题:
SongForm类在应用启动加载模块时就被定义,此时还没有用户请求,flask_login的current_user未被初始化,处于None状态,调用current_user.username自然触发报错。 - 循环导入问题:
forms.py中from Codice.artist.forms import *属于循环导入,会干扰模块正常加载流程。
解决方法
步骤1:修复循环导入
删除forms.py中的from Codice.artist.forms import *代码,消除循环导入异常。
步骤2:动态填充SelectField选项
不在表单类定义阶段设置choices,先将album字段的choices设为空列表,再在视图函数中(此时current_user已被正确初始化)动态填充选项。同时注意,SelectField的choices需要是**(选项值, 显示文本)**格式的元组列表。
修改后的forms.py
from flask_wtf import FlaskForm from wtforms import StringField, PasswordField,DateField,SubmitField,SelectField,EmailField from wtforms.validators import DataRequired, Length, Email, Optional from Codice.models import * from Codice.database import * class SongForm(FlaskForm): name = StringField("Name", validators=[DataRequired(),Length(max=40)]) cover = StringField("Cover", validators=[DataRequired(),Length(max=120)]) content=StringField("Content", validators=[DataRequired(),Length(max=120)]) release_date=DateField("Release Date", validators=[DataRequired()]) genre=SelectField("Genre", choices=Genre.list) # 先设为空列表,后续动态填充 album = SelectField("Album", choices=[], validate_choice=True ) premium = SelectField("Premium", choices=[' ','The song will be premium','The song will be available to everyone'], validate_choice=True ) submit = SubmitField("Upload")
修改后的routes.py
from flask import Blueprint, render_template, redirect, url_for, flash from flask_login import login_user, logout_user, login_required, current_user from Codice.models import * from Codice.database import * from Codice.artist.forms import * # Blueprint Configuration artist = Blueprint('artist', __name__, static_folder='static', template_folder='templates') @artist.route('/insertsong', methods=['GET','POST']) @login_required def insertsong(): form = SongForm() # 动态填充专辑选项:转换为(主键ID, 专辑名称)的元组列表 user_albums = Album.get_albums(current_user.username) form.album.choices = [(album.idalbum, album.name) for album in user_albums] # 可在此添加表单提交逻辑 return render_template('insertsong.html', form = form, user = current_user)
步骤3(可选):优化Album.get_albums方法
如果希望直接返回符合SelectField要求的格式,可修改get_albums方法:
class Album(Base): # 省略其他代码... @classmethod def get_albums(cls, temp_username): albums = Session_artist.query(cls).filter(cls.artist == temp_username).all() # 直接返回(值, 文本)的元组列表 return [(album.idalbum, album.name) for album in albums]
此时视图中可简化为form.album.choices = Album.get_albums(current_user.username)
内容的提问来源于stack exchange,提问作者ProfScrew
相关产品推荐
相关产品推荐

