完成一个完整的网页服务,需要有以下:

再次回顾一下Django 的完成开发流程:

一些值的获取:
对于性别,为互斥属性:


爱好则为多选:

需要使用新的方法 getlist 来获取多个爱好:

单选下拉框选择获取:

多选下拉框也需要用到getlist
对于上传文件的设置:
1 首先form 表单要设置特殊属性:

2 文件上传使用新的方法:

使用chunks 来一点一点获取数据:

上传文件到指定目录:

总结一下常用的方法:

然后来实践一下,把上面的全部实现一下:
views:
from django.shortcuts import render,redirect,HttpResponse
# Create your views here.
def user(request):
print('user')
if request.method == 'GET':
return render(request,'user.html')
elif request.method == 'POST':
#用户名
u = request.POST.get('user')
#密码
p = request.POST.get('pwd')
#性别
g = request.POST.get('gender')
#城市
c = request.POST.get('city')
#爱好
f = request.POST.getlist('favor')
print(u,p,g,c,f)
#文件是一个对象,可以查看对象,大小等
f_obj = request.FILES.get('up_head_img')
#获取文件名
f_name = f_obj.name
f_size = f_obj.size
print(f_name,f_size)
#真正接收并存到本地
import os
file_path = os.path.join('upload',f_obj.name)
block_size = 0
with open(file_path,mode='wb') as f:
for block in f_obj.chunks():
#用这个来获取的当前已经上传了多少,可以给用户返回
block_size += len(block)
print(block_size)
f.write(block)
print(f_obj.name,'传完了')
return HttpResponse('200')
urls:

html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/user/" method="POST" enctype="multipart/form-data">
<div class="text">
<label>用户名</label>
<input type="text" name="user"/>
<label>密码</label>
<input type="password" name="pwd"/>
</div>
<div class="chose">
<div>
<label>性别</label>
<input type="radio" name="gender" value="1"/>男
<input type="radio" name="gender" value="2"/>女
</div>
<div>
<label>城市</label>
<select name="city">
<option value="sh">上海</option>
<option value="bj">北京</option>
<option value="tj">天津</option>
<option value="sjz">石家庄</option>
</select>
</div>
<div>
<label>爱好</label>
<input type="checkbox" name="favor" value="1"/>骑行
<input type="checkbox" name="favor" value="2"/>旅游
<input type="checkbox" name="favor" value="3"/>音乐
<input type="checkbox" name="favor" value="4"/>电影
<input type="checkbox" name="favor" value="5"/>把妹
<input type="checkbox" name="favor" value="6"/>吃吃吃
</div>
</div>
<div class="upload">
<label>上传头像</label>
<input type="file" name="up_head_img"/>
</div>
<input type="submit" value="提交所有数据"/>
</form>
</body>
</html>
效果:

Django 有两种方式:
1 FBV
function base view
function函数处理的方式
2 CBV
class base view
class类处理的方式
写一个类处理的方式:
1 先导入View 模块
2 定义类及里面的属性

3 定义url:

4 html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<form action="/home/" method="POST">
<h1>测试Class 处理方式 CBV</h1>
<input type="submit" value="测试提交方法"/>
</form>
</div>
</body>
</html>
5 测试:

在这里我们可以实现一个类似装饰器的功能,就是在类里的方法执行前或后添加一些其他功能:
使用dispatch 函数:
from django.views import View
class Home(View):
def dispatch(self, request, *args, **kwargs):
#调用父类中的
print('访问前要执行的')
result = super(Home,self).dispatch(request,*args,**kwargs)
print('访问后要执行的')
return result
def get(self,request):
print('使用方法:', request.method)
return render(request,'home.html')
def post(self,request):
print('使用方法:',request.method)
return render(request, 'home.html')
测试:

以上为常用的方法。
下面学习下模板语言:
1 在html 中如何循环得道的字典数据呢?
实践:
views:
USER_DICT = {
'k1': 'root1',
'k2': 'root2',
'k3': 'root3',
'k4': 'root4',
'k5': 'root5',
}
def moban(request):
return render(request,'moban.html',{'USER_DICT':USER_DICT})
html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div>
<span>测试for 循环 只循环key</span>
<ul>
{% for k in USER_DICT.keys %}
<li>{{ k }}</li>
{% endfor %}
</ul>
</div>
<div>
<span>测试for 循环 只循环value</span>
<ul>
{% for v in USER_DICT.values %}
<li>{{ v }}</li>
{% endfor %}
</ul>
</div>
<div>
<span>测试for 循环 全部循环</span>
<ul>
<li>k -- v</li>
{% for k,v in USER_DICT.items %}
<li>{{ k }} -- {{ v }}</li>
{% endfor %}
</ul>
</div>
</body>
</html>
urls:
from user import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^user/', views.user),
url(r'^home/', views.Home.as_view()),
url(r'^moban/', views.moban),
]
效果:

下面实现一个稍微复杂一点的:
1 列出字典的k及value里的一个值
views:
USER_INFO = {
'1': {'name':'shenyang','age':25,'mail':'123@qq.com'},
'2': {'name':'wang','age':18,'mail':'456@qq.com'},
'3': {'name':'xiaoming','age':19,'mail':'789@qq.com'},
'4': {'name':'xiaohua','age':11,'mail':'101112@qq.com'},
}
def list(request):
return render(request,'list.html',{'USER_INFO':USER_INFO})
urls:
url(r'^list/', views.list),
html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>用户列表</h1>
<div>
<ul>
{% for k,v in USER_INFO.items %}
<li><a target="_blank" href="/detail-{{ k }}.html">{{ k }} -- {{ v.name }}</a></li>
{% endfor %}
</ul>
</div>
</body>
</html>
效果:
2 实现通过点击连接,进入新的网页并显示value里的所有值
用到的点有:
1 url的正则匹配
2 通过url的数据定位某一个数据
views:
USER_INFO = {
'1': {'name':'shenyang','age':25,'mail':'123@qq.com'},
'2': {'name':'wang','age':18,'mail':'456@qq.com'},
'3': {'name':'xiaoming','age':19,'mail':'789@qq.com'},
'4': {'name':'xiaohua','age':11,'mail':'101112@qq.com'},
}
def list(request):
return render(request,'list.html',{'USER_INFO':USER_INFO})
def detail(request,nid):
detail_info = USER_INFO[nid]
return render(request,'details.html',{'detail_info':detail_info})
urls:
from user import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^user/', views.user),
url(r'^home/', views.Home.as_view()),
url(r'^moban/', views.moban),
url(r'^list/', views.list),
url(r'^detail-(?P<nid>d+).html', views.detail),
]
html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h2>详细信息</h2>
<div>
<h6>用户名:{{ detail_info.name }}</h6>
<h6>年龄:{{ detail_info.age }}</h6>
<h6>邮箱:{{ detail_info.mail }}</h6>
</div>
</body>
</html>
效果:

我们不仅可以通过url 获取一个数据,还能获取多个数据:
匹配规则:
匹配类似于 detail-1-2.html 这种两个数字的:

函数获取数据:

但是这样有一个不好的就是当url中这两个数字换了以后代码里的函数获取的数据也就不正确了,所以需要给匹配到的指定一个变量,这样就不再需要关心顺序了:

函数获取数据:
不管顺序,直接获取:
nid 就是nid uid 就是uid

这里很重要,总结一下:
路由系统,URL的三种方式:
1 直接匹配,不需要获取数据:

2 通过正则匹配,但是在函数获取数据时必须注意前后顺序:

3 通过正则匹配到后不需要关心顺序,但是url中需要指定变量名称:

url不仅可以匹配数字,还可以通过各种匹配,函数还可以以字典方式和列表方式获取数据:

例如函数中以字典方式获取数据:
views:
def dic_test(request,**kwargs):
print('This dic is: ',kwargs)
nid = kwargs['nid']
uid = kwargs['uid']
all = 'This is ' + nid + ' and ' + uid
return HttpResponse(all)
urls:
url(r'^dic_test-(?P<nid>d+)-(?P<uid>d+).html', views.dic_test),
html:
无
效果:

url 地址还可以给一个变量,用于在html 模板中跳转到指定变量的地址中:

当然如果想获取绝对的url地址,使用:

因为在模板渲染的时候响应函数已经把所有的request 传入,所以想获取哪个数据,只要request中有,就一定能获取到,并渲染到模板中
另一种方式自己跳转到自定义页面:
需要用到 reverse 模块:
例如:
把name 为 i2 的url 自定义一个url 通过列表形式转换为自定义url
urls:

viwes:
from django.urls import reverse
def custom_url_i2(request,*args,**kwargs):
print(request.path_info)
url2 = reverse('i2',args=(8,12))
print(url2)
return HttpResponse(url2)
效果:

把name 为 i3 的url 自定义一个url 通过字典形式转换为自定义url
urls:

viwes:
def custom_url_i3(request,*args,**kwargs):
print(request.path_info)
url3 = reverse('i3',kwargs={'uid':88,'nid':66})
print(url3)
return HttpResponse(url3)
效果:

总结一下:

当然上面这些是只有Django 才有的方式
路由系统中另一个强大的功能叫做路由分发系统:
详细来说就是通过指定一个url 到另一个url路由文件就可以实现多个项目与主路由的松耦合,这样开发者可以自己修改自己的项目的url地址而不会影响到其他项目:
实现:
项目主urls:

user模块urls:

user viwes:

host模块urls:

host viwes:

效果:

路由系统暂时到此。
开始ORM:
ORM分为两类:
Django中的为Codefirst

使用Django 创建一个用户表:
1 写类
from django.db import models
# Create your models here.
class User_info(models.Model):
username = models.CharField(max_length=32)
password = models.CharField(max_length=64)
2 修改setting 添加app

3 执行命令生成表
python manage.py makemigrations python manage.py migrate
4 检查

Django 创建表的时候表名为:
app名_表的类名

这里我们在没有做修改之前默认用的是SQLite数据库,使用mysql 数据库:

完整使用mysql 数据库的步骤:
1 修改项目的__init__.py 添加pymysql

2 修改setting 使用mysql 连接

3 在app中写一个类:

4 修改setting 注册app

5 执行命令生成表
manage.py makemigrations manage.py migrate
6 查看表:

配置完后学一下增删改查:
1 增加:
a方式:

b方式:

以字典形式增加数据:

2 查:
查所有:

过滤(where)查询:

这里也是一个列表,因为用户名称等于root的可能有多个,所以要通过列表循环获取数据
组合查询(and条件):

虽然查到了一个但是查到的结果类型还是一个列表,所以还要循环
3 删除:
过滤删除:

全部删除:
.all().delete()
4 更新:
全部更新:

过滤更新:

实践一下:
from host_manage import models
def orm(request):
# 增加
models.User_info.objects.create(username='root',password='123')
# 查看
result = models.User_info.objects.all()
for row in result:
print(row.id,row.username,row.password)
#删除
models.User_info.objects.filter(username='alex').delete()
#更新
models.User_info.objects.filter(id=2).update(password='66666')
return HttpResponse('orm')


实现查询的时候只拿取第一个,并返回一个对象:
first() 方法:

这样查找之后就会取过滤后的第一个对象,这里可以判断如果对象存在就说明有数据,如果为None 则数据不存在
也可以用下面的计数查询,如果大于0说明有数据,但是不能获取到多个信息,不常用:

还有一种获取对象的方式,但是不推荐,需要配合try来使用:

查看真实的sql 语句,就是在操作对象时执行的sql:

写一个列出和添加用户的小功能:
1 views
from user import models
def user_info(request):
if request.method == 'GET':
user_list = models.UserInfo.objects.all()
print(user_list)
return render(request,'user_info.html',{'user_list':user_list})
elif request.method == 'POST':
u = request.POST.get('user')
p = request.POST.get('pwd')
print(u,p)
models.UserInfo.objects.create(username=u,password=p)
return redirect('/user/user_info/')
2 models
from django.db import models
# Create your models here.
class UserInfo(models.Model):
username = models.CharField(max_length=32)
password = models.CharField(max_length=64)
3 urls
from django.conf.urls import url
from user import views
urlpatterns = [
url(r'^login/',views.login),
url(r'^list/',views.list),
url(r'^user_info/',views.user_info),
]
4 html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/user/user_info/" method="POST">
<h2>用户列表</h2>
<ul>
{% for i in user_list %}
<li>{{ i.username }}</li>
{% endfor %}
</ul>
<input type="text" name="user" placeholder="用户名" /></div>
<div><input type="password" name="pwd" placeholder="密码" /></div>
<input type="submit" value="添加用户"/>
</form>
</body>
</html>
5 效果

继续添加点击用户名可以查看详细信息功能:
使用url 的正则匹配形式:
1 views
from user import models
def user_info(request):
if request.method == 'GET':
user_list = models.UserInfo.objects.all()
print(user_list)
return render(request,'user_info.html',{'user_list':user_list})
elif request.method == 'POST':
u = request.POST.get('user')
p = request.POST.get('pwd')
print(u,p)
models.UserInfo.objects.create(username=u,password=p)
return redirect('/user/user_info/')
def user_detail(request,nid):
print(nid)
user_info = models.UserInfo.objects.filter(id=nid).first()
return render(request,'userdetail.html',{'user_info':user_info})
2 urls
from django.conf.urls import url
from user import views
urlpatterns = [
url(r'^login/',views.login),
url(r'^list/',views.list),
url(r'^user_info/',views.user_info),
url(r'^userdetail-(?P<nid>d+).html/',views.user_detail),
]
3 html
userinfo
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/user/user_info/" method="POST">
<h2>用户列表</h2>
<ul>
{% for i in user_list %}
<li>{{ i.username }} <a href="/user/userdetail-{{ i.id }}.html">详细</a></li>
{% endfor %}
</ul>
<input type="text" name="user" placeholder="用户名" /></div>
<div><input type="password" name="pwd" placeholder="密码" /></div>
<input type="submit" value="添加用户"/>
</form>
</body>
</html>
userdetail
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<ul>
<li>{{ user_info.username }} -- {{ user_info.password }}</li>
</ul>
</body>
</html>
4 效果

最后添加删除和编辑功能:
1 删除:
最简单,根据id直接操作数据库然后返回到用户列表页即可
2 修改:
返回指定id的数据到input 框,当修改后根据id提交
views:
from user import models
def user_info(request):
if request.method == 'GET':
user_list = models.UserInfo.objects.all()
print(user_list)
return render(request,'user_info.html',{'user_list':user_list})
elif request.method == 'POST':
u = request.POST.get('user')
p = request.POST.get('pwd')
print(u,p)
models.UserInfo.objects.create(username=u,password=p)
return redirect('/user/user_info/')
def user_detail(request,nid):
print(nid)
user_info = models.UserInfo.objects.filter(id=nid).first()
return render(request,'userdetail.html',{'user_info':user_info})
def user_del(request,nid):
print(nid)
models.UserInfo.objects.filter(id=nid).delete()
return redirect('/user/user_info/')
def user_edit(request,nid):
print(nid)
if request.method =='GET':
user = models.UserInfo.objects.filter(id=nid).first()
return render(request,'useredit.html',{'user':user})
elif request.method == 'POST':
u = request.POST.get('username')
p = request.POST.get('password')
print(u,p)
models.UserInfo.objects.filter(id=nid).update(username=u,password=p)
return redirect('/user/user_info/')
urls:
from django.conf.urls import url
from user import views
urlpatterns = [
url(r'^login/',views.login),
url(r'^list/',views.list),
url(r'^user_info/',views.user_info),
url(r'^userdetail-(?P<nid>d+).html/',views.user_detail),
url(r'^userdel-(?P<nid>d+).html/',views.user_del),
url(r'^useredit-(?P<nid>d+).html/',views.user_edit),
]
html:
userinfo:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/user/user_info/" method="POST">
<h2>用户列表</h2>
<ul>
{% for i in user_list %}
<li>{{ i.username }} <a href="/user/userdetail-{{ i.id }}.html">详细|</a><a href="/user/userdel-{{ i.id }}.html">删除|</a><a href="/user/useredit-{{ i.id }}.html">编辑</a></li>
{% endfor %}
</ul>
<input type="text" name="user" placeholder="用户名" /></div>
<div><input type="password" name="pwd" placeholder="密码" /></div>
<input type="submit" value="添加用户"/>
</form>
</body>
</html>
useredit:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h2>修改用户信息</h2>
<form action="/user/useredit-{{ user.id }}.html/" method="POST">
<input type="text" name="nid" value="{{ user.id }}" style="display: none"/>
<input type="text" name="username" value="{{ user.username }}"/>
<input type="text" name="password" value="{{ user.password }}"/>
<input type="submit" value="提交修改"/>
</form>
</body>
</html>
效果:

基本的增删改查就到这里,下面说一下增加列和删除列:
通过Django 的ORM 操作数据库其实很简单:
增加列:
1直接在class中增加一个属性就行

2 执行命令,生成表结构:

删除列:
1 直接注释掉需要删除的列
2 执行命令删除

Django 中的ORM 有很多的数据类型,但是其本质也就是数据库那几种类型,只是Django 会帮你做一层验证:


数据表的一些其他操作:

指定列名:

建立索引:

建立唯一索引:

注册时间,创建时间,可是使用这个:


下面这种才会更新:

创建一个choices 类型的表:

Django 的admin 会自动当作选项:

存入数据库的还是数字,避免了连表查询

总结一下字段的参数:

Django admin 显示字段中文:

自定义帮助信息,在旁边坐一个小的提示:


admin 的其他一些方法:




实际上在数据库中会生成 user_group_id 这个表
通过这个关联键 获取数据:

创建一个值:

直接写入本地数据库而不是跨表写入
动态的下拉框:


实践:
添加一个在创建用户的时候指定组的功能,下拉框中的数据来自另一个表的数据,存储的时候直接存储到本表。
先实现展示的功能:
models:
创建关联的外键:
from django.db import models
# Create your models here.
class UserGroup(models.Model):
uid = models.AutoField(primary_key=True)
caption = models.CharField(max_length=32,unique=True)
ctime = models.DateTimeField(auto_now_add=True,null=True)
uptime = models.DateTimeField(auto_now=True,null=True)
class UserInfo(models.Model):
username = models.CharField(max_length=32)
password = models.CharField(max_length=64)
user_group = models.ForeignKey('UserGroup',to_field='uid')
插入几条数据,重新刷新一下数据库,发现 userinfo表里增加了一个 user_group_uid 的列,而不是user_group,这是因为外键关联的是一个对象,而不是真正的列


views:
处理数据,在获取组的时候使用外键的方式:
from user import models
def user_info(request):
if request.method == 'GET':
user_list = models.UserInfo.objects.all()
group_list = models.UserGroup.objects.all()
print(user_list)
return render(request,'user_info.html',{'user_list':user_list,'group_list':group_list})
elif request.method == 'POST':
u = request.POST.get('user')
p = request.POST.get('pwd')
g = request.POST.get('group')
print(u,p,g)
models.UserInfo.objects.create(username=u,password=p,user_group_id=g)
return redirect('/user/user_info/')
def user_detail(request,nid):
print(nid)
user_info = models.UserInfo.objects.filter(id=nid).first()
return render(request,'userdetail.html',{'user_info':user_info})
html:
info:
以点的方式继续操作另一张表
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/user/user_info/" method="POST">
<h2>用户列表</h2>
<ul>
<li> 用户名 -- 组</li>
{% for i in user_list %}
<li>{{ i.username }} -- {{ i.user_group.caption }} <a href="/user/userdetail-{{ i.id }}.html">详细|</a><a href="/user/userdel-{{ i.id }}.html">删除|</a><a href="/user/useredit-{{ i.id }}.html">编辑</a></li>
{% endfor %}
</ul>
<input type="text" name="user" placeholder="用户名" /></div>
<div><input type="password" name="pwd" placeholder="密码" /></div>
<div><select name="group" >
{% for g in group_list %}
<option value="{{ g.uid }}">{{ g.caption }}</option>
{% endfor %}
</select>
</div>
<input type="submit" value="添加用户"/>
</form>
</body>
</html>
detail:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<ul>
<li> 用户名 -- 密码 -- 组</li>
<li>{{ user_info.username }} -- {{ user_info.password }} -- {{ user_info.user_group.caption }}</li>
</ul>
</body>
</html>
效果:
