So I want to pass a variable to a flask form, in order to do it I've decided to modify the __init__
of SongForm
, but when I do it the album field loses its properties in the html. Does anyone know how do i have to correct my __init__
Here is forms.py:
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 = None
submit = SubmitField("Upload")
def __init__(self, username, *args, **kwargs):
super(SongForm, self).__init__(*args, **kwargs)
self.album = SelectField("Album", choices=Album.get_albums(username), validate_choice=True )
self.album.label = 'Album'
NB:Album.get_albums()
is a function that executes a query and gets a list from database. So it has to receive the parameter username in the constructor.
Or if there is a better way to pass a parameter without breaking the form.
Here is 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 = ModifyProfileForm() # <-- don't mind this form will be removed later
form2 = SongForm(current_user.username)
return render_template('insertsong.html', form = form, form2=form2, user = current_user)
Here is part of insertsong.html code:
<div >
{{ form2.album()}}
{{ form2.album.label()}}
</div>
But when I execute it breaks showing this error TypeError: 'str' object is not callable
:
Traceback (most recent call last):
File "/home/profscrew/.local/lib/python3.9/site-packages/flask/app.py", line 2095, in __call__
return self.wsgi_app(environ, start_response)
File "/home/profscrew/.local/lib/python3.9/site-packages/flask/app.py", line 2080, in wsgi_app
response = self.handle_exception(e)
File "/home/profscrew/.local/lib/python3.9/site-packages/flask/app.py", line 2077, in wsgi_app
response = self.full_dispatch_request()
File "/home/profscrew/.local/lib/python3.9/site-packages/flask/app.py", line 1525, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/profscrew/.local/lib/python3.9/site-packages/flask/app.py", line 1523, in full_dispatch_request
rv = self.dispatch_request()
File "/home/profscrew/.local/lib/python3.9/site-packages/flask/app.py", line 1509, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
File "/home/profscrew/.local/lib/python3.9/site-packages/flask_login/utils.py", line 303, in decorated_view
return current_app.ensure_sync(func)(*args, **kwargs)
File "/home/profscrew/Desktop/Progetto_Basi_Dati-master/Codice/artist/routes.py", line 28, in insertsong
return render_template('insertsong.html', form = form, form2=form2, user = current_user)
File "/home/profscrew/.local/lib/python3.9/site-packages/flask/templating.py", line 148, in render_template
return _render(
File "/home/profscrew/.local/lib/python3.9/site-packages/flask/templating.py", line 128, in _render
rv = template.render(context)
File "/home/profscrew/.local/lib/python3.9/site-packages/jinja2/environment.py", line 1291, in render
self.environment.handle_exception()
File "/home/profscrew/.local/lib/python3.9/site-packages/jinja2/environment.py", line 926, in handle_exception
raise rewrite_traceback_stack(source=source)
File "/home/profscrew/Desktop/Progetto_Basi_Dati-master/Codice/artist/templates/insertsong.html", line 1, in top-level template code
{% extends 'menu.html' %}
File "/home/profscrew/Desktop/Progetto_Basi_Dati-master/Codice/templates/menu.html", line 1, in top-level template code
{% extends "base.html" %}
File "/home/profscrew/Desktop/Progetto_Basi_Dati-master/Codice/templates/base.html", line 35, in top-level template code
{% block pagebody %}{% endblock %}
File "/home/profscrew/Desktop/Progetto_Basi_Dati-master/Codice/templates/menu.html", line 86, in block 'pagebody'
{% block content %}
File "/home/profscrew/Desktop/Progetto_Basi_Dati-master/Codice/artist/templates/insertsong.html", line 24, in block 'content'
{{ form2.album.label()}}
TypeError: 'str' object is not callable
Although if ()
is removed from the html code it executes but it shows up as plain text and not a SelectField
PS: Thank you for the help.
CodePudding user response:
You have tried to set the label property (incorrectly) to the same value which you've just set in the previous line via the label
parameter, i.e. this second line is redundant.
Anyway, here's why you are getting the error. Consider the following code:
def __init__(self, username, *args, **kwargs):
super(SongForm, self).__init__(*args, **kwargs)
self.album = SelectField("Album", choices=Album.get_albums(username), validate_choice=True )
self.album.label = 'Album' # here is your error
A field's label property isn't a str
it's a class, which is why you're getting the TypeError: 'str' object is not callable
error.
An instance of this class is created and assigned to the label property when you pass in a value for the label
parameter in a field's constructor e.g.
name = StringField("Name", validators=[DataRequired(),Length(max=40)])
If you want to change a field's label at runtime you'd do something like the following:
# within the form class
self.album.label = Label(self.album.id, 'Album Name')
# or on a form instance
form2.album.label = Label(form2.album.id, 'Album Name')
Personally, I wouldn't have any database calls in a form's definition, I'd set the choices at runtime. e.g.
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")
album = SelectField("Album", validate_choice=True)
@artist.route('/insertsong', methods=['GET','POST'])
@login_required
def insertsong():
form = ModifyProfileForm() # <-- don't mind this form will be removed later
form2 = SongForm()
# Set your choices at runtime
form2.genre.choices = Genre.list
form2.album.choices = Album.get_albums(username)
return render_template('insertsong.html', form = form, form2=form2, user = current_user)