在我开发第5阶段项目的过程中,实现的一个最重要的特性是数据验证。从后端到前端,一致的验证功能有助于保持数据库的完整性并确保数据一致性,并通过屏幕上的错误和成功提示,为用户提供友好的体验。
在这篇博客里,我会通过一个例子来带您了解在注册流程中如何验证主要用户属性之一(例如用户名)。我将使用Flask和SQLAlchemy来处理后端验证,同时使用Formik和Yup来处理前端验证。
在后端:使用 Flask 和 SQLAlchemy 验证用户名的有效性我们先从Flask/SQLAlchemy后端和User模型开始。这里实现了验证,以确保用户名是唯一的、格式正确,并符合一些基本的验证规则,在添加到数据库之前。
使用SQLAlchemy的用户模型(User Model)下面这个用户模型定义了用户名字段,并使用SQLAlchemy的@validates
装饰器进行了验证。
db = SQLAlchemy()class User(db.Model):
__tablename__ = 'users' id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String, unique=True, nullable=False)
# 其他属性 ... additional attributes
@validate('username')
def validate_username(self, key, username):
if not username:
raise ValueError("请输入用户名。")
if len(username) < 5:
raise ValueError("用户名必须至少包含5个字符。")
if not re.match(r'^[\w_]+
已实施的验证:
* **唯一性**:在数据库中将属性标记为 `unique=True` 可以确保每个用户名都是独一无二的。
* **必填项**:`if not username` 检查用户名字段是否为空。
* **最小长度**:`len(username) < 5` 检查用户名长度是否小于 5 个字符。
* **格式**:正则表达式 `^[\w_]+# 前后端协作实现用户名验证:利用SQLAlchemy和Formik/Yup进行表单验证
在我开发第5阶段项目的过程中,实现的一个最重要的特性是**数据验证**。从后端到前端,一致的验证功能有助于保持数据库的完整性并确保数据一致性,并通过屏幕上的错误和成功提示,为用户提供友好的体验。
在这篇博客里,我会通过一个例子来带您了解在注册流程中如何验证主要用户属性之一(例如用户名)。我将使用**Flask**和**SQLAlchemy**来处理后端验证,同时使用**Formik**和**Yup**来处理前端验证。
# 在后端:使用 Flask 和 SQLAlchemy 验证用户名的有效性
我们先从**Flask/SQLAlchemy**后端和User模型开始。这里实现了验证,以确保用户名是唯一的、格式正确,并符合一些基本的验证规则,在添加到数据库之前。
## 使用SQLAlchemy的用户模型(User Model)
下面这个用户模型定义了用户名字段,并使用SQLAlchemy的`@validates`装饰器进行了验证。
db = SQLAlchemy()class User(db.Model):
tablename = 'users' id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String, unique=True, nullable=False)
@validate('username')
def validate_username(self, key, username):
if not username:
raise ValueError("请输入用户名。")
if len(username) < 5:
raise ValueError("用户名必须至少包含5个字符。")
if not re.match(r'^[\w_]+
已实施的验证:
检查用户名是否只包含字母、数字和下划线。
- 检查重复:
User.query.filter_by()
方法查询数据库中是否已有相同用户名。
以下是处理用户注册的注册资源页面,应用了模型验证逻辑。
class Signup(Resource):
def post(self):
data = request.get_json()
username = data.get('username')
try:
new_user = User(
username=username.lower(),
... 其他相关属性
)
db.session.add(new_user)
db.session.commit()
session['username'] = new_user.username
return jsonify({'message': '用户注册成功。'}), 201
except ValueError as e:
return jsonify({'error': str(e)}), 400
except IntegrityError as e:
return jsonify({'error': str(e)}), 409
except Exception as e:
return jsonify({'error': str(e)}), 500
class CheckUsername(Resource):
def get(self, un):
un = un.lower()
existing_user = User.query.filter_by(un=un).first()
if existing_user:
return {'error': '用户名已存在。'}, 400
return {'message': '该用户名可用。'}, 200
注册步骤:
如果任何验证(例如唯一性或格式验证)失败,将会抛出一个 ValueError
,except
块捕获该异常并返回一个 400
错误。
The User.query.filter_by()
方法查询数据库中,检查用户名是否已存在。
后台验证已经处理好了,现在用户名可以在前端通过Formik和Yup进行实时验证。
表单注册组件,与 Formik 和 Yup下面是SignupForm组件,它导入了Formik进行表单处理和Yup进行验证:
function SignupForm() {
const checkUsername = (username) => {
formik.setFieldError("username", "");
formik.setStatus({ usernameAvailable: "" });
fetch(`/check_username/${username}`)
.then((r) => r.json())
.then((data) => {
if (data.error) {
formik.setFieldError("username", data.error);
} else {
formik.setStatus({ usernameAvailable:
data.message });
}
})
.catch((error) => {
console.error("用户名检查错误:", error.message);
});
};
useFormik({
initialValues: {
username: "",
...其他属性
},
validationSchema: Yup.object({
username: Yup.string()
.required("用户名是必填的")
.matches(/^[\w]+$/, "用户名只能包含字母、数字和下划线。")
.min(5, "用户名必须至少包含5个字符。")
.test("check-username", "检查用户名...",
function(value) {
if (value) {
checkUsername(value);
}
return true;
}),
...其他属性
}),
onSubmit: (values) => {
const newUser = {
username: values.username,
...其他属性
};
signup(newUser);
},
});
return (
<div>
<h1>注册</h1>
<form onSubmit={formik.handleSubmit}>
<div>
<label>用户名:</label>
<input
type="text"
id="username"
name="username"
onChange={(e) => {
formik.handleChange(e);
checkUsername(e.target.value);
}}
value={formik.values.username}
/>
<p>{!formik.errors.username && formik.status
? formik.status.usernameAvailable
: formik.errors.username}</p>
</div>
<button type="submit">注册</button>
</form>
</div>
);
}
export default SignupForm;
解释:
- 实时用户名验证:用户输入时,
checkUsername
函数会在 Formik 中触发。此函数向后端发送请求以验证用户名是否可用。 - Yup 验证:在提交之前,Formik 确保用户名符合要求规则(最小长度、格式等)。如果验证失败,会立即显示相应的错误消息。
在这篇博客里,我讲解了如何进行用户名验证,既在后端(使用 Flask 和 SQLAlchemy)上,也在前端(使用 Formik 和 Yup)上。同时在客户端和服务器端验证用户名,这样可以让你的应用程序既安全又好用。
- 后端验证 确保系统进入数据库的数据是有效的,并符合规定的规则(比如,唯一性,格式)。
- 前端验证 向用户即时提供反馈,减少不必要的服务器交互。
通过将这些技术结合起来,你可以构建一个坚实且可靠的表单验证系统,使其在整个技术栈中顺畅运行。
, username):
raise ValueError("用户名只能包含字母、数字和下划线。")
if User.query.filter_by(username=username).first():
raise ValueError("该用户名已存在。")
return username
Validations implemented:
* **Uniqueness** : Marking the attribute as `unique=True` in the database ensures that no two users can have the same username.
* **Required** : `if not username` checks if the username field is empty.
* **Minimum length** : `len(username) < 5` checks if the username less than 5 characters long.
* **Format** : The regular expression `^[\w_]+$` checks the username from the first character to the last, ensuring the username only contains letters, numbers, and underscores.
* **Check for duplicates** : The `User.query.filter_by()` method queries the database checking to see if the username already exists.
## Signup Resource in Flask
Below is the **signup resource** where user registration is handled and the validation logic from the model is applied:
class Signup(Resource):
def post(self):
data = request.get_json()
username = data.get('username')
... other attributes try:
new_user = User(
username=username.lower(),
... other attributes
) db.session.add(new_user)
db.session.commit()
session['username'] = new_user.username return jsonify({'message': 'User registered
successfully.'}), 201 except ValueError as e:
return jsonify({'error': str(e)}), 400 except IntegrityError as e:
return jsonify({'error': str(e)}), 409 except Exception as e:
return jsonify({'error': str(e)}), 500class CheckUsername(Resource):
def get(self, un):
un = un.lower()
existing_user = User.query.filter_by(un=un).first() if existing_user:
return {'error': 'Username already exists.'}, 400 return {'message': 'Username is available.'}, 200
## Signup Resource:
If any validation fails (either backend validation like uniqueness or format), a `ValueError` is raised which is caught in the `except` block and returned as a `400` error.
## Check Username Resource:
The `User.query.filter_by()` method queries the database checking to see if the username already exists.
# Frontend: Validating Usernames with Formik and Yup
Now that the backend validations have been handled, the username can be validated in real-time on the frontend with **Formik** and **Yup**.
## Signup Form Component with Formik and Yup
Below is the **SignupForm** component which imports **Formik** for form handling and **Yup** for validation:
function SignupForm() {
const checkUsername = (username) => {
formik.setFieldError("username", "");
formik.setStatus({ usernameAvailable: "" }); fetch(`/check_username/${username}`)
.then((r) => r.json())
.then((data) => {
if (data.error) {
formik.setFieldError("username", data.error);
} else {
formik.setStatus({ usernameAvailable:
data.message });
}
})
.catch((error) => {
console.error("Username check error:",
error.message);
});
}; const formik = useFormik({
initialValues: {
username: "",
... other attributes
},validationSchema: Yup.object({
username: Yup.string()
.required("Username is required")
.matches(/^[\w]+$/, "Username can only contain
letters, numbers, and underscores.")
.min(5, "Username must be at least 5 characters.")
.test("check-username", "Checking username...",
function(value) {
if (value) {
checkUsername(value);
}
return true;
}),
... other attributes
}), onSubmit: (values) => {
const newUser = {
username: values.username,
... other attributes
};
signup(newUser);
},
}); return (
<div>
<h1>Sign Up</h1>
<form onSubmit={formik.handleSubmit}>
<div>
<label>Username:</label>
<input
type="text"
id="username"
name="username"
onChange={(e) => {
formik.handleChange(e);
checkUsername(e.target.value);
}}
value={formik.values.username}
/>
<p>{!formik.errors.username && formik.status
? formik.status.usernameAvailable
: formik.errors.username}</p>
</div>
<button type="submit">Sign Up</button>
</form>
</div>
);
}export default SignupForm;
## Explanation:
* **Real-time Username Validation** : The `checkUsername` function is triggered in Formik as the user types. This function sends a request to the backend to check if the username is available.
* **Yup Validation** : Before submitting, Formik ensures the username follows the required rules (minimum length, format, etc.). If the validation fails, the error message is displayed immediately.
# Conclusion
In this blog post, I’ve shown how to handle **username validation** both on the **backend** (using Flask and SQLAlchemy) and the **frontend** (using Formik and Yup). By validating the username both client-side and server-side, you ensure that your application is both secure and user-friendly.
* **Backend validation** ensures that the data entering your database is valid and conforms to the required rules (e.g., uniqueness, formatting).
* **Frontend validation** provides immediate feedback to users, reducing unnecessary requests to the server.
By combining these techniques, you can build a solid, reliable form validation system that works seamlessly across the entire stack.
共同学习,写下你的评论
评论加载中...
作者其他优质文章