您的位置:首页 > 运维架构 > Nginx

技术笔记——Django+Nginx+uwsgi搭建自己的博客(二)

2017-11-25 17:46 549 查看
在上一篇博客中,为大家介绍了Django的一些基本概念以及建立了第一个App——Users,并且在数据库中建立了对应的表。

在这篇博客中,将为大家继续介绍数据库模型的定义和相关操作,以及Users App功能的后端实现——注册,登录以及查看用户资料。

上篇博客中,我们通过Users model建立了users_users表:

from django.db import models
import datetime
import PIL
# Create your models here.
class Users(models.Model):
username = models.CharField(max_length=8,primary_key=True,unique=True)
password = models.CharField(max_length=16)
logoimage = models.ImageField(upload_to='logoimages',null=True)
# new field
birthday = models.DateTimeField(null=True,blank=True)
email = models.CharField(max_length=255,null=True,blank=True)
mobilephone = models.CharField(max_length=11,null=True,blank=True)
# new field end
registertime = models.DateTimeField() Django为model提供了相关的字段类,通过字段类的使用,我们可以方便地定义数据库中字段的属性以及限制。以Users model为例,我们将username、password、email和mobilephone设计为CharField,用于存储纯文本数据;logoimage设计为ImageField,用于存储图片。此处也可以用FileField,但与ImageField相比,ImageField多了两个参数ImageField.height_field和ImageField.width_field用于设置图片的长和宽;birthday显然应该设计为DateField(此处不小心设计成了DateTimeField,其实也无大碍)。
对于CharField来说,max_length为可输入的最大字符数,primary_key标志该字段是否是主键,unique决定了是否有unique限制,null属性决定了该字段可否为空。

对于ImageField来说,一个特殊的地方是upload_to属性,该属性的值为定义在myblog/settings.py中的MEDIA_ROOT路径下的子目录。

例如,MEDIA_ROOT='/home/media/',upload_to='logoimage',则文件应该被上传到/home/media/logoimage/目录下。

在Django中,网页要调用的服务器端程序称之为视图(view),存储在views.py文件中;而与每个view相关联的url存储于urls.py文件中。通过在urls.py中写入相关的配置,我们可以实现前后端的关联。

首先来实现用户注册功能,如图所示:



该页面主要由一个表单组成,在输入相关信息后,点击提交按钮,信息会提交给Django程序,完成用户的注册工作。

Django提供了forms类用于设计表单。通过使用forms类,我们可以直接在服务器端设计表单,并将其渲染到前端中;当然,我们也可以直接在前端设计表单,并调用Django程序处理表单的数据。

我们在users文件夹下建立一个userForm.py文件,在这个文件中我们将定义两个表单:UserRegisterForm和UserLoginForm,前者用于用户注册,而后者用于用户登录。

userForm.py文件内容如下:

#-*- coding=utf-8 -*-
from django import forms

class UserRegisterForm(forms.Form):
username = forms.CharField(label=u'用户名',max_length=8,required=True)
password = forms.CharField(label=u'密码',widget=forms.PasswordInput,required=True)
birthday = forms.DateField(label=u'生日',widget=forms.SelectDateWidget,required=False)
email = forms.EmailField(label=u'电子邮件',required=False)
mobilephone = forms.CharField(label=u'手机号码',max_length=11,required=False)
logoimage = forms.FileField(label=u'头像',required=True)

class UserLoginForm(forms.Form):
username = forms.CharField(label=u'用户名',max_length=8,required=True)
password = forms.CharField(label=u'密码',widget=forms.PasswordInput,required=True)

在Django中,每个表单类都是Form类的子类,而类的成员变量则是表单中的各个字段,变量名称用于在view函数中取得对应栏位的数据。
在UserRegisterForm中,我们将username、password和mobilephone设置为CharField,将birthday设置为DateField,将email设置为EmailField,最后将头像文件logoimage设置为FileField,以便实现以后的上传头像功能。对于username、password和logoimage,我们将其设置为必选项,而余下三项设置为可选项。且通过使用widget将password设置为密码框格式,DateField设置为下拉框样式。

Django为我们提供了各种field,最常用的field就是CharField,其用于存储一般的文本信息。在CharField中,label属性值决定表单中的标题,max_length用于限制表单的最大输入长度,required属性用于决定该栏位是否可选,而widget决定了该栏位在前端应渲染为哪种样式。

与直接在前端设计表单相比,Django提供的Field会提供一些数据验证功能,如对email格式的验证、对日期的验证以及对必填字段的验证工作,这点为我们提供了很大便利,省去了在前端编写验证程序的工作。

UserLoginForm表单的设计与UserRegisterForm类似,只有两个表单项username和password。

现在,我们已经建立好了自己的表单类,可以开始编写view函数以及设置url配置项了。

在users目录下建立urls.py文件,该文件用于存储url与view函数的对应关系,以便在前端中使用。

# urls.py
from django.conf.urls import url,include
from . import views
from myblog.views import index

app_name='users'
urlpatterns = [
url(r'^$', index, name='index'),
url(r'^userregister/$',views.userregister,name='userregister'),
url(r'^userlogin/$',views.userlogin,name='userlogin'),
url(r'^loginResult/(?P<info>.*)$',views.loginResult,name='loginResult'),
url(r'^registerResult/(?P<info>.*)$',views.registerResult,name='registerResult'),
url(r'^logoff/$',views.logoff,name='logoff'),
url(r'^userinfo/$',views.userInfo,name='userInfo')
]该文件主要由两部分组成:app_name与urlpatterns。前者决定了该urls.py属于哪个App,以便在工程目录下的urls.py中调用;而urlpatterns列表存储了url和视图的对应关系,其元素为url对象。
url对象的声明分为三部分:正则表达式、view函数以及url名称。正则表达式用于匹配url,view函数名称为当某url被正则表达式匹配后执行的view函数,而name属性用于POST表单提交后的重定向以及前端中表单标签的action属性使用。在正则表达式中,可以使用?P<参数名>的方式来执行带参数的view函数,稍后会看到相关的范例。

以url(r'^userlogin/$',views.userlogin,name='userlogin')为例,该行匹配的意思为,当url以”userlogin/“结尾时,执行views.py中定义的userlogin函数,该url的name名称为userlogin,可用于登录表单的action属性。

设置好url配置之后,就可以开始编写view函数了。在views.py中,我们一共要编写userregister,registerResult,userlogin,loginResult,userInfo和logoff这六个view函数,分别对应用户注册界面、注册结果、用户登录、登录结果、用户信息与退出登录功能。

打开views.py文件,编写userregister函数,代码如下:

# views.py
# -*- coding=utf-8 -*-
from django.shortcuts import render
from django.http import HttpResponse,HttpResponseRedirect
from .models import Users
from django.urls import reverse
from PIL import Image
from django.core.exceptions import ValidationError
from django.contrib.sessions.backends.db import SessionStore
from myblog.settings import MEDIA_ROOT
from .userForm import UserRegisterForm,UserLoginForm

# Create your views here.
def userregister(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST,request.FILES)
if form.is_valid():
username = form.cleaned_data['username']
password = form.cleaned_data['password']
birthday = form.cleaned_data['birthday']
email = form.cleaned_data['email']
mobilephone = form.cleaned_data['mobilephone']
logoimage = request.FILES['logoimage']
imgname = ''
result_info = ''
try:
user = Users.create(username, password, birthday, email, mobilephone)
user.validate_unique()
user.save()
if logoimage:
img = Image.open(logoimage)
imgname = username + logoimage.name
img = img.convert('RGB')
img.save(MEDIA_ROOT + '/logoimages/' + imgname)
Users.objects.filter(username=username).update(logoimage=imgname)
result_info = 'success'
except ValidationError as e:
result_info = e.messages
return HttpResponseRedirect(reverse('users:registerResult', kwargs={'info': result_info}))
else:
form = UserRegisterForm()
return render(request,'users/userregister.html',{'form':form})

每一个view函数都有一个request参数,该参数用于接收从前端返回的信息。
在该view函数中,我们首先判断发送过来的request请求是否为POST请求,若是POST请求,则使用POST方法构造之前我们定义的UserRegisterForm表单。随后,我们调用is_valid()函数检查表单中的值是否与我们需要的一致。随后,我们从form.cleaned_data字典中取得各个字段的值,该字典的key值为UserRegisterForm的成员变量名称。注意,对于FileField,我们使用request.FILES['logoimage']方法来取得文件对象,而不是使用cleaned_data字典。

在取得各个值之后,我们使用上一篇提到的create函数来建立新的用户,并将用户上传的头像保存在MEDIA_ROOT/logoimages/目录下,文件名为username与图片名的连接,并使用update方法将头像图片名称存储到数据库中。其中,MEDIA_ROOT为所有上传文件的根目录,定义在myblog目录下的settings.py中。

在处理表单发送的数据之后,我们会调用HttpResponseRedirect函数重定向到registerResult页面。HttpResponseRedirect函数的参数为reverse对象,该对象的作用是根据之前在urls.py中的name反向找出其对应的url,并执行该url对应的view函数。在Django中,若想向其他页面传递参数,可在reverse函数中通过传递字典的方式进行:['传递的参数名':参数值]

registerResult函数及其url配置如下:

# urls.py
...
url(r'^registerResult/(?P<info>.*)$',views.registerResult,name='registerResult')
...
# views.py
def registerResult(request,info):
if info == 'success':
content = '注册成功!'
else:
content = info
return render(request,'users/registerResult.html',{'result_info':content})可以看到,urls.py中的?P<info>与views.py的registerResult(request,info)相对应,而在reverse中传递了['info':result_info],即把result_info的值传递给了info参数。
一般来说,每个view函数都会调用render函数将其后台数据渲染到前端页面中,并且可能还会传递相关的参数到网页中。以registerResult函数为例,render函数将此页面的内容渲染到’users/registerResult.html中,并且向页面中的result_info变量传递了content参数。

下面来编写userLogin函数,该函数实现了用户登录功能,并且在登录成功后将登录的用户名存储在session中,以便之后使用。

userLogin以及loginResult函数:

# views.py
def userlogin(request):
if request.method == 'POST':
form = UserLoginForm(request.POST)
if form.is_valid():
username = form.cleaned_data['username']
password = form.cleaned_data['password']
result_info = ''
try:
user = Users.objects.get(username=username)
tmpPassword = user.password
if tmpPassword == password:
result_info = 'success'
request.session['username'] = username
else:
result_info = 'fail'
except Exception as e:
result_info = 'fail'
return HttpResponseRedirect(reverse('users:loginResult', kwargs={'info': result_info}))
else:
form = UserLoginForm()
return render(request, 'users/userlogin.html',{'form':form})

def loginResult(request,info):
if info == 'success':
content = '登录成功!'
username = request.session['username']
return HttpResponseRedirect(reverse('index'))
else:
content = '用户名或密码错误!'
return render(request,'users/loginResult.html',{'result_info':content})

这两个函数与userregister和registerResult类似,都是通过表单读取数据后进行一系列操作。在userLogin函数中,登录成功后会使用request.session['username'] = username将登录成功的用户名存入session中。
当我们拿到了username之后,我们通过Users.objects.get(username=username)的方式拿到以username为主键的那条记录。在Django中,通常使用两种方式从数据库中拿记录:Model名.objects.get(some condition) 或者Model名.objects.filter(some condition)。这两者的区别在于,get方法一次只能拿一条记录,若有多条记录返回,则get方法会报错;而filter可以返回多条数据。

剩下两个小函数,相对比较简单:userInfo和logoff。前者用于显示已登录的用户信息,而后者用于退出登录。

# views.py
def userInfo(request):
username = request.session['username']
try:
user = Users.objects.get(username=username)
birthday = user.birthday
email = user.email
registertime = user.registertime
content = {'username':username,
'registertime':registertime,
'birthday':birthday,
'email':email}
except Exception as e:
pass
return render(request,'users/userinfo.html',content)

def logoff(request):
try:
del request.session['username']
except KeyError:
pass
return HttpResponseRedirect(reverse('index'))在userInfo中,当用户登录后,我们就可以通过request.session['username']拿到已登录的用户名,进而到数据库中查询相关信息并返回给页面;而在logoff函数中,我们执行的动作是从session字典中删除key=username的元素,从而达到退出登录的目的。
这篇博文介绍了上一篇建立的Users model的相关内容,以及Users App后台功能的实现,在下一篇博文中将介绍myblog/settings.py中的相关配置以及Users App的前端部分,希望大家继续关注~

(未完待续)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  django nginx