day19 Dgango进阶 路由系统及 ORM 详解

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

再次回顾一下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分为两类:

1  DBfirst      先创建数据库表结构  根据表结构自动生成类, 以后修改这个类就可以修改数据库
2  Codefirst   先写代码,写好要创建的数据库的表的类,然后自动生成表结构

 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 查:

  查所有:

   

    查到一个QuerySet 的格式的数据,直接理解为是一个列表。
    列表中每一个元素都是一个对象

 过滤(where)查询:

   

   这里也是一个列表,因为用户名称等于root的可能有多个,所以要通过列表循环获取数据

 组合查询(and条件):

   

   虽然查到了一个但是查到的结果类型还是一个列表,所以还要循环

删除:

  过滤删除:

  

  全部删除:

   .all().delete()

更新:

  全部更新:

  

  过滤更新:

  

实践一下:

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>

效果:

 

原文地址:https://www.cnblogs.com/yangever/p/6188023.html