通过上节课的学习,我们已经对Django有了简单的了解,现在来深入了解下~

1.1 单一路由对应

url(r'^index$', views.index),

1.2 基于正则的路由

url(r'^index/(\d*)', views.index),
url(r'^manage/(?P<name>\w*)/(?P<id>\d*)', views.manage),
  • 找到urls.py文件,修改路由规则
from django.conf.urls import url,include
from django.contrib import admin
from cmdb import views
 
urlpatterns = [
    url(r'^index', views.index),
    url(r'^detail-(\d+).html/', views.detail),
]
  • 在views.py文件创建对应方法
USER_DICT = {
    '1':{'name':'root1','email':'root@live.com'},
    '2':{'name':'root2','email':'root@live.com'},
    '3':{'name':'root3','email':'root@live.com'},
    '4':{'name':'root4','email':'root@live.com'},
}
 
def index(request):
    return render(request,"index.html",{"user_dict":USER_DICT})
 
def detail(request,nid):  # nid指定的是(\d+)里的内容
    detail_info = USER_DICT[nid]
    return render(request, "detail.html", {"detail_info": detail_info})

1.3 url分组

在url.py增加对应路径

from django.conf.urls import url,include
from django.contrib import admin
from cmdb import views
 
urlpatterns = [
    url(r'^index', views.index),
    url(r'^detail-(?P<nid>\d+)-(?P<uid>\d+).html/', views.detail),<br>   # nid=\d+ uid=\d+
]

在views.py文件创建对应方法

def detail(request,**kwargs):
    print(kwargs)          
    #{'nid': '4', 'uid': '3'}
    nid = kwargs.get("nid")
    detail_info = USER_DICT[nid]
    return render(request, "detail.html", {"detail_info": detail_info})

1.4 为路由映射名称

from django.conf.urls import url,include
from django.contrib import admin
from cmdb import views
 
urlpatterns = [
    url(r'^asdfasdfasdf/', views.index, name='i1'),     #第一种方式i1
    url(r'^yug/(\d+)/(\d+)/', views.index, name='i2'),  #第二种方式i2
    url(r'^buy/(?P<pid>\d+)/(?P<nid>\d+)/', views.index, name='i3'),    #第三种方式i3
]

在templates目录下的index.html

<body>
{#第一种方法i1       路径asdfasdfasdf/#}
{#<form action="{% url "i1" %}" method="post">#}
{#第二种方法i2       路径yug/1/2/#}
{#<form action="{% url "i2" 1 2 %}" method="post">#}
{#第三种方法i3       路径buy/1/9//#}
<form action="{% url "i3" pid=1 nid=9 %}" method="post">
    <p><input  name="user" type="text" placeholder="用户名"/></p>
    <p><input  name="password" type="password" placeholder="密码"/></p>
    <p><input type="submit" value="提交"/></p>
</form>
</body>

1.5 根据app对路由分类

主程序urls.py文件

from django.conf.urls import url,include
from django.contrib import admin
 
urlpatterns = [
    url(r'^monitor/', include('monitor.urls')), #调整到monitor目录中的urls.py文件
]

cmdb下的url.py文件

from django.conf.urls import url
from django.contrib import admin
from monitor import views
#
urlpatterns = [
    url(r'^login', views.login),
]

1.6 获取当前URL

view.py中配置

def index(request):
    print(request.path_info)    #获取客户端当前的访问链接
    # / index
    return render(request,"index.html",{"user_dict":USER_DICT})

在templates目录下的index.html文件

<form action="{{ request.path_info }}" method="post">
    <p><input  name="user" type="text" placeholder="用户名"/></p>
    <p><input  name="password" type="password" placeholder="密码"/></p>
    <p><input type="submit" value="提交"/></p>
</form>

1.7 默认值

在url.py增加对应路径

from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
    url(r'^index/',views.index,{"name":"root"}),
]

在views.py文件创建对应方法

from django.shortcuts import render,HttpResponse
def index(request,name):
    return HttpResponse("%s is ok"%name)

运行并访问http://127.0.0.1:8000/index,页面显示:root is ok

1.8 命名空间

不同的url指向同一个视图就需要借助命名空间

主程序url.py文件

from django.conf.urls import url,include
 
urlpatterns = [
    url(r'^a/', include('app01.urls', namespace='author-polls')),
    url(r'^b/', include('app01.urls', namespace='publisher-polls')),
]

app01下的urls.py文件

from django.conf.urls import url
from app01 import views
 
app_name = 'app01'
urlpatterns = [
    url(r'^index/$', views.detail, name='detail')
]

在views.py文件创建对应方法

from django.shortcuts import render,HttpResponse
def index(request):
    return HttpResponse("ok")

访问http://127.0.0.1:8000/a/index,页面显示"ok"

以上定义带命名空间的url之后,使用name生成URL时候,应该如下:

  • v = reverse('author-polls:detail')
  • {% url 'author-polls:detail'%}

2. 视图

2.1 获取用户请求数据

request.GET

request.POST

request.FILES 

其中,GET一般用于获取/查询 资源信息,而POST一般用于更新 资源信息 ; FILES用来获取上传文件;

2.2 checkbox等多选的内容

在templates目录下创建login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/login" method="POST" >
        <p>
            男:<input type="checkbox"  name="favor" value="11"/>
            女:<input type="checkbox" name="favor" value="22"/>
            人妖:<input type="checkbox" name="favor" value="33"/>
        </p>
        <input type="submit" value="提交"/>
    </form>
</body>
</html>

修改views.py文件对表单处理

def login(request):
    #checkbox  多选框
    if request.method == "POST":
        favor_list = request.POST.getlist("favor")      #getlist获取多个值
        print(favor_list)           #多选框获取到的是列表格式
        #['11', '22', '33']
        return render(request,"login.html")
    elif request.method == "GET":
        return render(request,"login.html")
    else:
        print("other")

2.3 上传文件

文件对象 = reqeust.FILES.get()
文件对象.name
文件对象.size
文件对象.chunks()

在templates目录下创建login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form action="/login" method="POST" enctype="multipart/form-data">
        <p>
            <input type="file" name="files"/>
        </p>
        <input type="submit" value="提交"/>
    </form>
</body>
</html>

修改views.py文件对表单处理

def login(request):
    #file 上传文件
    if request.method == "POST":
        obj = request.FILES.get('files')       #用files获取文件对象
        if obj:
            print(obj, type(obj), obj.name)
            # test.jpg <class 'django.core.files.uploadedfile.InMemoryUploadedFile'> test.jpg
            import os
            file_path = os.path.join('upload', obj.name)
            f = open(file_path, "wb")
            for item in obj.chunks():      #chunks表示所有的数据块,是个迭代器
                f.write(item)
            f.close()
        return render(request,"login.html")
    elif request.method == "GET":
        return render(request,"login.html")
    else:
        print("other")

2.4 请求的其他信息

from django.core.handlers.wsgi import WSGIRequest
request.environ #获取所有用户请求信息
request.environ['HTTP_USER_AGENT'] #获取用户请求的设备信息

2.5 FBV & CBV

2.5.1 FBV

1.在templates目录下创建home.html文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="/home/" method="POST">
    <p>
        <input type="text" name="user" placeholder="用户名"/>
    </p>
    <p>
        <input type="password" name="pwd" placeholder="密码"/>
    </p>
    <p>
        <input type="submit" value="提交">
    </p>
</form>
</body>
</html>

2. 在urls.py文件增加home路径

from django.conf.urls import url,include
from django.contrib import admin
from cmdb import views
 
urlpatterns = [
     # 固定语法
    url(r'^home/', views.Home.as_view()),
]

3. 在views.py文件创建函数Home

def home(request):
        return render(request,"home.html")

2.5.2 CBV

1. 在templates目录下创建home.html文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="/home/" method="POST">
    <p>
        <input type="text" name="user" placeholder="用户名"/>
    </p>
    <p>
        <input type="password" name="pwd" placeholder="密码"/>
    </p>
    <p>
        <input type="submit" value="提交">
    </p>
</form>
</body>
</html>

2. 在urls.py文件增加home路径

from django.conf.urls import url,include
from django.contrib import admin
from cmdb import views
 
urlpatterns = [
     # 固定语法
    url(r'^home/', views.Home.as_view()),
]

3. 在views.py文件创建类Home

from django.views import View
 
class Home(View):
    # 先执行dispatch里面的内容
    def dispatch(self,request, *args, **kwargs):
        print("before")
        # 调用父类中的dispatch
        result = super(Home,self).dispatch(request, *args, **kwargs)
        print("after")
        return result
 
    # 根据反射获取用户提交方式,执行get或post方法
    def get(self,request):
        print(request.method)
        return render(request,"home.html")
 
    def post(self,request):
        print(request.method)
        return render(request,"home.html")

3. Templates

  通过之前的学习我们已经可以实现模板功能,但是大家会发现一个问题:按照之前学习的方法,同一个系统下的不同功能页面,我们需要在每个页面复制菜单、左侧右侧导航等;这样虽然也可以实现我们的需求,但是如果菜单、左右侧导航有所修改,我们就需要再挨个去变更。那么有没有其他的方法解决这个问题呢?----这里我们引入母版。

3.1 继承

首先,我们需要新建一个母版html文件(如:master.html),文件内容如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %}{% endblock %}</title>
    <style>
        .pg_header{
            height: 50px;
            background-color: aquamarine;
            color:green;
        }
    </style>
</head>
<body>
    <div class="pg_header">母版测试</div>
    {% block content %}{% endblock %} 
</body>
</html>

再新建一个子板html文件(如:userlist.html),文件内容如下:

{% extends 'master.html' %} <!--有多个母版时,此处可区分继承的是哪个母版-->
{% block title %}用户管理{% endblock %} 
{% block content %}
    <h1>用户管理</h1>
    <ul>
        {% for i in u %}
            <li>{{ i }}</li>
        {% endfor %}
    </ul>
{% endblock %}

运行后查看页面,userlist.html继承了母版master.html的CSS和JS。(想要修改导航、菜单等内容,直接修改母版内容即可。)

学习完上面的东西之后,大家很快就会发现另外一个问题:上面的东西虽然能实现我们的需求,但是每个页面想要使用自己的CSS和JS就不行了,如何解决这个问题呢?

1.母版文件内容

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %}{% endblock %}</title>
    <style>
        .pg_header{
            height: 50px;
            background-color: aquamarine;
            color:green;
        }
    </style>
    {% block css %}{%endblock%}
</head>
<body>
    <div class="pg_header">母版测试</div>
    {% block content %}{% endblock %} 
    <script src="XXX"></script>
     {% block js %}{%endblock%}   
</body>
</html>

2. 子板文件内容

{% extends 'master.html' %} <!--有多个母版时,此处可区分继承的是哪个母版-->
{% block title %}用户管理{% endblock %} 
{% block content %}
    <h1>用户管理</h1>
    <ul>
        {% for i in u %}
            <li>{{ i }}</li>
        {% endfor %}
    </ul>
{% endblock %}
{% block css%}
    <style>
        .body{
            color:red
        }
    </style>
{% endblock%}
{% block js%}
    <script>.....</script>
{% endblock%}

PS:一个html文件只能继承一个母版

3.2 导入

新建tag.html文件, 文件内容如下:

<form>
    <input type="text"/>
    <input type="submit"/>
</form>

子板文件中插入代码

<% include "tag.html" %>
<% include "tag.html" %>
<% include "tag.html" %>
<% include "tag.html" %>

3.3 自定义simple_tag

  1. 在app中创建templatetags模块

  2. 创建任意 .py 文件,如:xx.py
    #!/usr/bin/env python
    #coding:utf-8
    from django import template
    from django.utils.safestring import mark_safe
       
    register = template.Library()
       
    @register.simple_tag
    def my_simple_time(v1,v2,v3):
        return  v1 + v2 + v3
       
    @register.simple_tag
    def my_input(id,arg):
        result = "<input type='text' id='%s' class='%s' />" %(id,arg,)
        return mark_safe(result)
  3. 在使用自定义simple_tag的html文件顶部导入之前创建的 xx.py 文件名

    {% load xx %}
  4. 使用simple_tag
    {% 函数名 arg1 arg2 %}
    {% my_simple_time 1 2 3%}
    {% my_input 'id_username' 'hide'%}
  5. 在settings中配置当前app,不然django无法找到自定义的simple_tag
    INSTALLED_APPS = (
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'app01',
    )

3.4 自定义filter

  1. 在app中创建templatetags模块

  2. 创建任意 .py 文件,如:xx.py

    #!/usr/bin/env python
    #coding:utf-8
    from django import template
    from django.utils.safestring import mark_safe
       
    register = template.Library()
       
    @register.filter
    def my_simple_time(v1,v2):
        return  v1 + v2 
       
    @register.filter
    def my_input(id,arg):
        result = "<input type='text' id='%s' class='%s' />" %(id,arg,)
        return mark_safe(result)
  3. 在使用自定义filter的html文件顶部导入之前创建的 xx.py 文件名

    {% load xx %}
  4. 使用filter
    {{ 参数1|函数名:"参数二,参数三" }} {{ 参数1|函数名:数字 }}
  5. 在settings中配置当前app,不然django无法找到自定义的simple_tag

    INSTALLED_APPS = (
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'app01',
    )
    

filter和simple_tag的优缺点:

  • simple_tag不能作为if条件;但可使用任意参数;
  • filter可以作为if条件;但最多两个参数,不能加空格;

4. 分页

4.1 django内置分页

Paginator

4.2 自定义分页

分页功能在每个网站都是必要的,对于分页来说,其实就是根据用户的输入计算出应该在数据库表中的起始位置。

4.2.1 准备基础数据

1. 在url.py增加对应路径

from django.conf.urls import url,include
from django.contrib import admin
from cmdb import views
  
urlpatterns = [
    url(r'^index', views.index),
    url(r'^userlist/', views.userlist),
]

2. 在views.py文件创建对应方法

from django.shortcuts import render,HttpResponse
LIST=[]
for i in range(109):
    LIST.append(i)
def user_list(request):
    return render(request,'userlist.html',{'li':LIST})

3. 在templates目录下的userlist.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <ul>
        {% for item in li %}
            <li>{{ item }}</li>
        {% endfor %}
    </ul>
</body>
</html>

运行程序并访问http://127.0.0.1:8000/userlist/,我们会发现该页面直接显示所有数据;

4.2.2 实现简单分页

我们可以考虑在url后带上参数表名用户访问的是第几页,从而返回数据;

views.py文件更改:

def userlist(request):
    current_page = request.GET.get('p',1)
    current_page = int(current_page)
    start = (current_page-1)*10
    end = current_page*10
    data = LIST[start:end]
    return render(request,'userlist.html',{'li':data})

重新运行程序后访问http://127.0.0.1:8000/userlist/?p=2,我们就可以看到第二页的数据了

4.2.3 简单优化

上面虽然可以实现简单分页,但是考虑到用户体验,肯定不能让用户如此访问,我们需要简单优化下:

html文件更改:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <ul>
        {% for item in li %}
            <li>{{ item }}</li>
        {% endfor %}
    </ul>
    <div>
        <a href="user_list/?p=1">1</a>
        <a href="user_list/?p=2">2</a>
        <a href="user_list/?p=3">3</a>
    </div>
</body>
</html>

重新运行程序后访问http://127.0.0.1:8000/userlist/,点击页面的1、2即可实现简单翻页功能;

4.2.4 最终分页实现

现在新的分页需求下来了:

1)每页10条;

2)停留在第一页的时候,上一页不可点击;停留在末页的时候,下一页不可点击;

3)当前页面被默认选中且颜色高亮显示;

4)只显示当前页、前3个页码和后3个页码;

头疼Ing,继续苦逼的写代码吧!

app的同级目录下新建utils目录,目录下新建pagination.py文件,文件内容如下:

from django.utils.safestring import mark_safe
class Page:
    def __init__(self,current_page,data_count,per_page_count=10,pager_num=7):
        self.current_page = current_page
        self.data_count = data_count
        self.per_page_count = per_page_count
        self.pager_num = pager_num
    @property
    def start(self):
        return (self.current_page-1) * self.per_page_count
    @property
    def end(self):
        return self.current_page * self.per_page_count
    @property
    def total_count(self):
        v,y = divmod(self.data_count, self.per_page_count)
        if y:
            v += 1
        return v
    def page_str(self, base_url):
        page_list = []
        if self.total_count < self.pager_num:
            start_index = 1
            end_index = self.total_count + 1
        else:
            if self.current_page <= (self.pager_num+1)/2:
                start_index = 1
                end_index = self.pager_num + 1
            else:
                start_index = self.current_page - (self.pager_num-1)/2
                end_index = self.current_page + (self.pager_num+1)/2
                if (self.current_page + (self.pager_num-1)/2) > self.total_count:
                    end_index = self.total_count + 1
                    start_index = self.total_count - self.pager_num + 1
        if self.current_page == 1:
            prev = '<a class="page" href="javascript:void(0);">上一页</a>'
        else:
            prev = '<a class="page" href="%s?p=%s">上一页</a>' %(base_url,self.current_page-1,)
        page_list.append(prev)
        for i in range(int(start_index),int(end_index)):
            if i ==self.current_page:
                temp = '<a class="page active" href="%s?p=%s">%s</a>' %(base_url,i,i)
            else:
                temp = '<a class="page" href="%s?p=%s">%s</a>' %(base_url,i,i)
            page_list.append(temp)
        if self.current_page == self.total_count:
            nex = '<a class="page" href="javascript:void(0);">下一页</a>'
        else:
            nex = '<a class="page" href="%s?p=%s">下一页</a>' %(base_url,self.current_page+1,)
        page_list.append(nex)
        jump = """
        <input type='text'  /><a onclick='jumpTo(this, "%s?p=");'>GO</a>
        <script>
            function jumpTo(ths,base){
                var val = ths.previousSibling.value;
                location.href = base + val;
            }
        </script>
        """ %(base_url,)
        page_list.append(jump)
        page_str = mark_safe("".join(page_list))
        return page_str
pagination.py

相关文章: