Thông báo: Download 4 khóa học Python từ cơ bản đến nâng cao tại đây.
Django Registration trong Python
Trong bài này, mình sẽ học cách tạo một form đăng ký Django cho phép người dùng đăng ký tài khoản. Hướng dẫn này sẽ tiếp nối từ phần cuối của hướng dẫn đăng nhập/đăng xuất Django, giúp bạn hoàn thiện hệ thống quản lý người dùng cho ứng dụng của mình.
Bắt đầu từ việc thiết lập form đăng ký, xử lý dữ liệu từ người dùng, cho đến việc tùy chỉnh và bảo mật thông tin, tất cả sẽ được trình bày một cách chi tiết và dễ hiểu. Hãy cùng tìm hiểu các bước để mang lại trải nghiệm người dùng tốt nhất cho web của bạn nhé.
Bạn có thể tải dự án form đăng ký Django bằng Python xuống tại đây.
Tạo Form đăng ký Django bằng Python
Bước đầu tiên, định nghĩa URL đăng ký trong urls.py
của ứng dụng users
:
from django.urls import path from . import views #Bài viết này được đăng tại freetuts.net urlpatterns = [ path('login/', views.sign_in, name='login'), path('logout/', views.sign_out, name='logout'), path('register/', views.sign_up, name='register'), ]
Tiếp theo, khai báo lớp RegisterForm
trong forms.py
của file users
:
Bài viết này được đăng tại [free tuts .net]
from django import forms from django.contrib.auth.models import User from django.contrib.auth.forms import UserCreationForm class LoginForm(forms.Form): username = forms.CharField(max_length=65) password = forms.CharField(max_length=65, widget=forms.PasswordInput) #Bài viết này được đăng tại freetuts.net class RegisterForm(UserCreationForm): class Meta: model = User fields = ['username', 'email', 'password1', 'password2']
RegisterForm
sử dụng mô hình User tích hợp sẵn và bao gồm bốn trường: tên người dùng, email, mật khẩu1 và mật khẩu2 mà người dùng cần điền vào để đăng ký.
Sau đó, định nghĩa hàm sign_up()
trong views.py
của ứng dụng users
:
from django.shortcuts import render, redirect from django.contrib import messages from django.contrib.auth import login, authenticate, logout from .forms import LoginForm, RegisterForm #Bài viết này được đăng tại freetuts.net def sign_up(request): if request.method == 'GET': form = RegisterForm() return render(request, 'users/register.html', {'form': form})
Hàm sign_up()
tạo đối tượng RegisterForm
và render nó trong template register.html
.
Tạo template register.html
trong thư mục templates/users
của ứng dụng users
:
{% extends 'base.html' %} #Bài viết này được đăng tại freetuts.net {% block content %} <form method="POST" novalidate> {% csrf_token %} <h2>Sign Up</h2> {{ form.as_p }} <input type="submit" value="Register" /> </form> {% endblock content %}
register.html
kế thừa từ template base.html
của dự án. Nó render RegisterForm
(form).
Lưu ý rằng thuộc tính novalidate
loại bỏ xác thực HTML5. Sau khi hoàn thành dự án, bạn có thể loại bỏ thuộc tính này để bật xác thực HTML5.
Cuối cùng, mở URL đăng ký:
http://127.0.0.1:8000/register/
Bạn sẽ thấy form đăng ký như sau:
Tùy chỉnh Form đăng ký Django bằng Python
Form đăng ký có bốn trường với nhiều thông tin. Thông tin này đến từ mô hình User mặc định.
Nếu bạn muốn tùy chỉnh thông tin hiển thị trên form, bạn có thể sửa đổi template register.html
như sau:
{% extends 'base.html' %} {% block content %} <form method="POST" novalidate> {% csrf_token %} <h2>Sign Up</h2> {% for field in form %} <p> {% if field.errors %} <ul class="errorlist"> {% for error in field.errors %} <li>{{ error }}</li> {% endfor %} </ul> {% endif %} {{ field.label_tag }} {{ field }} </p> #Bài viết này được đăng tại freetuts.net {% endfor %} <input type="submit" value="Register" /> </form> {% endblock content %}
Template này lặp qua các trường của form và hiển thị từng trường một cách riêng biệt. Đối với mỗi trường, nó hiển thị danh sách lỗi nếu xác thực không thành công.
Form mới sẽ trông như sau:
Nếu bạn điền thông tin và nhấn đăng ký, bạn sẽ nhận được lỗi vì mình chưa thêm mã xử lý yêu cầu HTTP POST.
Xử lý Logic đăng ký Django bằng Python
Để xử lý yêu cầu HTTP POST, bạn sửa đổi hàm sign_up()
trong file views.py
của ứng dụng users
:
def sign_up(request): if request.method == 'GET': form = RegisterForm() return render(request, 'users/register.html', {'form': form}) #Bài viết này được đăng tại freetuts.net if request.method == 'POST': form = RegisterForm(request.POST) if form.is_valid(): user = form.save(commit=False) user.username = user.username.lower() user.save() messages.success(request, 'You have signed up successfully.') login(request, user) return redirect('posts') else: return render(request, 'users/register.html', {'form': form})
Cách hoạt động:
Đầu tiên, tạo một instance mới của RegisterForm
:
form = RegisterForm(request.POST)
Nếu form hợp lệ, mình lưu form nhưng không lưu ngay vào cơ sở dữ liệu. Điều này được thực hiện bằng cách truyền đối số commit=False
cho phương thức save()
của đối tượng form.
Lý do là mình muốn chuyển tên người dùng thành chữ thường trước khi lưu vào cơ sở dữ liệu:
user.username = user.username.lower() user.save()
Sau khi lưu người dùng, mình tạo thông báo flash, đăng nhập người dùng và chuyển hướng người dùng đến trang danh sách bài viết:
messages.success(request, 'You have signed up successfully.') login(request, user) return redirect('posts')
Nếu form không hợp lệ, mình sẽ render lại form với các giá trị đã nhập trước đó bằng cách truyền đối tượng form vào hàm render()
:
return render(request, 'users/register.html', {'form': form})
Ví dụ sau đây minh họa cách đăng ký một người dùng với tên người dùng là freetuts.net:
Thêm các liên kết
Đầu tiên, bao gồm liên kết đăng ký bằng cách sửa đổi template base.html
. Cũng bao gồm các liên kết My Posts và New Post nếu người dùng đã đăng nhập:
{% load static %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" href="{% static 'css/style.css' %}" /> <script src="{% static 'js/app.js' %}" defer></script> <title>My Site</title> </head> <body> <header> {% if request.user.is_authenticated %} <a href="{% url 'posts' %}">My Posts</a> <a href="{% url 'post-create' %}">New Post</a> <span>Hi {{ request.user.username | title }}</span> <a href="{% url 'logout' %}">Logout</a> {% else %} <a href="{% url 'login' %}">Login</a> <a href="{% url 'register' %}">Register</a> {% endif %} </header> <main> {% if messages %} #Bài viết này được đăng tại freetuts.net <div class="messages"> {% for message in messages %} <div class="alert {% if message.tags %}alert-{{ message.tags }}"{% endif %}> {{ message }} </div> {% endfor %} </div> {% endif %} {% block content %} {% endblock content %} </main> </body> </html>
Thứ hai, bao gồm liên kết đăng ký trong template login.html
:
{% extends 'base.html' %} #Bài viết này được đăng tại freetuts.net {% block content %} <form method="POST" novalidate> {% csrf_token %} <h2>Login</h2> {{ form.as_p }} <input type="submit" value="Login" /> <p>Don't have an account? <a href="{% url 'register' %}">Register</a></p> </form> {% endblock content %}
Thứ ba, thêm liên kết đăng nhập vào trang register.html
:
{% extends 'base.html' %} {% block content %} <form method="POST" novalidate> {% csrf_token %} <h2>Sign Up</h2> {% for field in form %} <p> #Bài viết này được đăng tại freetuts.net {% if field.errors %} <ul class="errorlist"> {% for error in field.errors %} <li>{{ error }}</li> {% endfor %} </ul> {% endif %} {{ field.label_tag }} {{ field }} </p> {% endfor %} <input type="submit" value="Register" /> <p>Bạn đã có tài khoản? <a href="{% url 'login' %}">Login</a></p> </form> {% endblock content %}
Ngăn người dùng chỉnh sửa/xóa bài viết của người khác
Thông thường, người dùng không nên có quyền chỉnh sửa hoặc xóa bài viết của người dùng khác. Tuy nhiên, người dùng có thể xem bài viết của người dùng khác.
Để triển khai chức năng này, mình cần kiểm tra xem tác giả của bài viết có giống với người dùng hiện tại đã đăng nhập hay không. Nếu có, mình sẽ hiển thị các form chỉnh sửa/xóa. Ngược lại, mình có thể chuyển hướng người dùng đến trang 404.
Ngoài ra, mình cần ẩn các liên kết chỉnh sửa và xóa của trang danh sách bài viết nếu bài viết không thuộc về người dùng.
Đầu tiên, sửa đổi views.py
của ứng dụng blog
:
from django.shortcuts import render, redirect, get_object_or_404 from django.contrib import messages from django.contrib.auth.decorators import login_required from .models import Post from .forms import PostForm @login_required def delete_post(request, id): post = get_object_or_404(Post, pk=id) context = {'post': post} #Bài viết này được đăng tại freetuts.net if request.method == 'GET': return render(request, 'blog/post_confirm_delete.html', context) elif request.method == 'POST': post.delete() messages.success(request, 'Bài viết đã được xóa thành công.') return redirect('posts') @login_required def edit_post(request, id): post = get_object_or_404(Post, id=id) if request.method == 'GET': context = {'form': PostForm(instance=post), 'id': id} return render(request, 'blog/post_form.html', context) #Bài viết này được đăng tại freetuts.net elif request.method == 'POST': form = PostForm(request.POST, instance=post) if form.is_valid(): form.save() messages.success( request, 'Bài viết đã được cập nhật thành công.') return redirect('posts') else: messages.error(request, 'Vui lòng chỉnh sửa lại các lỗi sau:') return render(request, 'blog/post_form.html', {'form': form}) @login_required def create_post(request): if request.method == 'GET': context = {'form': PostForm()} return render(request, 'blog/post_form.html', context) elif request.method == 'POST': form = PostForm(request.POST) if form.is_valid(): user = form.save(commit=False) user.author = request.user user.save() messages.success(request, 'Bài viết đã được tạo thành công.') return redirect('posts') else: messages.error(request, 'Vui lòng chỉnh sửa lại các lỗi sau:') return render(request, 'blog/post_form.html', {'form': form}) #Bài viết này được đăng tại freetuts.net def home(request): posts = Post.objects.all() context = {'posts': posts} return render(request, 'blog/home.html', context)
Trong cả hai trường hợp xóa và cập nhật, mình lọc bài viết theo người dùng hiện tại trước khi truyền nó cho hàm get_object_or_404()
.
Nếu bạn đăng nhập dưới tên Jane và cố gắng chỉnh sửa một bài viết không thuộc về Jane, bạn sẽ nhận được lỗi 404. Ví dụ:
Trang 404:
Thứ hai, sửa đổi template home.html
để ẩn các liên kết chỉnh sửa và xóa.
{% extends 'base.html' %} {% block content %} <h1>My Posts</h1> {% for post in posts %} <h2>{{ post.title }}</h2> <small>Published on {{ post.published_at | date:"M d, Y" }} by {{ post.author | title }}</small> <p>{{ post.content }}</p> #Bài viết này được đăng tại freetuts.net {% if request.user.is_authenticated and request.user == post.author %} <p> <a href="{% url 'post-edit' post.id %}">Edit</a> <a href="{% url 'post-delete' post.id %}">Delete</a> </p> {% endif %} {% endfor %} {% endblock content %}
Loại bỏ tác giả khỏi form tạo bài viết
Đầu tiên, loại bỏ trường tác giả khỏi các trường của lớp PostForm
:
from django.forms import ModelForm from .models import Post class PostForm(ModelForm): class Meta: model = Post fields = ['title', 'content']
Form tạo bài viết sẽ trông như thế này:
Thứ hai, sửa đổi hàm create_post()
trong views.py
của ứng dụng blog
để cập nhật tác giả của bài viết thành người dùng hiện tại đã đăng nhập:
@login_required def create_post(request): #Bài viết này được đăng tại freetuts.net if request.method == 'GET': context = {'form': PostForm()} return render(request, 'blog/post_form.html', context) elif request.method == 'POST': form = PostForm(request.POST) if form.is_valid(): user = form.save(commit=False) user.author = request.user user.save() messages.success(request, 'The post has been created successfully.') return redirect('posts') else: messages.error(request, 'Please correct the following errors:') return render(request, 'blog/post_form.html', {'form': form})
Bạn có thể tải dự án form đăng ký Django bằng Python xuống tại đây.
Kết bài
Qua hướng dẫn này, bạn đã học được cách tạo một form đăng ký Django giúp người dùng có thể đăng ký tài khoản một cách dễ dàng và bảo mật. Từ việc thiết lập URL và form đăng ký, xử lý yêu cầu HTTP, đến việc tùy chỉnh giao diện và bảo vệ dữ liệu người dùng, bạn đã nắm bắt được các bước cơ bản và quan trọng để xây dựng một hệ thống quản lý người dùng hoàn chỉnh. Việc tích hợp chức năng đăng ký này không chỉ nâng cao trải nghiệm người dùng mà còn giúp bạn quản lý người dùng hiệu quả hơn. Hãy tiếp tục tìm hiểu những công cụ mà Django cung cấp để phát triển các ứng dụng web chuyên nghiệp và đáng tin cậy.
Danh sách file tải về
Tên file tải về | Pass giải nén |
---|---|
Django Registration trong Python | Không có |