Django的入门(二)创建models和处理数据、上传显示图片
继续上文,这次完成接收前端网页的GET和POST请求数据并处理
具体功能为实现注册账户密码和修改密码功能,并实现数据库交互
终端开启服务器
- cd 到你的文件夹
- workon django_py3 // 用workon打开你配置好的虚拟环境
- python manage.py runserver // 运行服务器
记录终端的内容到txt文件中
在你要放这个txt文件的地方创建
script -a 1.txt
设定接下去的终端所有内容,都打印到1.txt这个文件,同时在终端显示结果。只到你输入:
exit
为止。这样打印出来的文本文件直接在图形化的gedit打开有些字符是无法正常显示的,但是如果利用
cat 1.txt
发现是没有乱码的。
关闭csrf保护的三种方法
在html文件的表单标签里写
<form method="POST" action="/user/changepwd/">
{# 前后端不分离发送form表单要加这个 #}
{% csrf_token %}
在setting.py这个列表第四个,注释掉即可
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware', # 这个就是验证
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
在viwes.py导包然后写装饰器,也是关csrf验证
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def changepwd(request):
创建注册网页
这里action是跳转到handleraddress/,要注意斜杠
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>注册账号</h1>
<form method="POST" action="/user/handleraddress/">
{# 前后端不分离发送form表单要加这个 #}
{% csrf_token %}
<sapn>请输入名字</sapn><input type="text" name="username"><br>
<sapn>请输入密码</sapn><input type="password" name="pwd"><br>
<sapn>请确认密码</sapn><input type="password" name="cpwd"><br>
<sapn>请输入地址</sapn><input type="text" name="addname"><br>
<sapn>请输入手机号码</sapn><input type="text" name="phone"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
在models.py添加数据库字段(列名)
直接添加一个字段password,然后在终端写python manage.py makemigrations迁移数据库
python manage.py migrate
# 每个表对应一个类
class UserInfo(models.Model):
name = models.CharField(max_length=20)
password = models.CharField(max_length=20, default='123456')
phone = models.CharField(max_length=11)
addkey = models.ForeignKey(AddressInfo, on_delete=models.CASCADE)
class Meta:
# 元类
db_table = 'userinfo'
verbose_name_plural = '用户信息'
def __str__(self):
return self.name
在url.py写跳转逻辑
最下面三个是今天要写的功能
from django.conf.urls import url
from user.views import *
urlpatterns = [
url(r'^index/', index),
url(r'^userinfo/', userinfo),
url(r'^show_userinfos/', show_userinfos),
url(r'^register/', register),
url(r'^handleraddress/', handleradd),
url(r'^changepwd/',changepwd),
]
url路径匹配使用正则匹配
- 这是用()里面内容正则匹配,会匹配出一组则会生成一个参数自动传输到views.py里对应的函数, 所以需要多加一个参数
- ()正则匹配如果多写了,就要多添加几个参数
- 正则写多了可以用?P<NAME>,这个name是写别名用的
url(r'^(?P<city>city)/(?P<cname>\w+)/', showadd),
在views.py的对应方法showadd加参数:
def showadd(request, cname, city):
print(request.path) # 这两种都能打印路径
print('城市名字是', cname) # 这种更直接,直接打印正则匹配的路径没有/
print('city是', city)
return HttpResponse('城市页面')
在views.py写功能
上面导包不能少
from django.shortcuts import render
from django.http import HttpResponse, JsonResponse
import re
def register(request):
# render返回网页,HttpResponse返回字符串,JsonResponse返回json数据
return render(request, 'register.html')
def handleradd(request):
print('##############################3')
print(request.POST)
# addname = request.GET.get('addname')
# POST的获取方法
addname = request.POST.get('addname')
username = request.POST.get('username')
phone = request.POST.get('phone')
pwd = request.POST.get('pwd')
cpwd = request.POST.get('cpwd')
# 如果为空返回false
if not all([username, addname, phone, pwd, cpwd]):
return JsonResponse({'null': "can't be null!!"})
# 验证用户名的首字母大写,必须是数字字母下划线6-8位
# 校验两次密码是否一致
# 校验地址,不存在则创建,存在则使用旧地址
# 将处理后的数据插入数据库
ret = re.match(r"^[A-Z][a-zA-Z0-9_]{5,7}$", username)
try:
print('匹配成功', ret.group())
if pwd == cpwd:
try:
# 检验数据库是否已存在地址
add_obj = AddressInfo.objects.get(add=addname)
except BaseException as e:
print('校验数据库出的错误:', e)
add_obj = AddressInfo.objects.create(add=addname)
finally:
UserInfo.objects.create(
name=username,
password=pwd,
phone=phone,
addkey=add_obj
)
return HttpResponse('OK')
else:
return HttpResponse('密码不一致')
except BaseException as e:
print('校验用户名出的错误:', e)
return HttpResponse('用户名的首字母大写,必须是数字字母下划线6-8位')
def changepwd(request):
if request.method == 'GET':
print('###############')
print('进入get请求')
return render(request, 'changepwd.html')
else:
# 进入post请求
# 参数分别是用户名,旧密码,新密码,确认新密码
username = request.POST.get('username')
old_pwd = request.POST.get('old_pwd')
pwd = request.POST.get('pwd')
cpwd = request.POST.get('cpwd')
'''1.检验名字是否存在
2.校验旧密码是否匹配
3.输入密码和确认密码是否一致
4.最后修改'''
try:
# 检验数据库是否存在用户名
user_list = UserInfo.objects.filter(name=username)
print('*********************POST')
obj = user_list[0]
if len(user_list) == 0 or obj.password != old_pwd:
return HttpResponse('用户名或者密码存在错误')
else:
if pwd != cpwd:
# 判断密码
return HttpResponse('密码不一致')
# 取出对象,然后修改密码并保存
user_obj = UserInfo.objects.get(name=username)
# user_obj.password = pwd
# 第二种修改方法
user_obj.objects.update(password=pwd)
user_obj.save()
return HttpResponse('ok')
except BaseException as e:
return HttpResponse(e)
views.py某些小知识点
request.GET或者POST得到的是一个类字典结构的数据,其实是QueryDict对象
用postman软件模拟get请求,即
localhost:8000/user/city/beijing?name=小王&age=18&age=19
然后request.GET打印出来结果为:
<QueryDict: {'name': ['小王'], 'age': ['18', '19']}>
但是用getlist可以获取所有,这两个方法都可以设置默认值
print(request.GET) # 只能获取一个,最后那个
print(request.GET.getlist('age')) # 获取对应的列表
POST请求的时候CheckBox传递加名字
value设置名字,不设置则显示状态
<form method="post" action="show">
姓名:<input type="text" name="username">
爱好:<input type="checkbox" name="hobby" value="sing">唱
<input type="checkbox" name="hobby" value="dance">跳
<input type="checkbox" name="hobby" value="rap">rap
<input type="checkbox" name="hobby" value="basketball">篮球
<input type="submit" value="提交">
</form>
打印结果
<QueryDict: {'hobby': ['on', 'on', 'on', 'basketball'], 'username': ['cxk']}>
POST发送文件
<input type="file" name="file"><br>
打印request.body得到的是二进制编码,这里可以用png,jpg,jpeg文件
print(request.body) # 这个获取到的就是原始文件数据,bytes类型
print(request.POST) # 类字典
data = request.body
with open('上传的图片.png', 'wb+') as f:
f.write(data)
这时候用POSTMAN软件模拟请求:
如何使用form表单提交文件:
修改这个enctype
<form method="post" action="show2" enctype="multipart/form-data">
然后打印看看效果
print(request.FILES) # 这个获取到的是字典类型
# <form method="post" action="show2" enctype="multipart/form-data">
print(request.FILES['file']) # 这个打印显示是一个class django的某种对象
所以可以使用这个对象:
file_obj = request.FILES['file']
print('##################')
# chunks表示不溢出内存读取,打印出来的是二进制及文件内容
for i in file_obj.chunks():
print(i)
with open('form上传的.png', 'wb+') as f:
f.write(i)
Django怎么显示图片
图片是本地路径上,但是Django里img标签src只会查找url路径,不能填相对路径或者绝对路径,因此需要转换
在urls.py进行转换:
from django.views.static import serve
# 导包
# 指定路径显示图片,serve是方法
# document_root后面对的是本地相对路径
urlpatterns = [
url(r'^medias/(?P<path>.*)$', serve, {'document_root': ''}),
]
然后在views.py对应方法写:
print(request.FILES['file']) # 这个打印显示是一个class django的某种对象
file_obj = request.FILES['file']
print('##################')
# chunks表示不溢出,打印出来的是二进制及文件内容
imgsrc = '../medias/xiaobei.jpg' # 这个是相对路径,根据url配置来
for i in file_obj.chunks():
# 这个是表单上传并写入到本地的地址,默认为相对根目录路径
with open('xiaobei.jpg', 'wb+') as f:
f.write(i)
# hobby是表单选择得到的结果,多项选择因此是list,进行拼接,也可以直接传列表
list1 = request.POST.getlist('hobby')
str1 = ''
for s in list1:
str1 += ' ' + s
name = request.POST['username']
# 把这些拼成context字典传过去,然后在html处理
context = {'imgsrc': imgsrc, 'name':name, 'interest':str1}
return render(request, 'myprofile.html', context)
在对应的html界面处理数据:
<head>
<meta charset="UTF-8">
<title>个人资料</title>
<style>
h1{
display: inline-block;
}
.imgsrc{
border-radius: 50px;
display: inline-block;
}
</style>
</head>
<body>
<h1>{{ name }}</h1><img src="{{ imgsrc }}" class="imgsrc" width="50px" height="50px"><br>
<span>我的爱好是:{{ interest }}</span>
</body>
这样显示的网页内容为: