Django从零搭建卖家中心注册页面实战

发布于:2025-04-12 ⋅ 阅读:(49) ⋅ 点赞:(0)

在电商系统开发中,卖家中心是一个重要的组成部分,而用户注册与登陆则是卖家中心的第一步。本文将详细介绍如何使用Django框架从零开始搭建一个功能完善的卖家注册页面,包括前端界面设计和后端逻辑实现。

一、项目概述

  1. 我们将创建一个名为seller_center的Django项目,实现卖家登陆与注册功能,包括:

    • 用户注册与登陆表单
    • 表单验证
    • 数据库存储
    • 成功提示页面
  2. Django 框架流程

    # 1. 运行 python manage.py runserver 启动开发服务器, manage.py 设置 DJANGO_SETTINGS_MODULE 环境变量并调用 Django 的命令行执行函数。
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'seller_center.settings')
    
    # 2. Django 根据 DJANGO_SETTINGS_MODULE 加载 settings.py 文件,读取项目的配置信息。
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME': 'your_database_name',
            'USER': 'your_database_user',
            'PASSWORD': 'your_database_password',
            'HOST': 'your_database_host',
            'PORT': 'your_database_port',
        }
    }
    
    # 3. 开发服务器加载 wsgi.py 文件,创建 WSGI 应用对象(Web 服务器网关接口)。
    
    # 4. 浏览器发送请求到 http://localhost:8000/ ,Web 服务器将请求传递给 WSGI 应用对象。
    
    # 5. WSGI 应用对象根据 settings.py 中配置的 ROOT_URLCONF 找到 urls.py 文件,根据请求的 URL 路径查找对应的视图函数。
    ROOT_URLCONF = 'seller_center.urls'
    
    # 6. 调用相应的视图函数处理请求,并将处理结果返回给客户端。 	
    eg. 注册流程从用户在 register.html 页面提交表单开始,经过 urls.py 进行路由匹配,调用 views.py 中的视图函数处理请求,使用 forms.py 进行表单验证,最后通过 models.py 将数据保存到数据库。
    

二、环境准备

首先,确保已安装Python和pip,然后准备一个requirements.txt,内容如下

# Django 框架
Django
# Django 表单美化库
django-crispy-forms
# 配合 django-crispy-forms 使用的 Bootstrap 5 样式库
crispy-bootstrap5
# Python 连接 MySQL 数据库的驱动
mysqlclient
# 用于加载环境变量的库
python-dotenv
pip install -r requirements.txt

三、创建项目

  1. 创建Django项目
django-admin startproject seller_center
cd seller_center
  1. 创建应用
python manage.py startapp users

四、设计数据模型

  1. 执行数据库迁移 :
python manage.py makemigrations
python manage.py migrate
注:可能需要对库下的表授权
  1. 在users/models.py中创建卖家模型:
from django.db import models

class Seller(models.Model):
    """
    卖家模型
    """
    id = models.BigAutoField(primary_key=True)
    username = models.CharField('用户名', max_length=50, unique=True)
    password = models.CharField('密码', max_length=100)
    real_name = models.CharField('真实姓名', max_length=50, null=True, blank=True)
    phone = models.CharField('电话', max_length=20, null=True, blank=True)
    email = models.CharField('邮箱', max_length=100, null=True, blank=True)
    status = models.IntegerField('状态', default=1, help_text='状态:0-禁用 1-启用')
    create_time = models.DateTimeField('创建时间', auto_now_add=True)
    update_time = models.DateTimeField('更新时间', auto_now=True)

    class Meta:
        app_label = 'users'
        managed = False,
        db_table = 'seller'
        verbose_name = '卖家'
        verbose_name_plural = '卖家列表'

    def __str__(self):
        return self.username
  1. 创建自定义表
CREATE TABLE `seller` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `username` varchar(50) NOT NULL,
  `password` varchar(100) NOT NULL,
  `real_name` varchar(50) DEFAULT NULL,
  `phone` varchar(20) DEFAULT NULL,
  `email` varchar(100) DEFAULT NULL,
  `status` tinyint DEFAULT '1' COMMENT '状态:0-禁用 1-启用',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP,
  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `username` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

五、创建表单

  1. 在users/forms.py中创建注册表单:
from django import forms
import hashlib
from django.contrib.auth.hashers import make_password, check_password
from django.contrib.auth.password_validation import validate_password
from django.core.exceptions import ValidationError
from .models import Seller

# 封装表单字段属性
def get_form_field_attrs(placeholder, autocomplete):
    return {
        'class': 'form-control',
        'placeholder': placeholder,
        'autocomplete': autocomplete
    }

# 创建一个基类来封装重复的字段和验证逻辑
class BaseSellerLoginForm(forms.Form):
    username = forms.CharField(
        widget=forms.TextInput(attrs=get_form_field_attrs('用户名', 'username'))
    )
    password = forms.CharField(
        widget=forms.PasswordInput(attrs=get_form_field_attrs('密码', 'current-password'))
    )

    def clean(self):
        cleaned_data = super().clean()
        username = cleaned_data.get('username')
        password = cleaned_data.get('password')

        if username and password:
            try:
                seller = Seller.objects.get(username=username)
                if seller.status == 0:
                    raise forms.ValidationError('该账号已被禁用,请联系管理员')
                if not check_password(password, seller.password):
                    raise forms.ValidationError('用户名或密码不正确')
                cleaned_data['seller'] = seller
            except Seller.DoesNotExist:
                raise forms.ValidationError('用户名或密码不正确')
        return cleaned_data

# 继承自 BaseSellerLoginForm
class SellerLoginForm(BaseSellerLoginForm):
    """
    卖家登录表单
    """
    def get_validated_seller(self):
        """
        获取验证后的卖家对象,如果验证失败返回 None
        """
        if self.is_valid(): # is_valid() 方法会触发表单类的 clean() 方法
            return self.cleaned_data.get('seller')
        return None

class SellerRegistrationForm(forms.ModelForm):
    """
    卖家注册表单
    """
    password1 = forms.CharField(
        label='密码',
        widget=forms.PasswordInput(attrs=get_form_field_attrs('请设置密码', 'new-password')),
        help_text='密码长度不少于8位,包含字母和数字'
    )
    password2 = forms.CharField(
        label='确认密码',
        widget=forms.PasswordInput(attrs=get_form_field_attrs('请再次输入密码', 'new-password'))
    )

    class Meta:
        model = Seller
        fields = ['username', 'real_name', 'phone', 'email']
        widgets = {
            field: forms.TextInput(attrs=get_form_field_attrs(f'请输入{label}', autocomplete))
            for field, label, autocomplete in [
                ('username', '用户名', 'username'),
                ('real_name', '真实姓名', None),
                ('phone', '手机号码', 'tel'),
                ('email', '邮箱地址', 'email')
            ]
        }
        labels = {
            'username': '用户名',
            'real_name': '真实姓名',
            'phone': '手机号码',
            'email': '邮箱地址'
        }

    def clean_username(self):
        username = self.cleaned_data.get('username')
        if Seller.objects.filter(username=username).exists():
            raise forms.ValidationError('用户名已存在,请更换')
        return username

    def clean_password2(self):
        password1 = self.cleaned_data.get('password1')
        password2 = self.cleaned_data.get('password2')

        if password1 and password2 and password1 != password2:
            raise forms.ValidationError('两次输入的密码不一致')

        try:
            validate_password(password1)
        except ValidationError as e:
            self.add_error('password1', e)

        return password2

    def save(self, commit=True):
        seller = super().save(commit=False)
        # 对密码进行哈希处理
        seller.password = make_password(self.cleaned_data['password1'])
        if commit:
            seller.save()
        return seller  # 返回 seller 实例

六、创建视图

在users/views.py中实现注册视图:

from django.shortcuts import render, redirect
from django.http import HttpResponse  # HttpResponse 仍然从 django.http 导入
from .forms import SellerRegistrationForm, SellerLoginForm
from .models import Seller
import hashlib
from django.contrib.auth.hashers import check_password
import logging

def register_seller(request):
    """
    卖家注册视图
    :param request: 请求对象
    :return: 渲染后的注册页面或重定向到登录页面
    """
    if request.method == 'POST':
        form = SellerRegistrationForm(request.POST)
        if form.is_valid():
            # 创建新的卖家账号
            seller = form.save(commit=True)
            return redirect('login_seller')
        else:
            # 处理表单验证失败的情况
            print(form.errors)  # 打印表单错误信息
    else:
        form = SellerRegistrationForm()

    return render(request, 'users/register.html', {'form': form})

# 配置日志记录
logger = logging.getLogger(__name__)

def login_seller(request):
    """
    卖家登录视图
    :param request: 请求对象
    :return: 渲染后的登录页面或重定向到订单列表页面
    """
    if request.method == 'POST':
        # 简化表单验证和获取卖家对象的逻辑
        if (seller := SellerLoginForm(request.POST).get_validated_seller()):
            # 登录成功,设置 cookie
            response = redirect('base_page')
            response.set_cookie('seller_id', seller.id, max_age=3600 * 24 * 7)
            return response
        else:
            # 表单验证失败
            form = SellerLoginForm(request.POST)
            logger.error(f"表单验证失败: {form.errors}")
            # 将错误信息传递到模板
            return render(request, 'users/login.html', {'form': form})
    else:
        form = SellerLoginForm()

    return render(request, 'users/login.html', {'form': form})

def base_page_view(request):
    return render(request, 'base.html')


七、配置URL

  1. 修改seller_center/urls.py:
from django.urls import path, include
from django.shortcuts import render
from django.http import HttpResponse, HttpResponseRedirect

def home_view(request):
    return HttpResponseRedirect('/users/login/')

urlpatterns = [
    # 映射空路径到主页视图函数,命名为home
    path('', home_view, name='home'),
    # 修改登录路由,指向 users 应用的 urls.py 文件
    path('users/', include('users.urls')),
]
  1. 创建users/urls.py:
from django.urls import path
from .views import register_seller, login_seller, base_page_view

urlpatterns = [
    path('register/', register_seller, name='register_seller'),
    path('login/', login_seller, name='login_seller'),
    path('base/', base_page_view, name='base_page'),
]

八、创建模板

  1. 创建基础模板
    首先在项目根目录创建templates文件夹,并在settings.py中配置:
import os # 导入 os 模块,用于与操作系统进行交互,例如文件路径操作
...

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],  # 添加这一行
        'APP_DIRS': True,
        # ...其他配置...
    },
]
  1. 创建templates/base.html:
{% load static %}
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
    <title>{% block title %}卖家中心{% endblock %}</title>
    <style>
        body {
            background-color: #f8f9fa;
        }
        .container {
            max-width: 2500px;
            margin: 80px auto;
            padding: 30px;
            background-color: #fff;
            border-radius: 10px;
            box-shadow: 0 0 15px rgba(0,0,0,0.1);
        }
        .title {
            text-align: center;
            margin-bottom: 30px;
            color: #333;
        }
        .form-group {
            margin-bottom: 20px;
        }
        .btn-action {
            width: 100%;
            padding: 10px;
            border: none;
        }
        .link {
            text-align: center;
            margin-top: 20px;
        }
    </style>
</head>
<body>
    <div class="container">
        欢迎来到卖家中心!
        {% block content %}
        <!-- 页面内容将在这里填充 -->
        {% endblock %}
    </div>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
  1. 创建注册页面
    创建templates/users/register.html:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>卖家注册</title>
    <!-- Bootstrap 5 CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
    <!-- Bootstrap Icons -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.1/font/bootstrap-icons.css">
    <style>
        body {
            background-color: #f8f9fa;
            height: 100vh;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        /* 统一容器样式,与登录页面保持一致 */
        .register-container {
            max-width: 420px; /* 修改为与登录页面一致的宽度 */
            width: 100%;
            padding: 30px;
            background-color: #fff;
            border-radius: 10px;
            box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
        }
        .register-header {
            text-align: center;
            margin-bottom: 30px;
        }
        .register-header h1 {
            font-size: 28px;
            font-weight: 600;
            color: #344767;
        }
        .register-header .icon {
            font-size: 48px;
            /* 修改颜色与登录页面风格协调 */
            color: #5e72e4; 
            margin-bottom: 15px;
        }
        .form-control {
            padding: 12px 15px;
            border-radius: 8px;
        }
        .form-control:focus {
            /* 修改聚焦颜色与登录页面一致 */
            border-color: #5e72e4; 
            box-shadow: 0 0 0 0.25rem rgba(94, 114, 228, 0.25);
        }
        /* 修改按钮样式与登录页面一致 */
        .btn-primary { 
            background-color: #5e72e4;
            border-color: #5e72e4;
            padding: 12px 15px;
            font-weight: 600;
            border-radius: 8px;
            width: 100%;
        }
        .btn-primary:hover {
            background-color: #4a5cd1;
            border-color: #4a5cd1;
        }
        .login-link {
            text-align: center;
            margin-top: 20px;
            color: #6c757d;
        }
        .login-link a {
            /* 修改链接颜色与登录页面一致 */
            color: #5e72e4; 
            text-decoration: none;
            font-weight: 600;
        }
        .login-link a:hover {
            text-decoration: underline;
        }
        .errorlist {
            color: #dc3545;
            list-style-type: none;
            padding-left: 0;
            margin-bottom: 10px;
            font-size: 14px;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-6 col-lg-5">
                <div class="register-container">
                    <div class="register-header">
                        <div class="icon">
                            <i class="bi bi-person-plus"></i>
                        </div>
                        <h1>注册卖家账号</h1>
                        <p class="text-muted">创建账号以开始使用卖家中心</p>
                    </div>
                    
                    <form method="post" class="needs-validation" novalidate>
                        {% csrf_token %}
                        
                        <div class="row">
                            {% for field in form %}
                            <div class="{% if field.name == 'password1' or field.name == 'password2' %}col-12{% else %}col-md-6{% endif %} mb-3">
                                <label for="{{ field.id_for_label }}" class="form-label">{{ field.label }}</label>
                                {{ field.errors }}
                                {{ field }}
                                {% if field.help_text %}
                                <div class="form-text">{{ field.help_text }}</div>
                                {% endif %}
                            </div>
                            {% endfor %}
                        </div>
                        
                        <div class="mb-3">
                            <button type="submit" class="btn btn-primary">
                                <i class="bi bi-check-circle me-2"></i>注册
                            </button>
                        </div>
                    </form>
                    
                    <div class="login-link">
                        <p>已有账号?<a href="{% url 'login_seller' %}">点击登录</a></p>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <!-- Bootstrap 5 JS Bundle with Popper -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
    <script>
        // 为表单字段添加Bootstrap的form-control类
        document.addEventListener('DOMContentLoaded', function() {
            var inputs = document.querySelectorAll('input, select, textarea');
            inputs.forEach(function(input) {
                input.classList.add('form-control');
            });
        });
    </script>
</body>
</html>
  1. 创建登陆页面
    创建templates/users/login.html:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>卖家登录</title>
    <!-- Bootstrap 5 CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
    <!-- Bootstrap Icons -->
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.1/font/bootstrap-icons.css">
    <style>
        body {
            background-color: #f8f9fa;
            height: 100vh;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        .login-container {
            max-width: 420px;
            width: 100%;
            padding: 30px;
            background-color: #fff;
            border-radius: 10px;
            box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
        }
        .login-header {
            text-align: center;
            margin-bottom: 30px;
        }
        .login-header h1 {
            font-size: 28px;
            font-weight: 600;
            color: #344767;
        }
        .login-header .icon {
            font-size: 48px;
            color: #5e72e4;
            margin-bottom: 15px;
        }
        .form-control {
            padding: 12px 15px;
            border-radius: 8px;
        }
        .form-control:focus {
            border-color: #5e72e4;
            box-shadow: 0 0 0 0.25rem rgba(94, 114, 228, 0.25);
        }
        .btn-primary {
            background-color: #5e72e4;
            border-color: #5e72e4;
            padding: 12px 15px;
            font-weight: 600;
            border-radius: 8px;
            width: 100%;
        }
        .btn-primary:hover {
            background-color: #4a5cd1;
            border-color: #4a5cd1;
        }
        .register-link {
            text-align: center;
            margin-top: 20px;
            color: #6c757d;
        }
        .register-link a {
            color: #5e72e4;
            text-decoration: none;
            font-weight: 600;
        }
        .register-link a:hover {
            text-decoration: underline;
        }
        .errorlist {
            color: #dc3545;
            list-style-type: none;
            padding-left: 0;
            margin-bottom: 10px;
            font-size: 14px;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-6 col-lg-5">
                <div class="login-container">
                    <div class="login-header">
                        <div class="icon">
                            <i class="bi bi-shop"></i>
                        </div>
                        <h1>卖家中心</h1>
                        <p class="text-muted">请登录您的账号以继续</p>
                    </div>
                    
                    <form method="post" class="needs-validation" novalidate>
                        {% csrf_token %}
                        
                        {% for field in form %}
                        <div class="mb-3">
                            <label for="{{ field.id_for_label }}" class="form-label">{{ field.label }}</label>
                            {{ field.errors }} <!-- 显示字段级别的错误信息 -->
                            {{ field }}
                            {% if field.help_text %}
                            <div class="form-text">{{ field.help_text }}</div>
                            {% endif %}
                        </div>
                        {% endfor %}
                        
                        <!-- 显示非字段级别的错误信息 -->
                        {% if form.non_field_errors %}
                        <div class="errorlist">
                            {{ form.non_field_errors }}
                        </div>
                        {% endif %}
                        
                        <div class="mb-3">
                            <button type="submit" class="btn btn-primary">
                                <i class="bi bi-box-arrow-in-right me-2"></i>登录
                            </button>
                        </div>
                    </form>
                    
                    <div class="register-link">
                        <p>还没有账号?<a href="{% url 'register_seller' %}">点击注册</a></p>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <!-- Bootstrap 5 JS Bundle with Popper -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
    <script>
        // 为表单字段添加Bootstrap的form-control类
        document.addEventListener('DOMContentLoaded', function() {
            var inputs = document.querySelectorAll('input, select, textarea');
            inputs.forEach(function(input) {
                input.classList.add('form-control');
            });
        });
    </script>
</body>
</html>

十、运行项目

python manage.py runserver

打开浏览器访问 http://localhost:8000
在这里插入图片描述
在这里插入图片描述

十一、效果展示

登陆成功
在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到