准备
工具
- vscode 版本: 1.71.2
- python(conda) 版本: 3.9.12
- mysqlclient 版本: 2.1.1
- Django 版本: 4.1
- PyMySQL 版本: 1.0.2
创建
创建项目
- cmd进入需要建立Django项目的文件夹,或在建立Django项目的文件夹内进入cmd
- 输入命令
django-admin startproject projectname
- 这种情况是因为使用的是conda环境,此时只需要激活对应的环境就可以了。
- cd到djangoTest项目文件夹内,输入命令
django-admin startapp appname
-
使用vscode打开,对应的目录 -
创建templates文件夹 -
注册app,在wutengspro文件夹中的setting.py中 -
修改时区,语言,配置模板路径
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
- 如果使用mysql的话,进行如下配置
- 确保已经创建了对应的数据库,不然运行时会出错 确保数据库密码正确
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'wuteng',
'USER': 'root',
'PASSWORD': '******',
'HOST': '127.0.0.1',
'PORT': '3306',
}
}
在项目文件中的 init.py中添加代码:
import pymysql
pymysql.install_as_MySQLdb()
- 设置静态文件目录 文件上传目录
STATIC_URL = '/static/'
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static'),
)
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
运行
- 运行命令
python manage.py runserver
创建模型
了解django自带的User模型
字段
- id:自动生成
- password:一个密码的哈希值和元数据
- last_login:用户最后一次登录的日期时间
- is_superuser:指定该用户拥有所有权限,而不用一个个开启权限
- username:用户名
- first_name:名
- last_name:姓
- email:电子邮件地址
- is_staff:指定该用户是否可以访问管理站点
- is_active:指定该用户账户是否应该被视为活跃账户
- date_joined:指定账户创建时间的日期时间
我们可以扩展一下
- 加入其他字段,比如:
- mobile:手机号
- mobile_confirmed:手机号验证状态:0 未验证 1 已验证
- avatar:头像地址
- email_confirmed:邮箱验证状态:0 未验证 1 已验证
- gender:用户性别:0 未知 1 男性 2 女性
- status:用户状态:0 正常 1 禁用 2 审核中 3 审核拒绝
- wx_openid:微信登录的openid
创建模型,在app下的models中操作
from django.db import models
from django.contrib.auth.models import AbstractUser
import uuid
import os
def user_directory_path(instance, filename):
ext = filename.split('.')[-1]
filename = '{}.{}'.format(uuid.uuid4().hex[:10], ext)
sub_folder = 'file'
if ext.lower() in ["jpg", "png", "gif",'jpeg']:
sub_folder = "avatar"
if ext.lower() in ["pdf", "docx"]:
sub_folder = "document"
return os.path.join(str(instance.user.id), sub_folder, filename)
class Users(AbstractUser):
mobile = models.CharField(max_length=11, null=True,
blank=True, verbose_name="手机号码", help_text='用户手机号')
mobile_confirmed = models.CharField(max_length=1, choices=(("0", "未验证"), ("1", "已验证"),), blank=True,
db_index=True, verbose_name="用户手机号验证状态", help_text='用户手机号验证状态:0 未验证 1 已验证')
avatar = models.ImageField(upload_to=user_directory_path, blank=True, null=True, verbose_name="用户头像", help_text='用户头像')
email_confirmed = models.CharField(max_length=1, choices=(("0", "未验证"), ("1", "已验证"),), blank=True,
db_index=True, verbose_name="邮箱验证状态", help_text='邮箱验证状态:0 未验证 1 已验证')
gender = models.CharField(max_length=1, choices=(("0", "未知"), ("1", "男"),("2", "女"),), blank=True,
db_index=True, verbose_name="性别", help_text='性别')
status = models.CharField(max_length=1, choices=(("0", "正常"), ("1", "禁用"),("2", "审核中"),("3", "审核拒绝"),), blank=True,
db_index=True, verbose_name="用户状态", help_text='用户状态:0 正常 1 禁用 2 审核中 3 审核拒绝', default='2')
wx_openid = models.CharField(max_length=128,null=True,blank=True,verbose_name='微信id', help_text='微信id',unique=True)
class Meta:
verbose_name = 'Users'
get_latest_by = "last_login"
unique_together = (("mobile", "wx_openid"),)
def __str__(self):
return f"用户名:{self.username} 手机号:{self.mobile} 邮箱:{self.email} 帐号状态:{self.status}"
这里我们采用了,重写User模型,我们继承了AbstractUser,不需要重写AbstractUser已经定义好的字段了,只需要增加我们需要添加的字段即可, 在setting.py里添加
AUTH_USER_MODEL = 'users.Users'
执行命令
python manage.py makemigrations
python manage.py migrate
此时数据库可以看到:
配置路由
app中新建urls.py文件,输入:
from django.urls import re_path, path
from . import views
app_name = 'users'
urlpatterns = [
path('login', views.login, name='login'),
path('regeister', views.regeister, name='regeister'),
re_path(r'^user/profile/$', views.profile, name='profile'),
]
编写视图函数
在app的views.py中
from django.shortcuts import render, get_object_or_404
from .models import Users
from django.contrib import auth
from .form import RegistrationForm, LoginForm, ProfileForm, PwdChangeForm
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.contrib.auth.decorators import login_required
def register(request):
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
username = form.cleaned_data['username']
email = form.cleaned_data['email']
mobile = form.cleaned_data['mobile']
password = form.cleaned_data['password2']
user = Users.objects.create_user(
username=username, password=password, email=email, mobile=mobile)
return HttpResponseRedirect("/users/login")
else:
form = RegistrationForm()
return render(request, 'users/registration.html', {'form': form})
def login(request):
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user = auth.authenticate(request,username=username, password=password)
if user is not None and user.is_active:
auth.login(request, user)
return HttpResponseRedirect(reverse('users:profile'))
else:
return render(request, 'users/login.html', {'form': form,
'message': '账号或密码错误!'})
else:
form = LoginForm()
return render(request, 'users/login.html', {'form': form})
def profile(request):
return render(request, 'users/profile.html')
在app中新建 utils.py,用于重写 authenticate()方法,实现多种方式登录 在setting.py添加
AUTHENTICATION_BACKENDS = [
'users.utils.UsernameMobileAuthBackend',
]
编写表单校验
在app新建forms.py
from django import forms
from .models import Users
import re
def mobile_check(mobile):
pattern = re.compile("^((13)|(14)|(15)|(16)|(17)|(18)|(19))\\d{9}$")
return re.match(pattern, mobile)
def email_check(email):
pattern = re.compile(r"\"?([-a-zA-Z0-9.`?{}]+@\w+\.\w+)\"?")
return re.match(pattern, email)
def paw_check(password):
pattern1 = re.compile("/^(\d{6,10})|([a-z]{6,10})|([A-Z]{6,10})$/")
pattern2 = re.compile("/^(?![\d]+$)(?![a-zA-Z]+$)(?![^\da-zA-Z]+$).{6,20}$/")
pattern3 = re.compile("/(?=.*[0-9])(?=.*[a-zA-Z])(?=.*[^a-zA-Z0-9]).{6,10}/")
if re.match(pattern1,password):
return 1
if re.match(pattern2,password):
return 2
if re.match(pattern3,password):
return 3
class RegistrationForm(forms.Form):
username = forms.CharField(
label='用户名',
required=True,
min_length=3,
max_length=8,
error_messages={
'required': '用户名不能为空',
'max_length': '用户名长度不得超过8个字符',
'min_length': '用户名长度不得少于3个字符',
})
email = forms.EmailField(
label='邮箱',
required=True,
error_messages={
'required': '邮箱不能为空',
})
mobile = forms.CharField(
label='手机号',
required=True,
error_messages={
'required': '手机号不能为空',
})
password1 = forms.CharField(
label='密码',
widget=forms.PasswordInput,
required=True,
min_length=6,
max_length=20,
error_messages={
'required': '密码不能为空',
'max_length': '用密码长度不得超过20个字符',
'min_length': '密码长度不得少于6个字符',
})
password2 = forms.CharField(
label='确认密码',
widget=forms.PasswordInput,
required=True,
min_length=6,
max_length=20,
error_messages={
'required': '密码不能为空',
'max_length': '用密码长度不得超过20个字符',
'min_length': '密码长度不得少于6个字符',
})
def clean_username(self):
username = self.cleaned_data.get('username')
filter_result = Users.objects.filter(username__exact=username)
if filter_result.exists():
raise forms.ValidationError("用户名已存在!")
return username
def clean_email(self):
email = self.cleaned_data.get('email')
if email_check(email):
filter_result = Users.objects.filter(email__exact=email)
if filter_result.exists():
raise forms.ValidationError("邮箱已存在已被绑定!")
else:
raise forms.ValidationError("邮箱码格式错误!")
return email
def clean_mobile(self):
mobile = self.cleaned_data.get('mobile')
if mobile_check(mobile):
filter_result = Users.objects.filter(mobile__exact=mobile)
if filter_result.exists():
raise forms.ValidationError("手机号已被绑定!")
else:
raise forms.ValidationError("手机号码格式错误!")
return mobile
def clean_password1(self):
password1 = self.cleaned_data.get('password1')
if paw_check(password1) == 1:
print("密码强度低")
if paw_check(password1) == 2:
print("密码强度中")
if paw_check(password1) == 3:
print("密码强度高")
return password1
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(
"密码不一致!")
return password2
class LoginForm(forms.Form):
username = forms.CharField(label='用户名', max_length=50)
password = forms.CharField(label='密码', widget=forms.PasswordInput)
def clean_username(self):
username = self.cleaned_data.get('username')
if email_check(username):
filter_result = Users.objects.filter(email__exact=username)
if not filter_result:
raise forms.ValidationError("邮箱不存在!或未绑定邮箱!")
elif mobile_check(username):
filter_result = Users.objects.filter(mobile__exact=username)
if not filter_result:
raise forms.ValidationError("手机号不存在!或未绑定手机号!")
else:
filter_result = Users.objects.filter(username__exact=username)
if not filter_result:
raise forms.ValidationError(
"用户名不存在!")
return username
class ProfileForm(forms.Form):
def __str__():
return "你好!"
class PwdChangeForm(forms.Form):
def __str__():
return "你好!"
编写html
在app中的templates文件夹下新建文件夹users,新建login.html profile.html registration.html
login.html
{% block content %}
<div class="form-wrapper">
<form method="post" action="" enctype="multipart/form-data">
{% csrf_token %}
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
{% if field.help_text %}
<p class="help">{{ field.help_text|safe }}</p>
{% endif %}
</div>
{% endfor %}
<div class="button-wrapper submit">
<input type="submit" value="Submit" />
</div>
</form>
</div>
{% endblock %}
registration.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div>
<form method="post" action="" enctype="multipart/form-data">
{% csrf_token %}
{% for field in form %}
<div class="fieldWrapper">
{{ field.errors }}
{{ field.label_tag }} {{ field }}
{% if field.help_text %}
<p class="help">{{ field.help_text|safe }}</p>
{% endif %}
</div>
{% endfor %}
<div>
<input type="submit" value="Submit" />
</div>
</form>
</div>
</body>
</html>
profile.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
??
</body>
</html>
运行
执行命令
python manage.py runserver
在网址输入: http://127.0.0.1:8000/users/login
完毕
前端页面待开发…
|