个人网站功能包括发表、存储个人文章,保存网络上的图片,展示图片,保存并展示个人视频。以下为网站的登陆注册部分。
上期文章:个人网站开发前相关项目配置
再网站开发中,用户登录验证的一个简单思路通常是将用户输入的信息与数据库中的信息比对,若一致则通过,反之,验证失败.
在本项目中,也采用这种验证方式。这里要用到数据库,Django默认采用自带的sqlite数据库,在这里无需对数据库做改动,若采用MySQL等其它数据库,需要对配置文件做些改动,这里不再详细描述。
这里可以将数据模型简单地理解为数据表,编写数据模型即设计数据库的表中有哪些内容,数据模型需要在应用中的models.py文件中编写。
下面为一个用户个人信息示例:
class UserProfile(models.Model):
birth = models.DateTimeField(max_length=100,blank=True)
phone = models.CharField(max_length=20)
def __str__(self):
return 'user {}'.format(self.user.username)
在这个模型中,包含了用户的’phone’,'birth’信息,由此可见,设计一个数据模型就是一个类,这个类继承了models类,在这个类中字段是各个字段类的实例,例如’phone’是字符型,它是字段类’CharField’类的实例,我们可以在类中添加一些属性,例如最大长度 max_length
,是否可以为空blank
等,关于数据模型具体操作会以后再讲解。
当创建好数据模型之后,需要生成数据表并迁移,这两步现在不需要详细了解,再终端中执行下面两条命令。
python manage.py makemigrations
python manage.py migrate
需要用户填写信息时,会用到表单,通常会采用标签,在django中也可以采用这种方式,但django提供了一种表单方式可以让我们方便处理表单数据,这便是form表单。
采用form表单时需要创建一个类,在应用文件中创建一个 forms.py文件。
打开文件,输入以下代码:
class UserProfileForm(forms.ModelForm):
birth= forms.DateTiemField()
phone=forms.CharField()
class Meta:
model = UserProfile
fields=('birth', 'phone',)
可以看出form表单与数据模型相似,表单类继承了forms类,在这个表单中,用户需填写’birth’和‘phone’,同models一样,forms中各个字段也可以设置max_length
等属性。在页面中使用表单时,表单会生成****标签,无需自己编写。
这里有一个Meta类,其中model = UserProfile
声明了表单对应哪个类型。通常我们会将表单的数据保存至数据库。models中字段与forms中的字段一一对应,为了减少重复,在Meta类中声明采用的数据模型,告诉forms需要展示这个数据模型中的字段。有时数据模型中的字段不会完全用到,设置一个fields属性,其值为我们想要展示的字段。
用户登录时,需要设计一个用户登录的数据模型,其中包括用户名和登录密码。django内置了包含用户基本信息的数据模型User,其中包括用户名,密码,邮箱等基本信息。这包含了用户登录时用到的基本信息,所以无需再额外设置数据模型了。
下面编写用户登录的表单:
class LoginForm(forms.Form):
username = forms.CharField()
password = forms.CharField(widget=forms.PasswordInput)
编写用户登录的视图文件,打开views.py:
from django.http import HttpResponse
from django.shortcuts import render
from.forms import LoginForm
from django.contrib.auth import authenticate,login
def Login(request):
if request.method == "POST":
forms = LoginForm(request.POST)
if forms.is_valid():
cd = forms.cleaned_data
user = authenticate(username=cd['username'], password=cd['password'])
if user:
login(request, user)
return HttpResponse("登录成功")
else:
return HttpResponse("登录失败")
else:
return HttpResponse('请输入正确格式的数据')
else:
forms = LoginForm()
return render(request, "account/login.html", {"form": forms})
现在来分析用户登录时的请求过程。
当用户打开登陆页面时,前端会以“GET”方式向后端发送请求,当用户填写好表单点击按钮提交时会向后端发送“POST”请求。
在视图文件中,分别对这两种请求进行不同处理。
request.method == "POST"
是确定当请求方式为“POST”时的情况。
forms = LoginForm(request.POST)
以“POST”请求生成了一个LoginForm实例,由于“POST”包含了用户填写的所有信息,实例forms中也包含了用户所有信息。
forms.is_valid()
是验证表单数据是否合法,如数据据类型的字段被填写为字符类型会验证失败。
cd = forms.cleaned_data
clean_data方法是对表单数据清洗,返回字典类型。
cd[‘username’] 和 cd[‘password’] 是提取清洗后的数据中的“username”,“passowrd”内容。
authenticate() 是django内置的用户验证方法,以用户名和密码作为参数验证用户名和密码是否匹配。
login() 是django内置的登录方法。
当请求方式为“GET”时,生成一个空的表单实例,并渲染登陆模板,并把表单的实例作为参数发送至前端页面。
模板编写
<form action="." method="post">
{% csrf_token %}
用户名:{{ form.username }}
密码:{{ form.password }}
<input type="submit" value="提交"/>
form>
在设计用户名和密码填写表单时,并未用到标签,而是**{{form.password}}**,当浏览器解析时,会自动解析成标签。
{{ }} 和 {% %} 都是django模板语言,前者是定义变量,后者是用来定义控制语句。
当使用表单时,需要在标签内添加 {% csrf_token %}
这个模板页面只是简单编写,还可以添加样式,下面为完整代码
{% extends 'base.html' %}
{% load static %}
{% block title %}登录{% endblock %}
{% block content %}
<form class="form_horizontal" action="." method="post">
{% csrf_token %}
<div class="form-group">
<label for="username">用户名:label>
{{ form.username }}
div>
<div class="form-group">
<label for="password">密码:label>
{{ form.password }}
div>
<div class="form-group">
<input type="submit" value="提交"/>
div>
form>
{% endblock %}
{% extends 'base.html' %}
是引入外部的base.html文件
{% load static %}
当页面中需要引入静态变量,需要使用此标签
{% block content %}相当于在base.html中定义了一块名为content区域,当想要在外部页面中向这块区域中添加内容时,只需引入此文件,添加这个标签并在这个标签中添加内容即可。
例如此页面中 {% block content %} {% endblock %} 的内容将会填加到外部页面 base.html 中的 {% block content %} {% endblock %} 中。
用户注册过程与登录相似,注册的数据模型需要自己编写。
models.py:
from django.contrib.auth.models import User
class UserProfile(models.Model):
user=models.OneToOneField(User, on_delete=models.CASCADE,unique=True)
birth = models.DateTimeField(max_length=100,blank=True)
phone = models.CharField(max_length=20)
def __str__(self):
return 'user {}'.format(self.user.username)
其中 user定义了UserProfile数据表与User表是一对一关系。
forms.py
from .models import UserProfile
from django.contrib.auth.models import User
class RegisterForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput)
password_2 = forms.CharField(widget=forms.PasswordInput)
class Meta:
model = User
fields = ('username', 'email',)
def clean_password_2(self):
cd = self.cleaned_data
if cd['password'] != cd['password_2']:
raise forms.ValidationError("password do not match.")
return cd['password_2']
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields=('birth', 'phone',)
views.py
from django.http import HttpResponse,HttpResponseRedirect
from django.shortcuts import render
from.forms import RegisterForm, UserProfileForm
from django.urls import reverse
def Register(request):
if request.method == "POST":
register = RegisterForm(request.POST)
userprofile = UserProfileForm(request.POST)
if register.is_valid():
cd = register.cleaned_data
new_user = register.save(commit=False)
new_user.set_password(cd['password'])
new_user.save()
new_profile = userprofile.save(commit=False)
new_profile.user = new_user
new_profile.save()
return HttpResponseRedirect(reverse("account:login"))
else:
return HttpResponse('请输入正确格式')
else:
userForm = RegisterForm()
profileForm = UserProfileForm()
return render(request,'account/register.html', {'userForm': userForm,'profileForm':profileForm})
new_user = register.save(commit=False)
这是将表单内容保存至数据库,但添加了commit=False,这是还要对表单内容作出修改,先不保存至数据库。
new_user.set_password(cd['password'])
设置表单的 password 字段。
new_profile.save()
这是将表单内容保存至数据库。
register.html
{% extends "base.html" %}
{% load static %}
{% block title %}注册{% endblock %}
{% block content %}
<div class="row">
<form class="form_horizontal" action="." method="post">
{% csrf_token %}
<div class="form-group">
<label for="username">用户名label>
{{userForm.username}}
div>
<div class="form-group">
<label for="exampleInputPassword1">输入密码label>
{{ userForm.password }}
div>
<div class="form-group">
<label for="exampleInputFile">确认密码label>
{{ userForm.password_2 }}
div>
<div class="form-group">
<label for="exampleInputPassword1">邮箱label>
{{ userForm.email }}
div>
<div class="form-group">
<label for="exampleInputFile">生日label>
{{ profileForm.birth}}
div>
<div class="form-group">
<label for="exampleInputFile">联系方式label>
{{ profileForm.phone }}
div>
<button type="submit" class="btn btn-default">Submitbutton>
form>
div>
{% endblock %}