So I was following Corey Schafer's Flask tutorial when I came to the part about checking if a username or email is already used while registering for an account. I cannot for the life of me understand how this code works, I guess its because I'm new to Python and Flask but still it shouldn't be this confusing.
class RegistrationForm(FlaskForm):
username = StringField('Username', validators=[DataRequired(), Length(min=4,
max=20)])
email = StringField('Email', validators=[DataRequired(), Email()])
password = PasswordField('Password', validators=[DataRequired()])
password_confirm = PasswordField('Confirm password', validators=[DataRequired(),EqualTo('password')])
submit = SubmitField('Sign Up')
def validate_username(self, username):
user = User.query.filter_by(username=username.data).first()
if user:
raise ValidationError('That username is taken. Please choose
another.')
def validate_email(self, email):
user = User.query.filter_by(email=email.data).first()
if user:
raise ValidationError('That email is taken. Please choose another.')
So, the specific part that I don't understand are the two functions in the RegistrationForm class: Firstly, how do both of the functions know what username and email is? For example if I changed the 'username' and 'email' arguments in the function definitions to something like 'u_n' and 'e_mail' and then ran the query with 'u_n.data' and 'e_mail.data', the code still works. Secondly if I'm to rename the functions to anything else the code stops working and I don't understand why?
I know the answer to this cannot be too complicated but this has annoyed me so much. Any help would be greatly appreciated.
I am going to explain this thoroughly, so bear with me as I will answer your specific questions at the end, to make sure you fully understand how all the pieces work together.
Your form definition is given with this chunk of code:
class RegistrationForm(FlaskForm):
username = StringField('Username', validators=[DataRequired(), Length(min=4, max=20)])
email = StringField('Email', validators=[DataRequired(), Email()])
password = PasswordField('Password', validators=[DataRequired()])
password_confirm = PasswordField('Confirm password', validators=[DataRequired(),EqualTo('password')])
submit = SubmitField('Sign Up')
This is what creates the form's UI on the screen and ultimately what the user sees when they're signing up. This form creation is accomplished with the flask_wtf library, and is rendered within an html page with the help of Jinja2. Jinja2 is a templating engine that Python can leverage to serve server-side pages with dynamic data. Now what do the variables within this form definition mean? I.e. [username, email, password, confirm_password, submit] well these are references to the form's fields. For example, when the user typed in their information to sign up for an account on your site, the username they used is accessed by referencing the form.username.data field. Similarly, to get the password they used, to sign up with, you have to reference the form.password.data field and so on and so forth... The validation functions: validate_username(...) and validate_email(..) are class methods you created on your RegistrationForm(FlaskForm) class to validate the uniqueness of a user's email and username when he/she submits their account details by clicking the Sign Up button. If another user is already using this username or email an error will be thrown. So how is this accomplished? This validation is assisted by your model definitions created within your models.py file:
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
image_file = db.Column(db.String(20), nullable=False, default='default.jpg')
password = db.Column(db.String(60), nullable=False)
posts = db.relationship('Post', backref='author', lazy=True)
def __repr__(self):
return f"User('{self.username}', '{self.email}', '{self.image_file}')"
These models are leveraging flask-sqlalchemy, a wrapper around sqlalchemy, to make queries within your tables, in this example your user table. Sqlalchemy is a Python SQL toolkit and ORM that makes it easy to submit SQL queries as well as map objects to table definitions and vice versa. So user = User.query.filter_by(username=username.data).first() is leveraging your User model definition, which has been setup with flask-sqlalchemy, to query your user table to see if anyone else has signed up with that username. The from flaskblog.models import User is the import statement which is allowing you to use your User model to query your user table from within your form definition file. Furthermore, the reason we can use username.data instead of having to use form.username.data is because this is an object method within your RegistrationForm so we have direct access to the username and email form fields.
Now to answer your questions:
Answer: These are just function parameter variables and can be named however you see fit since you're passing the username (or email) form field directly into the function through the function declaration. i.e. validate_<field_name>
Answer:
Your validation methods have to follow the validate_<field_name> convention specified within flask-wtf In your example, your form fields are: [username, email, password, confirm_password, submit] so your validation methods would have to be: validate_username(...), validate_email(...), validate_password(...), etc... If you want to have a different validation method name you would also have to correspondingly rename your form fields appropriately.
Hopefully that helps!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With