用前端框架Bootstrap和Django实现用户注册页面-CSDN博客
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
01-新建一个名为“mall_backend”的Project
命令如下
CD E:\Python_project\P_001\myshop-test
E:
django-admin startproject mall_backend
02-新建应用并注册应用
执行下面条命令依次创建需要的应用
CD E:\Python_project\P_001\myshop-test\mall_backend\
E:
python manage.py startapp users
名叫users的应用创建好后还需要在全局配置文件中对应在用进行注册具体方法如下
打开““E:\Python_project\P_001\myshop-test\mall_backend\mall_backend\settings.py””文件找到名叫“INSTALLED_APPS”的列表(list)在其中加入应用名如下
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'users', # 这是自己创建的应用需要手动注册
]
03-实现“用户注册”模块
“用户注册”模块使用如下技术来开发。
使用Form表单方式进行表单数据的验证。
通过继承AbstractUser类来简化用户权限认证。
03-01-创建数据库模型类
打开文件 E:\Python_project\P_001\myshop-test\mall_backend\users\models.py 写入下面的代码
from django.db import models
from datetime import datetime
from django.contrib.auth.models import AbstractUser, Group, Permission
class MyUser(AbstractUser):
SEX = (
(0, '男'),
(1, '女'),
)
LEVEL = (
(1, '寂寞卡会员'),
(2, '钻石卡会员'),
(3, '金卡会员'),
(4, '银卡会员'),
)
STATUS = (
(0, '正常'),
(1, '异常'),
)
groups = models.ManyToManyField(
Group,
verbose_name='groups',
blank=True,
help_text='The groups this user belongs to.',
related_name='user_groups' # 设置不同的 related_name
)
user_permissions = models.ManyToManyField(
Permission,
verbose_name='user permissions',
blank=True,
help_text='Specific permissions for this user.',
related_name='user_permissions' # 设置不同的 related_name
)
nickname = models.CharField('qq', blank=True, max_length=50)
truename = models.CharField('真实姓名', blank=True, max_length=50)
mobile = models.CharField('手机号码', max_length=11, default="")
sex = models.IntegerField(default=0, choices=SEX)
birthday = models.DateField(blank=True, null=True)
user_img = models.ImageField("头像", upload_to="user_img", default="")
level = models.IntegerField(default=4, choices=LEVEL)
status = models.IntegerField(default=0, choices=STATUS)
create_time = models.DateTimeField(default=datetime.now, verbose_name='创建时间')
update_time = models.DateTimeField(default=datetime.now, verbose_name="更新时间")
def __str__(self):
return self.username
class Meta(AbstractUser.Meta):
permissions = (
['check_myuser', '审核用户信息'],
)
问在整个项目中还用到了字段password、is_staff、is_superuser那这些字段为什么不定义呢原因是在基类AbstractUser中已经定义了。详情见https://blog.csdn.net/wenhao_ir/article/details/131594115
03-02-创建表单类及表单类代码详解
在目录 E:\Python_project\P_001\myshop-test\mall_backend\users 下新建文件 forms.py
然后写入下面的代码A
from users.models import *
from django import forms
from django.core.exceptions import ValidationError
import re
def mobile_validate(value):
mobile_re = re.compile(
r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
if not mobile_re.match(value):
raise ValidationError('手机号码格式错误')
class UserRegForm(forms.Form):
username = forms.CharField(label="用户名", min_length=6,
widget=forms.widgets.TextInput(
# 其中class样式为form-control这是bootstrap的样式
attrs={'class': 'form-control', 'placeholder': "请输入用户名"}),
error_messages={
'required': '用户姓名不能为空',
'min_length': '长度最少6位',
})
password = forms.CharField(label="密码", min_length=6, max_length=10,
widget=forms.widgets.PasswordInput(
# render_value=True页面校验不通过后页面上该值还存在
attrs={"class": "form-control"}, render_value=True),
error_messages={
'max_length': '密码最长10位',
'required': '密码不能为空',
'min_length': '密码最少6位'
})
re_password = forms.CharField(label="确认密码", min_length=6, max_length=10,
widget=forms.widgets.PasswordInput(
# render_value=True页面校验不通过后页面上该值还存在
attrs={"class": "form-control"}, render_value=True),
error_messages={
'max_length': '密码最长10位',
'required': '密码不能为空',
'min_length': '密码最少6位'
})
nickname = forms.CharField(label="昵称", max_length=20, required=False,
widget=forms.widgets.TextInput(
# 其中class样式为form-control这是bootstrap的样式
attrs={'class': 'form-control', 'placeholder': "请输入用户昵称"}),
error_messages={
'required': '用户昵称不能为空',
'max_length': '昵称长度不能超过20位',
})
email = forms.EmailField(label="邮箱",
widget=forms.widgets.EmailInput(
attrs={'class': 'form-control', }),
error_messages={
'required': '邮箱不能为空',
'invalid': '邮箱格式不对',
})
mobile = forms.CharField(label="手机号码", validators=[mobile_validate],
widget=forms.widgets.TextInput(
attrs={'class': 'form-control', }),
error_messages={
'required': '手机号码不能为空',
})
user_img = forms.ImageField(label="用户头像", required=False, widget=forms.widgets.FileInput(
attrs={'class': 'form-control'}))
# 全局钩子函数
def clean(self):
password = self.cleaned_data.get("password")
re_password = self.cleaned_data.get("re_password")
print(password)
if password != re_password:
# raise forms.ValidationError("二次密码输入不一致")
self.add_error("re_password", ValidationError("二次密码输入不一致"))
①类ValidationError有什么作用
答在Django中ValidationError
类是一个异常类它属于django.core.exceptions
模块。当数据验证失败时可以通过引发ValidationError
异常来表示验证错误。
②-①re.compile()方法有什么用
请参考博文https://blog.csdn.net/wenhao_ir/article/details/132026895
②-2 有没有关于正则表达式 r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$'
的详细理解
请参考博文 https://blog.csdn.net/wenhao_ir/article/details/132027668 的第4点、第5点和第6点。
③能不能介绍下Django中的表单forms模块中的类forms.CharField
请参考博文https://blog.csdn.net/wenhao_ir/article/details/132029002
④能不能介绍下什么是Django表单中的全局钩子函数
在Django表单中全局钩子函数Global Form Validation Hook是指在表单类中定义的特殊方法它允许开发者对表单中的多个字段进行综合性的验证和处理。全局钩子函数会在表单的所有字段个别验证完成后被调用用于执行那些需要考虑多个字段相互关系的验证逻辑或处理逻辑。
通常情况下Django表单中的字段验证是在各个字段的 clean_<field_name>
方法中进行的。例如对于一个字段名为 username
的表单字段其验证逻辑会放在 clean_username()
方法中。这样的验证方法称为字段级别的验证。
但是有些情况下需要对多个字段的数据进行联合验证或验证它们之间的关系。这时就可以使用全局钩子函数来进行全局性的表单验证。全局钩子函数的名称是 clean
它没有特定的字段名称前缀而是直接在表单类中定义。
全局钩子函数的工作方式如下
-
先执行各个字段的单独验证方法如
clean_username()
clean_password()
等来验证各个字段的合法性。 -
在所有字段单独验证通过后Django会自动调用全局钩子函数
clean()
如果表单类中有定义。 -
在
clean()
方法中您可以对多个字段的数据进行综合验证和处理。如果需要在多个字段之间执行联合验证这里是合适的位置。 -
如果全局钩子函数
clean()
验证失败即调用self.add_error()
方法添加了错误信息则表单将被认为是无效的验证失败的错误信息将在表单的非特定字段下方显示。
总结全局钩子函数是在Django表单中定义的用于对多个字段进行综合性验证和处理的特殊方法。它在所有字段个别验证通过后被自动调用允许开发者执行联合验证或处理多个字段之间的关系。
⑤能不能介绍下代码password = self.cleaned_data.get("password")
?
当用户提交表单后self.cleaned_data
是一个字典其中包含经过表单字段验证后的干净数据。每个表单字段的值如果有效都会存储在这个字典中以其相应的字段名为键。
在代码中的这一行 password = self.cleaned_data.get("password")
self.cleaned_data.get("password")
用于从字典中获取经过验证的 “password” 字段的干净值。
下面是对这一行代码的详细解释
-
self
在 Django 表单的上下文中self
是表单实例自身的引用。它是封装表单数据和逻辑的对象。 -
cleaned_data
cleaned_data
是表单实例self
的属性它保存用户提交的经过验证和清理后的数据。这个字典中的数据根据表单类中定义的字段类型和验证器进行了清理和格式化。 -
.get("password")
Python 字典的get()
方法用于根据给定的键获取与之关联的值。在这里键是 “password”对应着 “password” 表单字段的名字。
self.cleaned_data.get("password")
这一行代码从表单的 cleaned_data
字典中获取 “password” 字段的干净值。如果表单有效且 “password” 字段存在并且通过了验证它会返回 “password” 字段的干净值。如果 “password” 字段无效或未包含在提交的数据中它将返回 None
。
通过使用这种方法来访问清理后的数据表单的作者可以安全地获取用户的输入无需担心潜在的验证错误或缺失的字段。这是 Django 表单中常用的访问经过验证数据的方式。
⑥能不能介绍下代码 self.add_error("re_password", ValidationError("二次密码输入不一致"))
?
当表单数据在全局钩子函数 clean
中进行综合校验时如果发现特定的校验规则未通过开发者可以通过 self.add_error(field, error)
方法来向表单字段添加错误信息。
在代码A中的这一行 self.add_error("re_password", ValidationError("二次密码输入不一致"))
self.add_error()
方法用于向表单字段添加错误信息以告知用户二次密码输入不一致。
下面是对这行代码的详细解释
-
self
在 Django 表单的上下文中self
是表单实例自身的引用。它是封装表单数据和逻辑的对象。 -
add_error()
add_error()
是表单实例的方法用于向表单字段添加错误信息。它接收两个参数- 第一个参数是表单字段的名称field这里是 “re_password”即确认密码字段的名称。
- 第二个参数是一个 ValidationError 对象它用于指定具体的错误信息。
-
“re_password”这是表单字段的名称即确认密码字段的名称。表单字段的名称是在定义表单类时给定的。
-
ValidationError("二次密码输入不一致")
这是一个 ValidationError 对象用于指定错误信息。在这里它表示 “二次密码输入不一致” 是校验失败的原因。
在全局钩子函数 clean
中当表单数据不满足某些特定的条件时例如密码和确认密码不一致开发者可以使用 self.add_error()
方法来添加错误信息然后这些错误信息将在渲染表单时显示给用户帮助用户找到并纠正表单中的错误。
问为什么add_error()要有第一个参数即表单字段的名称呢我感觉没有用呀。
您提出的疑问很合理。实际上在全局钩子函数 clean
中使用 self.add_error()
方法时第一个参数即表单字段的名称是非常有用的。它有两个重要的作用
-
指定出现错误的字段 在一个表单中可能有多个字段需要进行全局校验而不仅仅是一个确认密码字段。通过指定字段的名称作为第一个参数
self.add_error()
方法可以告诉 Django 哪个字段出现了错误从而确保错误信息被添加到正确的字段中。 -
显示错误信息 表单字段的名称不仅指定了出现错误的字段还在渲染表单时用于显示错误信息。当
self.add_error()
方法被调用后错误信息将与相应字段一起传递给前端页面。这样用户在查看表单时可以清楚地看到哪些字段存在错误以及错误的具体信息。
例如在代码A中self.add_error("re_password", ValidationError("二次密码输入不一致"))
会向 “re_password” 字段添加一个 “二次密码输入不一致” 的错误信息。如果用户在确认密码时输入的密码与之前输入的密码不一致就会触发这个错误并在确认密码字段下方显示 “二次密码输入不一致” 的错误提示帮助用户及时纠正错误。
总结表单字段的名称作为 self.add_error()
方法的第一个参数是为了将错误信息与相应字段关联起来并在前端页面上正确显示错误信息提高用户体验。
04-创建视图函数并编写视图函数
04-1-视图函数views.py里的代码
打开文件 E:\Python_project\P_001\myshop-test\mall_backend\users\views.py 写入下面的代码B
from django.shortcuts import render
from users.models import MyUser
from users.forms import *
# Create your views here.
def user_reg(request):
if request.method == "GET":
form_obj = UserRegForm()
return render(request, 'shop/user_reg.html', {"form_obj": form_obj})
if request.method == "POST":
form_obj = UserRegForm(request.POST, request.FILES)
if form_obj.is_valid():
uname = request.POST.get("username", '')
users = MyUser.objects.filter(username=uname)
if users:
for user in users:
user_img = user.user_img
info = '用户已经存在'
else:
form_obj.cleaned_data.pop("re_password")
form_obj.cleaned_data["is_staff"] = 1
form_obj.cleaned_data["is_superuser"] = 0 # 非管理员
# 接收页面传递过来的参数进行用户新增
user = MyUser.objects.create_user(**form_obj.cleaned_data)
user_img = user.user_img
info = '注册成功,请登陆'
return render(request, 'shop/user_reg.html', {"form_obj": form_obj, "info": info, "user_img": user_img})
else:
errors = form_obj.errors
print(errors)
return render(request, "shop/user_reg.html", {'form_obj': form_obj, 'errors': errors})
return render(request, 'shop/user_reg.html', {"form_obj": form_obj})
04-2-视图函数views.py代码详解
①注意user_reg()并不是一个类而是一个函数。
这个函数的参数为request参数request代表了客户端发起的请求。它包含了关于请求的各种信息例如用户提交的表单数据、HTTP方法等。
②语句 form_obj = forms.UserRegForm() 是什么意思
注意UserRegForm是一个类这个类是在自己前面新建的文件 “E:\Python_project\P_001\myshop-test\mall_backend\users\forms.py” 中自定义的类这个类继承自Django的forms.Form类。
所以这句代码是创建类UserRegForm的实例化对象form_obj 。
③详细解释下语句 return render(request, ‘shop/user_reg.html’, {“form_obj”: form_obj}。
答当你调用render
函数时它用于将一个模板渲染成HTML响应并返回给客户端。这个函数的第一个参数是request
对象第二个参数是模板的路径第三个参数是一个字典用于向模板传递上下文变量。在这里第三个参数不太好理解详情见我的另一篇博文链接https://blog.csdn.net/wenhao_ir/article/details/132501337
在代码中render
函数的目的是渲染名为 'shop/user_reg.html'
的模板同时传递一个名为 form_obj
的变量给模板。让我详细解释一下这段代码
-
request
: 这是视图函数的第一个参数代表了客户端发起的请求。它包含了关于请求的各种信息例如用户提交的表单数据、HTTP方法等。 -
'shop/user_reg.html'
: 这是模板的路径告诉Django要使用哪个模板来生成HTML响应。 -
{"form_obj": form_obj}
: 这是一个字典用于传递变量给模板。在这里form_obj
是一个表单实例通过这个字典将这个表单实例传递给了模板。在模板中你可以通过键名form_obj
来访问这个表单实例以便在模板中渲染表单的各个字段、错误信息等。
总之render
函数的第三个参数是用于向模板传递上下文变量的让模板能够使用这些变量来动态生成HTML内容。在这里你传递了一个名为 form_obj
的变量这个变量在模板中可以被用来渲染注册表单的各个部分和数据。
④能否详细解释下代码B中的代码
form_obj = forms.UserRegForm(request.POST, request.FILES)
咱们把03-02中的表单类的代码记为代码A把视图函数里的代码记为代码B。
当你在Django中使用表单时你需要在视图函数中处理用户提交的数据。这个数据通常包含在HTTP请求中的POST数据中可能包含用户在表单中输入的文本、上传的文件等。为了处理这些数据你需要实例化一个表单对象并将这些数据传递给它进行验证和处理。
在你提到的代码中form_obj = forms.UserRegForm(request.POST, request.FILES)
这一行代码完成了以下操作
-
forms.UserRegForm
: 这是代码A中定义的注册表单的类。通过调用这个类你可以创建一个用于处理用户提交数据的表单对象。 -
request.POST
: 这是一个包含用户在表单中提交的文本数据的字典。当用户通过POST方法提交表单时表单中的文本字段的数据会包含在这个字典中。这个参数将这些POST数据传递给表单对象。 -
request.FILES
: 这是一个包含用户在表单中上传的文件的字典。当用户通过POST方法提交包含文件上传的表单时上传的文件数据会包含在这个字典中。这个参数将这些文件数据传递给表单对象。
request.FILES
中包含的是用户通过表单上传的文件的数据但这些文件并没有直接保存在这个字典中。实际上这些上传的文件数据会被保存在服务器的临时文件夹中然后在需要的时候通过文件句柄进行访问和处理。
当用户通过表单上传文件时这些文件数据会被存储在服务器上的一个临时目录中通常位于 Django 项目的根目录下的media
文件夹或者根据你在 Django 设置中配置的MEDIA_ROOT
设置的路径。临时文件会在请求处理完成后自动被清理掉。
在你的代码中通过request.FILES
参数传递给表单对象后你可以在表单类中的对应字段中访问这些文件数据。比如在你的UserRegForm
类中user_img
字段是一个forms.ImageField
类型的字段它会处理用户上传的头像文件数据。
总之request.FILES
中包含的是上传文件的数据的引用而文件本身会被存储在服务器的临时目录中可以在表单处理过程中进行访问和处理然后根据需要进行持久化保存。
所以form_obj = forms.UserRegForm(request.POST, request.FILES)
这行代码创建了一个 UserRegForm
类的实例用于处理用户通过POST方法提交的数据包括文本字段数据和上传的文件数据。这个实例可以用于验证用户提交的数据并执行相关的处理操作比如将数据保存到数据库中。
⑤能否详细解释下代码B中的代码 if form_obj.is_valid():
当你处理用户提交的表单数据时其中一个关键的步骤是验证这些数据是否合法和有效。在Django中你可以使用 is_valid()
方法来检查表单数据是否通过了验证规则以及是否符合字段定义和自定义验证逻辑。
在你提到的代码中form_obj.is_valid()
这一行代码的含义是检查用户提交的数据是否有效。这个方法会运行表单类中的所有验证规则包括字段的定义验证比如最小长度、最大长度等、自定义验证方法以及其他内置的验证规则。
如果所有的验证规则都通过了is_valid()
方法会返回 True
表示用户提交的数据是有效的。如果任何一个验证规则失败is_valid()
方法会返回 False
并且表单对象会保存验证失败的信息包括错误消息和错误类型。
因此在你的代码中这个条件 if form_obj.is_valid():
意味着如果用户提交的数据经过验证是有效的就执行接下来的逻辑比如保存数据到数据库。如果验证失败则可以根据表单对象中的错误信息回显错误消息给用户让用户进行修正。
总之form_obj.is_valid()
是用来判断用户提交的表单数据是否合法的关键方法它决定了是否继续处理表单数据或者显示错误消息给用户。
问is_valid()方法是怎么知道哪些函数或方法是验证规则的呢
在Django中is_valid()
方法通过以下方式来确定哪些函数或方法是验证规则
-
字段类型和属性每个字段在表单类中都有相应的字段类型比如
CharField
、EmailField
、IntegerField
等。这些字段类型定义了默认的验证规则例如长度限制、数据类型等。你可以在字段的构造函数中传递参数来自定义这些规则。 -
内置验证器Django 提供了一些内置的验证器你可以在字段的构造函数中使用
validators
参数来添加。这些验证器可以是函数、类方法或自定义的验证函数它们会在is_valid()
方法执行时被调用。 -
自定义验证方法你可以在表单类中定义自己的验证方法这些方法的命名规则为
clean_<field_name>
例如clean_username()
。这些方法会在is_valid()
方法执行时被自动调用。 -
clean()
方法你可以在表单类中定义一个全局的clean()
方法用于对整个表单的数据进行自定义的综合性验证。这个方法会在is_valid()
方法执行时被调用。
当你调用 is_valid()
方法时Django 会遍历表单类中的所有字段执行这些字段类型定义的默认验证规则调用与字段相关的内置验证器以及执行自定义的验证方法和全局的 clean()
方法。如果任何一个验证规则失败is_valid()
方法会设置表单对象的 errors
属性记录错误信息。
总之Django 使用一系列约定和机制来确定验证规则包括字段类型、内置验证器、自定义验证方法和全局的 clean()
方法。在调用 is_valid()
方法时这些规则会被按顺序执行以判断表单数据的有效性。
⑥代码uname = request.POST.get(“username”, ‘’)为什么第2个参数要填一个空字符串
在代码B中uname = request.POST.get("username", '')
这行代码的作用是从request.POST
字典中获取键为 "username"
的值。如果这个键存在就返回对应的值如果这个键不存在就返回一个默认值这里是空字符串 ''
。
这种做法的目的是为了防止在访问字典中不存在的键时出现错误。如果使用request.POST["username"]
来获取值当 "username"
这个键不存在时会抛出 KeyError
异常导致程序终止执行。而使用 .get()
方法并且传递一个默认值作为第二个参数可以在键不存在时提供一个安全的默认值避免程序崩溃。
在这个具体情境中uname
变量用于存储从用户提交的表单数据中获取的用户名。如果用户在表单中没有输入用户名那么通过 request.POST.get("username", '')
可以确保 uname
变量始终有一个值即空字符串而不会引发异常。
总之使用 .get()
方法并提供一个默认值是一种良好的编程习惯可以保证在处理字典时不会因为键不存在而导致程序崩溃。
⑦代码users = MyUser.objects.filter(username=uname) 是什么意思
在代码B中users = MyUser.objects.filter(username=uname)
这行代码的作用是从数据库中查询满足特定条件的用户数据。
具体解释如下
-
MyUser
是在数据库模型文件中定义的一个类它对应着数据库中的一张表。这个类包含了与用户相关的字段比如用户名、密码、邮箱等以及方法。 -
MyUser.objects
是一个与数据库交互的管理器Manager对象。通过这个管理器你可以执行数据库查询操作。 -
.filter(username=uname)
是一个查询过滤条件它的意思是从MyUser
表中筛选出字段username
值等于uname
变量值的记录。 -
将查询结果赋值给变量
users
。这个变量将包含所有满足条件的用户记录以查询集QuerySet的形式返回。
所以users = MyUser.objects.filter(username=uname)
这行代码的目的是从数据库中检索所有用户名等于 uname
变量值的用户记录并将这些记录存储在 users
变量中以供后续处理和使用。
⑧代码form_obj.cleaned_data.pop(“re_password”)是什么意思
在代码B中form_obj.cleaned_data.pop("re_password")
这行代码的作用是从表单的清理数据cleaned_data中移除一个特定的字段。
解释如下
-
form_obj
: 这是一个表单对象它包含了用户提交的数据并经过了验证和清理处理。 -
.cleaned_data
: 这是一个字典包含了已经通过了验证并被清理过的数据。这些数据可以用于后续的处理比如保存到数据库。 -
.pop("re_password")
: 这是对字典的操作用于从字典中移除一个特定的键key及其对应的值value。在这里"re_password"
是一个键表示确认密码字段这行代码的目的是将确认密码字段从cleaned_data
字典中移除。
通常情况下确认密码字段不会被保存到数据库所以在将表单数据保存到数据库之前可能会需要将确认密码字段从 cleaned_data
中移除以避免将这个字段保存到数据库中。
总之form_obj.cleaned_data.pop("re_password")
这行代码的作用是从表单的清理数据中移除确认密码字段以准备将其余数据保存到数据库中。
⑨代码user = MyUser.objects.create_user(**form_obj.cleaned_data)
中的参数form_obj.cleaned_data前面的两个“**”是什么意思
在Python中**
是一种特殊的语法用于将一个字典的内容解包unpack并作为关键字参数传递给函数。在这行代码中**form_obj.cleaned_data
的作用是将 form_obj.cleaned_data
这个字典中的内容解包并作为关键字参数传递给 MyUser.objects.create_user
函数。
具体解释如下
-
form_obj.cleaned_data
: 这是一个字典包含了经过验证和清理处理后的表单数据。每个字段的名称都是键对应的用户输入数据是值。 -
**
: 这是解包操作符用于将字典中的内容解包并作为关键字参数传递给函数。 -
MyUser.objects.create_user
: 这是一个用于创建用户的方法。它通常是在Django的用户认证系统中的用户模型例如User
或MyUser
中定义的一个方法用于创建新的用户记录。
所以MyUser.objects.create_user(**form_obj.cleaned_data)
这行代码的意思是将经过验证和清理的表单数据作为关键字参数传递给 create_user
方法以便用这些数据来创建一个新的用户记录。
总之**form_obj.cleaned_data
是一种用于将字典内容解包的语法用于方便地将字典的键值对作为关键字参数传递给函数。
⑩能否详细解释下代码user = MyUser.objects.create_user(**form_obj.cleaned_data)
。
user = MyUser.objects.create_user(**form_obj.cleaned_data)
这行代码的含义是创建一个新的 MyUser
记录并使用从表单中清理过的数据填充各个字段。
让我详细解释这段代码的逻辑
-
MyUser.objects
: 这是与MyUser
模型数据库表进行交互的管理器Manager对象。 -
.create_user
: 这是一个自定义的方法它通常在 Django 的用户认证系统中的用户模型类中定义用于创建新的用户记录。在你提供的代码中MyUser
类继承了AbstractUser
所以它继承了create_user
方法。 -
**form_obj.cleaned_data
: 这部分使用了解包操作符**
将经过验证和清理的表单数据解包并作为关键字参数传递给create_user
方法。因为form_obj.cleaned_data
是一个字典它包含了经过验证的表单字段及其对应的值。
所以user = MyUser.objects.create_user(**form_obj.cleaned_data)
的意思是使用从表单中清理过的数据创建一个新的 MyUser
记录。这将把用户提交的表单数据填充到 MyUser
模型的各个字段中并创建一个新的用户记录。
总之这行代码是在数据库中创建一个新的用户记录并将表单中的数据应用于相应的字段。
11 代码 user_img = user.user_img 的user_img是用户头像路径吗
答不是user_img只是数据库模型MyUser的头像字段ImageFieldFile的一个对象它代表数据库查询的QuerySet如果要获取用户的头像的上传路径要用下面的代码
user_img_path = user.user_img.url
即通过 .url 属性可以获取头像上传路径。
所以这句代码是存疑的。
12 最后一个return语句 return render(request, 'shop/user_reg.html', {"form_obj": form_obj})
是什么意思
答在POST请求方法中不管哪种情况最终都要再次显示显示表单填写页面。
05-模板文件user_reg.html
05-01-注册模板目录
打开文件
E:\Python_project\P_001\myshop-test\mall_backend\mall_backend\settings.py
找到配置选项“TEMPLATES”然后将代码
'DIRS': [],
修改为:
'DIRS': [os.path.join(BASE_DIR, 'templates')],
由于上面这句代码用到了os库所以还需要在 settings.py 中导入该库
import os
05-02-配置模板文件user_reg.html需要的Bootstrap静态文件
01-创建路径 E:\Python_project\P_001\myshop-test\mall_backend\static\other\css\ 所需的相关目录。
02-然后下载Bootstrap的包“bootstrap-4.5.3-dist.zip”
官网下载方法请参考博文 https://blog.csdn.net/wenhao_ir/article/details/132089650
百度网盘下载链接https://pan.baidu.com/s/14BM9gpC3K-LKxhyLGh4J9Q?pwd=m02m
下载完成后解压把css文件夹下的文件“bootstrap.min.css”和文件“bootstrap.min.css.map”都复制到目录E:\Python_project\P_001\myshop-test\mall_backend\static\other\css\ 中。
关于映射文件“bootstrap.min.css.map”有什么用请参考下面两篇文章
文章01 https://blog.csdn.net/wenhao_ir/article/details/132090746
文章02 https://blog.csdn.net/wenhao_ir/article/details/132152980
05-03-注册静态文件目录
打开文件
E:\Python_project\P_001\myshop-test\mall_backend\mall_backend\settings.py
找到代码
STATIC_URL = '/static/'
将其替换为下面三句代码
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, '/static')
问
代码
STATICFILES_DIRS = [os.path.join(BASE_DIR, ‘static’)]
与代码
STATIC_ROOT = os.path.join(BASE_DIR, ‘/static’)
有什么区别
答这两行代码有不同的目的和用途它们分别用于不同情况下的静态文件配置。
-
STATICFILES_DIRS
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
这行代码配置了一个列表其中包含了其他应用或项目级别的静态文件目录。
os.path.join(BASE_DIR, 'static')
表示将项目根目录下的static
文件夹加入到静态文件查找路径中。这个配置用于指定除了应用内部的静态文件目录之外的其他静态文件目录。在这个列表中的目录会被用于开发环境中的静态文件查找而不会被用于生产环境的静态文件收集即不会被collectstatic
命令收集到STATIC_ROOT
目录中。 -
STATIC_ROOT
STATIC_ROOT = os.path.join(BASE_DIR, '/static')
这行代码定义了一个目录用于在生产环境中收集所有静态文件。
STATIC_ROOT
是一个绝对路径指定了一个位置collectstatic
命令会将所有应用和项目中的静态文件收集到这个目录中以便在生产环境中统一提供静态文件的服务。这个目录应该是你部署服务器上的一个真实路径。
在总体架构上STATICFILES_DIRS
用于开发环境中的静态文件查找而 STATIC_ROOT
用于生产环境中的静态文件收集。这两个设置在功能上是不同的它们的目标是为了在不同的环境中处理静态文件。
问代码STATIC_URL = '/static/'
有什么用
在Django的settings.py
文件中STATIC_URL
是一个用于设置静态文件的URL前缀的配置项。它定义了浏览器访问静态文件的基本URL路径。在你的代码中STATIC_URL
被设置为'/static/'
。
这意味着当你在HTML模板或Django视图中引用静态文件例如CSS、JavaScript、图像等Django将使用这个URL前缀来构建静态文件的URL。例如如果你有一个名为style.css
的CSS文件并且STATIC_URL
被设置为'/static/'
那么在模板中引用这个文件时你可以这样做
<link rel="stylesheet" type="text/css" href="{% static 'style.css' %}">
Django会将{% static 'style.css' %}
转换为/static/style.css
这是浏览器请求静态文件的URL。所以STATIC_URL
定义了静态文件的基本URL路径让你可以方便地引用这些文件而不需要硬编码整个URL。这使得你的应用更加灵活和可维护因为你可以轻松地更改STATIC_URL
而不必修改所有静态文件的引用。
05-02-创建模板文件user_reg.html并写入代码
创建文件 E:\Python_project\P_001\myshop-test\mall_backend\templates\shop\user_reg.html
然后写入下面的代码
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>页面标题用户注册</title>
<link rel="stylesheet" href="{% static 'other/css/bootstrap.min.css' %}">
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-6 col-md-offset-2">
<div class="page-header">
<h2>用户注册</h2>
</div>
<form novalidate action="" method="post" enctype="multipart/form-data" class="form-horizontal">
{% csrf_token %}
<div class="form-group">
<label for="{{form_obj.username.id_for_label}}" class="col-sm-2">{{form_obj.username.label}}</label>
<div class="col-sm-8">{{form_obj.username}}
<span class="help-block">{{ form_obj.errors.username.0 }}</span>
</div>
</div>
<div class="form-group">
<label for="{{form_obj.password.id_for_label}}" class="col-sm-2">{{form_obj.password.label}}</label>
<div class="col-sm-8">{{form_obj.password}}
<span class="help-block">{{ form_obj.errors.password.0 }}</span>
</div>
</div>
<div class="form-group">
<label for="{{form_obj.re_password.id_for_label}}" class="col-sm-2">{{form_obj.re_password.label}}</label>
<div class="col-sm-8">{{form_obj.re_password}}
<span class="help-block">{{ form_obj.errors.re_password.0 }}</span>
</div>
</div>
<div class="form-group">
<label for="{{form_obj.nickname.id_for_label}}" class="col-sm-2">{{form_obj.nickname.label}}</label>
<div class="col-sm-8">{{form_obj.nickname}}
<span class="help-block">{{ form_obj.errors.nickname.0 }}</span>
</div>
</div>
<div class="form-group">
<label for="{{form_obj.nickname.id_for_label}}" class="col-sm-2">{{form_obj.email.label}}</label>
<div class="col-sm-8">{{form_obj.email}}
<span class="help-block">{{ form_obj.errors.email.0 }}</span>
</div>
</div>
<div class="form-group">
<label for="{{form_obj.nickname.id_for_label}}" class="col-sm-2">{{form_obj.mobile.label}}</label>
<div class="col-sm-8">{{form_obj.mobile}}
<span class="help-block">{{ form_obj.errors.mobile.0 }}</span>
</div>
</div>
<div class="form-group">
<label for="{{form_obj.nickname.id_for_label}}" class="col-sm-2">{{form_obj.user_img.label}}</label>
<div class="col-sm-8">{{form_obj.user_img}}
<span class="help-block"></span>
</div>
<img src="/media/{{ user_img }}">
</div>
<div class="col-8">
<label for="agreeTerms">
{{ info }}
</label>
</div>
<div class="form-group">
<div class="col-sm-10">
<input type="submit" class="btn btn-success" value="用户注册">
<a href="/users/login/" class="btn btn-success">用户登录</a>
</div>
</div>
</form>
</div>
</div>
</div>
</body>
</html>
05-03-模板文件user_reg.html代码详解
01 {% load static %}是什么意思
{% load static %}
是 Django 模板语言的标签用于加载静态文件如样式表、JavaScript 文件等。它告诉 Django 模板引擎在当前模板中启用静态文件的处理以便能够正确地引用静态文件路径。
当你在Django模板中使用 {% load static %}
标签时它会通知Django模板引擎去处理与静态文件相关的操作。这包括了为静态文件生成正确的URL路径以便在模板中正确引用这些文件。
有了上面这句模板语言的声明后当模板引擎看到 {% static %}
标签时它会根据对静态文件的设置生成一个完整的路径使你能够在HTML代码中引用静态文件。
在上面的静态文件路径设置中用了下面三条语句
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, '/static')
设置了上面三条语句后如果在你的代码片段中有下面这一行
<link rel="stylesheet" href="{% static 'other/css/bootstrap.min.css' %}">
那么{% static 'other/css/bootstrap.min.css' %}
会根据在settting.py中设置的静态目录的路径分两步
进行路径
第1步根据STATIC_URL = '/static/'
将路径解析为/static/other/css/bootstrap.min.css
第2步根据STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
【这一句用于调试开发环境】或STATIC_ROOT = os.path.join(BASE_DIR, '/static')
【这一句用于生产部署环境】,将路径中的/static/
替换为E:\Python_project\P_001\myshop-test\mall_backend\static\
最终得到完整的E:\Python_project\P_001\myshop-test\mall_backend\static\other\css\bootstrap.min.css
总之通过在模板中使用 {% load static %}
标签和 {% static %}
标签你可以确保在Django项目中正确处理和引用静态文件使你的网页可以正确加载样式、脚本和其他静态资源。
02 为什么通过语句 将语言设置为英文但是仍然可以有中文字符
答在代码中通过语句 <html lang="en">
设置了页面的主要语言为英文但是仍然可以在页面中包含中文字符这是因为 <html lang="en">
标签只是一种声明它向浏览器和搜索引擎指示页面的主要语言是英文以便它们能够正确地对页面进行处理和显示。
然而这并不意味着页面只能包含英文内容。HTML 中的语言设置主要是为了支持浏览器和搜索引擎的语言处理、搜索和优化。你仍然可以在页面中包含其他语言如中文的内容而不会影响页面的显示。
实际上在网页中你可以同时使用多种语言这对于国际化和多语言支持的网站是很常见的。浏览器可以根据内容自动调整显示的语言同时搜索引擎也能够正确地处理多种语言的内容。
所以尽管你在代码中设置了 <html lang="en">
但是这并不妨碍你在页面中使用中文字符或其他语言的内容。这个设置更多地是为了提供一种指示以帮助浏览器和搜索引擎更好地处理你的网页。
值得注意的是虽然在网页中设置 <html lang="en">
可以帮助浏览器和搜索引擎更好地理解和处理网页内容的语言但并不是必需的。许多网页在实际开发中可能会省略 <html lang>
设置特别是当网页内容包含多种语言时。
在现代的网页开发中浏览器和搜索引擎已经变得足够智能能够自动识别和适应多种语言的内容。这意味着即使你不设置 <html lang>
浏览器仍然可以正确地显示多语言内容并且搜索引擎也可以适当地处理你的网页。
03-代码<link rel="stylesheet" href="{% static 'other/css/bootstrap.min.css' %}">
中的参数rel是什么英文的缩写代表什么意思
详情和答案见博文https://blog.csdn.net/wenhao_ir/article/details/132091300
04-如何彻底理解模板文件user_reg.html中的各种Bootstrap的前端样式
答没有捷径只有认真系统的学习一次bootstrap所以本篇博文对于模板文件user_reg.htm中的各种Bootstrap前端样式不作展开介绍。
04-Bootstrap的类col-md-offset-2是什么效果
在 Bootstrap 3 中col-md-offset-2
是用来创建栅格偏移grid offset的类。它的作用是在大屏幕medium-sized devices上将列column向右偏移两个列宽的位置。这个偏移可以用来调整列的位置以实现更复杂的布局。
具体来说Bootstrap 使用一个12列的栅格系统其中 col-md-
类用于定义列的宽度而 col-md-offset-
类用于定义列的偏移量。所以col-md-offset-2
将列向右偏移两个列的宽度等于 16.6667% * 2 * 100% = 33.3334% 的宽度。
以下是一个示例展示了如何在 Bootstrap 3 中使用 col-md-offset-2
<div class="container">
<div class="row">
<div class="col-md-2">左侧内容</div>
<div class="col-md-offset-2 col-md-8">这个列向右偏移了两个列的宽度然后占据了8个列的宽度</div>
</div>
</div>
在上面的示例中第一个列占据了两个列的宽度而第二个列使用 col-md-offset-2
偏移了两个列的宽度然后占据了剩余的八个列的宽度实现了一个复杂的布局效果。
05-代码 <form novalidate action="" method="post" enctype="multipart/form-data" class="form-horizontal">
详解。
问 关键词 novalidate 是什么意思
详见博文 https://blog.csdn.net/wenhao_ir/article/details/132488987
问action=""是什么意思
详见博文 https://blog.csdn.net/wenhao_ir/article/details/132488987
问enctype=“multipart/form-data” 是什么意思
详见博文 https://blog.csdn.net/wenhao_ir/article/details/132488987
06-代码 <label for="{{form_obj.username.id_for_label}}" class="col-sm-2">{{form_obj.username.label}}</label>
详解一下。
要理解这句代码关键是理解label标签和对象form_obj关于label标签请参考博文 https://blog.csdn.net/wenhao_ir/article/details/132500712
当然实际上上面这句代码实际上并不需要设置这个for属性因为并无别的HTML元素与其联系。
而对象form_obj请参阅视图函数代码中关于函数render()的代码而关于函数函数render()的详解请参阅博文https://blog.csdn.net/wenhao_ir/article/details/132501337
另外还要问“在HTML板模中的“{{form_obj.username.id_for_label}}”和“{{form_obj.username.label}}”得到的结果有什么不同”
回答在Django中{{ form_obj.username.id_for_label }}
和 {{ form_obj.username.label }}
都用于获取表单字段 username
的标签信息但它们有一些不同之处
-
{{ form_obj.username.id_for_label }}
:
这将生成一个用于关联标签和表单字段的 HTMLid
属性的值。通常情况下这个值会与表单字段的id
属性相同用于确保标签与相应的输入字段建立关联。在你的示例中你定义了一个自定义的表单字段username
但没有显式指定id
属性所以Django会自动生成一个唯一的id
值。这个值可以用于在HTML中编写自定义的标签以及用于与输入字段建立关联。示例用法
<label for="{{ form_obj.username.id_for_label }}">Username:</label>
-
{{ form_obj.username.label }}
:
这将返回字段的标签文本即"用户名"。这是你在表单类中通过label
参数指定的标签文本。这通常用于直接输出标签文本而不需要手动指定关联的id
属性。示例用法
<label>{{ form_obj.username.label }}</label>
总的来说{{ form_obj.username.id_for_label }}
主要用于关联标签和输入字段而 {{ form_obj.username.label }}
用于直接获取标签文本。具体的用法取决于你在HTML模板中的需求。如果你需要在HTML中自定义标签并且需要关联标签和输入字段那么你可以使用 {{ form_obj.username.id_for_label }}
。如果你只需要显示标签文本那么 {{ form_obj.username.label }}
就足够了。
07-代码<span class="help-block">{{ form_obj.errors.username.0 }}</span>
解释一下吧。
关于span标签的介绍请参见博文https://blog.csdn.net/wenhao_ir/article/details/132502816
form_obj.errors.username.0
的介绍如下
关于对象form_obj请参阅视图函数代码中关于函数render()的代码而关于函数函数render()的详解请参阅博文https://blog.csdn.net/wenhao_ir/article/details/132501337
在 Django 的表单处理中form_obj.errors
是一个包含表单验证错误信息的字典。这个字典以表单字段为键对应的值是一个列表列表中包含了与该字段相关的所有错误。这些错误通常会在用户提交表单时进行验证例如如果用户名字段为空那么就会产生一个与用户名字段相关的错误。
在你的代码A中{{ form_obj.errors.username.0 }}
这部分的含义是
form_obj.errors
: 表示获取表单对象form_obj
中的错误信息字典。.username
: 表示从错误字典中获取与用户名字段相关的错误列表。.0
: 表示获取该错误列表的第一个元素。
所以{{ form_obj.errors.username.0 }}
的意思是从表单对象的错误字典中获取用户名字段的第一个错误信息。如果你的表单验证中出现了多个关于用户名字段的错误这将会获取第一个错误。如果没有错误它将不会显示任何内容。
例如假设用户没有填写用户名字段那么在验证表单时会产生一个错误该错误信息会被存储在 form_obj.errors.username
列表中的第一个位置。你可以使用 {{ form_obj.errors.username.0 }}
来在模板中显示这个错误信息以便向用户指出出现的问题。
06-配置URL请求路径(配置路由)
打开文件"E:\Python_project\P_001\myshop-test\mall_backend\mall_backend\urls.py"
写入下面的代码
from django.contrib import admin
from django.urls import path
from users import views
urlpatterns = [
path('user_reg/', views.user_reg),
]
07-配置数据库
第01步在文件"E:\Python_project\P_001\myshop-test\mall_backend\mall_backend\settings.py"中写入以下数据库的配置信息
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'mall-backend',
'USER': 'mall-backend',
'PASSWORD': 'swh123456',
'HOST': 'localhost',
'PORT': '3306',
# 取消外键约束否则多对多模型迁移报django.db.utils.IntegrityError: (1215, 'Cannot add foreign key constraint')
'OPTIONS': {
"init_command": "SET foreign_key_checks = 0;",
'charset': 'utf8'
},
}
}
第02步在mysql中按上面的信息创建数据库 mall-backend
第03步生成数据库的迁移执行文件
CD E:\Python_project\P_001\myshop-test\mall_backend
E:
manage.py makemigrations
第04步执行数据库迁移模型
CD E:\Python_project\P_001\myshop-test\mall_backend
E:
manage.py migrate
此时可以查看下数据库中是否有相关的表了
08-运行应用
CD E:\Python_project\P_001\myshop-test\mall_backend
E:
python manage.py runserver 127.0.0.1:8010
09-访问URL路径测试有无问题
根据“E:\My_Data\0072-Django教材源码\myshop-back\apps\users\urls.py” 设置的URL。
应该访问下面这个URL:
http://127.0.0.1:8010/user_reg/
运行效果如下
注册一个用户试下:
点用注册后数据库中出现了下面这条记录
10-项目打包源文件
链接https://pan.baidu.com/s/1BgQ3aH3OQs2vALgq7wd67w?pwd=rubw
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |