完成一个完整的网页服务,需要有以下:
再次回顾一下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>
效果: