Django学习记录

一、项目创建

1、使用pycharm创建Django项目

 

 会创建一个跟项目同名的app,在该app中可以设置整个项目主路由、配置信息等

 

 2、在pycharm 终端使用python3 manage.py 操作django项目。如 python3 manage.py runserver启动django项目(截图中的提示表示没有同步数据库信息)

 

二、URL

Django处理URL请求

浏览器地址栏 -> http://127.0.0.1:8000/admin

1、Django 从配置文件中根据ROOT_URLCONF找到主路由文件;默认情况下,该文件是项目同名app下的urls.py

2、Django 加载主路由文件中的urlpatterns变量(包含很多路由的数组)

3、依次匹配urlpatterns中的path,若匹配到第一个合适的路劲,则会中断后续匹配

4、匹配成功->调用对应的师徒函数处理请求,返回响应

5、匹配失败-> 返回404

主路由 urls.py 示例
from django.contrib import admin
from django.urls import path

urlpatterns = [
    path('admin/', admin.site.urls),
]

  

三、视图函数 

定义:视图函数是用于接收一个浏览器请求(httprequest对象)并通过httpresponse对象返回响应的函数。

语法:

def xxx_view(request):
    pass
    return HttpResponse对象

ps:第一个参数必须是request
返回值必须是HttpResponse对象

示例:

1、在与项目同名的app下新建urls.py文件

2、创建视图函数 page_1_view

from django.http import HttpResponse

def
page_1_view(request): html = "<h1>test1</h1>" return HttpResponse(html)

3、在主路由中添加路径及对应视图函数

from django.urls import path
from . import views # 在当前目录引用

urlpatterns = [
    path('admin/', admin.site.urls),
    path('page/1', views.page_1_view) #配置路由和视图函数
]

 

 

 path函数详解:

1、导入  from django.urls import path

2、语法 path(route, views, name=None)

3、参数 route: 字符串类型,匹配请求的路径。

            views:指定路径对应的视图处理函数名称。(views不能添加括号,添加括号之后就是将函数的结果引用过来了,两者完全不同

    name:为地址起的别名,在模板中地址反向解析时使用

 

四、path转换器 

语法: <转换器类型:自定义名称>

作用:若转换器类型匹配到对应类型的数据,则将数据按照关键字传参的方式传给视图函数

例:   path('update/<int:note_id>', views.update_note)

转换器类型及作用:

转换器类型 作用 示例

str

匹配除'/'之外的非空字符串 'user/<str:username>'匹配'user/wx'
int 匹配0或者任何整数,返回一个int 'page/<int:page>'匹配'page/1'
slug 匹配任意由ascll字母或数字以及连字符和下划线组成的短标签 'detail/<slug:sl>'匹配'detail/test-django'
path 匹配非空字段,包括路径分隔符'/' 'test/<path:pa>'匹配'test/a/b/c'

示例:

views.py
def page_view(request):
      html = f"这是编号为{str(pg)}"的页面
      return HttpResponse(html)
  
urls.py

path('page/<int:pg>', views.page_view)

 

 ps: urls.py中的urlpatterns按从上往下的顺序匹配

五、re_path()

定义:在url的匹配中可以使用正则表达式进行精确匹配

语法:re_path(reg, view, name=xxx)

         正则表达式为命名分组模式(?P<name>pattern); 匹配提取参数后用关键字传参方式传递给视图函数

示例:

from django.urls import path, re_path

urlpatterns = [
    path('admin/', admin.site.urls),
    re_path(r'^(?P<x>\d{1,2})/(?P<y>\w+)/(?P<z>\d{1,2})$', views.page_view())
]
^ 代表开头
& 代表结束
P 代表正则匹配
<x> 代表我们给他命名为x
\d 匹配数字
{1,2} 匹配1-2位
\w+ 匹配字符串

六、请求和响应

Django主要做的是网页,而请求和响应是网页十分重要的东西。

请求:指浏览器通过http协议发送给服务端的数据

响应:指服务收到请求后做出响应处理后再回复给浏览器的数据。

 

请求方式:

1、根据http标准,http请求可以使用多种请求方法。

2、http1.0定义了三种请求方发:get、post、head(最常用)。

3、http1.1新增了五种请求方法:options、put、delete、trace、connect。

序号 方法 描述
1 GET 请求指定的页面信息,并返回实体主体
2 HEAD 类似于get方法,只是返回的数据中没有具体的内容,用于获取报头
3 POST 向指定资源提交数据进行处理请求(例如提交表单或上传文件),数据被包含在请求中,post请求可能导致新的资源建立或已有的资源修改
4 PUT 从客户端向服务端传送的数据取代指定的文档中的内容
5 DELETE 请求服务器删除指定的页面
6 CONNECT http1.1协议中预留给能够将连接改为管道方式的代理服务器
7 OPTIONS 允许客户端查看服务器的性能
8 TRACE 回显服务器收到的请求,主要用于测试或诊断

 

Django中的请求:

1、请求在Django中是视图函数的第一个参数,即HttpRequest对象。

2、Django接收到http协议的请求后,会根据请求数据报文创建HttpRequest对象。

3、HttpRequest对象通过属性描述了请求的所有相关信息。

 

Django中请求的属性:

1、path_info:URL字符串。

2、method:标识http请求的方法。

3、GET:QueryDict查询字典的对象,包含get请求方法的所有数据。

4、POST:QueryDict查询字典的对象,包含post请求方法的所有数据。

5、FILES:类似于字典的对象,包含所有上传的文件信息。

6、COOKIES:python字典,包含所有的cookie,key和value都是字符串。

7、session:类似字典的对象,表示当前的会话。

8、body:字符串,请求体的内容。

9、scheme:请求协议(http/https).

10、get_full_path():请求的完整路径。

11、META:请求中的元数据。 META['EMOTE_ADDR']:客户端IP地址。

 

 

响应状态码:

200 请求成功
301 永久重定向
302 临时重定向
404 请求的资源不存在
500 服务器错误

响应状态码分类:

HTTP状态码由三位十进制数字组成,第一个十进制数字定义了状态码的类型,后两个数字没有分类的作用。

分类 分类描述
1** 信息。服务器收到信息,需要请求者继续执行操作
2** 成功。操作被成功接受并处理
3** 重定向。需要进一步的操作以完成请求
4** 客户端错误。请求包含语法错误或无法完成的请求
5** 服务端错误。服务端在处理请求的过程中发生错误

 

Django响应:

  构造函数格式:

  HttpResponse(content=响应体,content_type=响应体数据类型,status=状态码) 

  作用:

  向浏览器返回响应,同时携带响应体内容

 

常用的Content-Type:

'text/html' 默认的,html文件
'text/plain' 纯文本
'text/css' css文件
'text/javascript' js文件
'multipart/rom-data' 文件提交
'application/json' json传输
'application/xml' xml文件

 

 HttpResponse子类:

类型

作用 状态码

HttpResponseRedirect

重定向 302
HttpResponseNotModified 未修改 304
HttpResponseBadRequest 错误请求 400
HttpResponseNotFound 没有对应的资源 404
HttpResponseForbidden 请求被禁止 403
HttpResponseServerError 服务器错误 500

 

 

七、GET和POST请求

GET和POST请求:

  无论是GET还是POST,统一由视图函数接收请求,通过request.methed区分具体的请求操作。

示例:

def test_get_post(request):
    
    if request.method == 'GET':
        pass
    elif request.method == 'POST':
        pass
    else:
        pass
    return HttpResponse('--test get post is ok--')

 

GET处理:

1、GET请求动作,一般用于向服务器获取数据

2、能够产生GET请求的场景:

  -浏览器地址栏中输入URL后,回车

  -<a href='地址?参数=值&参数=值'>

  -form表单中的methed为get

3、GET请求中如果有数据需要传递给服务器,通常会用查询字符串(Query String)传递。【不要传递敏感数据】

  -URL格式:xxx?参数名1=值1&参数名2=值2

  -如:http://127.0.0.1/page?a=1&b=2

  -服务端接收参数。获取客户端GET请求的数据

方法示例:
request.GET['参数名']  #QueryDict
request.GET.get('参数名','默认值')
request.GET.getlist('参数名')

views.py

def test_get_post(request):
    if request.method == 'GET':
        print(request.GET['a'])
        print(request.GET.get('c', 'no c'))
        print(request.GET.getlist('a'))
    elif request.method == 'POST':
        pass
    else:
        pass
    return HttpResponse('--test get post is ok--')

urls.py
path('test_get_post',views.test_get_post),

 

 

POST处理:

1、post请求动作,一般用于向服务器提交大量/隐私数据

2、客户端通过表单等POST请求将数据传递给服务器,如:

<form methed='post' action="/login">
    姓名: <input type="text" name="username">
    <input type="submit" value="登录">
</form> 

3、服务端接收参数:

  -通过request.methed来判断是否为post请求,如:

if request.methed =='POST':
    处理post请求的数据并响应
else:
    处理非post请求

4、取消csrf验证,否则Django会拒绝服务端发来的POST请求,返回403

5、使用POST方法接收客户端数据 

request.POST['参数名'] #QueryDict
request.POST.get('参数名', '')
request.POST.getlist('参数名')

八、Django设计模式及模板层

MTV

MTV代表Model-Template-View(模型-模板-视图) 

M 模型层(Model): 负责与数据库交互

T 模板层(Template):  负责呈现内容到浏览器(HOW)

V 视图层(View):  负责接收请求、获取数据、返回结果(WHAT)

 

模板层

1、定义

  模板是可以根据字典数据动态变化的html网页

  模板可以根据视图中传递的字典数据动态生成相应的html网页

2、模板配置

 创建模板文件夹 <项目名>/templates

 在settings.py中TEMPLATES配置项

  BACKEND: 指定模板的引擎

  DIRS: 模板的搜索目录(可以是一个也可以是多个)

  APP_DIRS: 是否要在应用的templates文件夹中搜索模板文件

  OPTIONS: 有关模板的选项

 

 

 3、模板的加载方式

方式一:通过loader获取模板,通过HttpResponse进行响应

在视图函数中:

from django.template import loader
# 1、通过loader加载模板
t = loader.get_template('模板文件名')
# 2、将t转换成HTML字符串
html = t.render('字典数据')
# 3、用响应对象将返回的字符串内容返回给浏览器
return HttpResponse(html)

views.py

def test_html(request):

    from django.template import loader

    t = loader.get_template('test_html.html')
    html = t.render()
    return HttpResponse(html)

urls.py

path('test_html',views.test_html)

test_html.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h3>来自模板层</h3>
</body>
</html>

运行结果如下图:

 

 

 

方式二: 使用render()直接加载并响应模板

在视图函数中:

from django.shortcuts import render
return render(request, '模板文件名', '字典数据')

views.py

def test_html(request):

    # from django.template import loader
    #
    # t = loader.get_template('test_html.html')
    # html = t.render()
    # return HttpResponse(html)
    from django.shortcuts import render
    return render(request, 'test_html.html')

运行结果如下图:

 

 4、视图层与模板层之间的交互

  视图函数中可以将python变量封装到字典中传递给模板

def xxx_view(request):
    dic = {
         "变量1": "值1",
         "变量2": "值2"
    }    
    return render(request, 'xxx.html', dic)

  在模板中可以使用{{变量名}}调用视图函数传来的变量

views.py

def test_html(request):
    # from django.template import loader
    #
    # t = loader.get_template('test_html.html')
    # html = t.render()
    # return HttpResponse(html)
    from django.shortcuts import render
    dic = {'name': 'tester', 'age': '17'}
    return render(request, 'test_html.html', dic)

test_html.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h3>{{name}}来自模板层<h3>
</body>
</html> 

运行结果如下图:

 

 

 5、能从视图传递到模板中的数据类型

str -字符串    int -整型
list -数组     tuple -元组
dict -字典     func -方法
object -类实例化的对象

模板中使用变量的语法:
{{变量名}}

{{变量名.index}}

{{变量名.key}}

{{对象.方法}}

{{函数名}}

views.py

def test_html_param(request):
    dic = {}
    dic['int'] = 88
    dic['str'] = 'zhangsan'
    dic['lst'] = ['Tom', 'Jack', 'Lily']
    dic['dict'] = {'a': 9, 'b': 8}
    dic['func'] = say_hi
    dic['class_obj'] = Test()

    return render(request, 'test_html_param.html', dic)


def say_hi():
    return 'hahha'


class Test:
    def say(self):
        return 'tester'

urls.py

path('test_html_param',views.test_html_param),

test_html_param.html 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h3>int 是 {{ int }}</h3>
    <h3>str 是 {{ str }}</h3>
    <h3>lst 是 {{ lst }}</h3>
    <h3>lst 是 {{ lst.0 }}</h3>
    <h3>dict 是 {{ dict }}</h3>
    <h3>dict['a'] 是 {{ dict.a }}</h3>
    <h3>function 是 {{ func }}</h3>
    <h3>class_obj 是 {{ class_obj.say }}</h3>
</body>
</html> 

运行结果如下图:

 

 6、模板中的标签

作用:将一些服务端的功能嵌入到模板中,例如流程控制等。

标签语法:

{%标签%}
......
{%结束标签%} 

if 标签

语法:

{% if 条件表达式1 %}
...
{% elif 条件表达式2 %}
...
{% elif 条件表达式3 %}
...
{% else 条件表达式4 %}
...
{% endif %}

注意:

  if条件表达式里可以用的运算符 ==, !=, >, <, >=, <=, in, not in, is, is not, not, and, or

  在if标记中使用实际括号是无效的语法,如果需要指定他们的优先级,应使用嵌套的if标记

示例:

views.py

def test_if_for(request):
    dic = {}
    dic['x'] = 10
    return render(request,'test_if_for.html',dic)

urls.py

path('test_if_for',views.test_if_for),

test_if_for.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>测试 if和for</title>
</head>
<body>
    {% if x > 10 %}
        今天天气很好
    {% else %}
        今天天气非常好
    {% endif %}
</body>
</html>

  

for 标签

语法:

{% for 变量 in 可迭代对象%}
    ...循环语句
{% empty %}
    ...可迭代对象无数据时填充的数据
{% endfor %}

  

内置变量:

变量 描述
forloop.counter 循环的当前迭代(从1开始索引)
forloop.counter0 循环的当前迭代(从0开始索引)
forloop.revcounter counter值的倒序
forloop.revcounter0 revcounter值的倒序
forloop.first 如果这是第一次通过循环,则为真
forloop.last 如果这是最后一次循环,则为真
forloop.parentloop 当嵌套循环,parentloop表示外层循环

示例:

views.py

def test_if_for(request):
    dic = {}
    dic['x'] = 10
    dic['lst'] = {'Tom', 'Jack', 'Lily'}
    return render(request,'test_if_for.html',dic)

test_if_for.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>测试 if和for</title>
</head>
<body>
    {% if x > 10 %}
        今天天气很好
    {% else %}
        今天天气非常好
    {% endif %}
    <br>
    {% for name in lst %}
        {% if forloop.first %} $$$$${% endif %} <!--当第一次循环的时候会输出该符号-->
        <p>{{ forloop.counter }} {{ name }}</p> <!--forloop.counter 从1开始计数-->
        {% if forloop.last %} ===={% endif %}<!--当第最后一次循环的时候会输出该符号-->
    {% empty %}
        当前无数据
    {% endfor %}
</body>
</html>
</body>
</html>

运行结果如下图:

 九、模板层-过滤器和继承

1、过滤器

  定义:在变量输出时对变量的值进行处理

  作用:可以通过过滤器来改变变量的输出显示

  语法:{{变量|过滤器1:'参数值1'|过滤器2:'参数值2'......}}

2、常用过滤器

过滤器 说明
lower 将字符串转换为全部小写
upper 将字符串转换为大写模式
safe 默认不对变量内的字符串进行html转义
add:'n'

将value的值增加n

truncatechars:'n' 如果字符串字符数量多于指定的字符数量,那么会被截断,截断的字符串将以可翻译的省略号序列("...")结尾

 

3、upper、add、safe使用示例

test_html_param.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h3>int 是 {{ int|add:'2' }}</h3>   # 为原有数值增加2
    <h3>str 是 {{ str|upper }}</h3>    # 将字符串转换为大写
    <h3>lst 是 {{ lst }}</h3>
    <h3>lst 是 {{ lst.0 }}</h3>
    <h3>dict 是 {{ dict }}</h3>
    <h3>dict['a'] 是 {{ dict.a }}</h3>
    <h3>function 是 {{ func }}</h3>
    <h3>class_obj 是 {{ class_obj.say }}</h3>
    <h3>script 是 {{ script|safe }}</h3>  # 告知浏览器不要转义该字符串
</body>
</html>

 

views.py

def test_html_param(request):
    dic = {}
    dic['int'] = 88
    dic['str'] = 'zhangsan'
    dic['lst'] = ['Tom', 'Jack', 'Lily']
    dic['dict'] = {'a': 9, 'b': 8}
    dic['func'] = say_hi
    dic['class_obj'] = Test()
    dic['script'] = '<script>alert(111)</script>'
    return render(request, 'test_html_param.html', dic)

 

 

4、继承

 使用场景:如下图,很多页面的头和尾都是相同的,这就是继承的主要使用场景。

 

 

  作用:模板继承可以使父模板的内容重用,子模板直接继承父模板的全部内容并可以覆盖父模板中相应的快。

  语法-父模板中:

    定义父模板中的块block标签

    标识出哪些在子模块中是允许被修改的

    block标签:在父模板中定义,可以在子模板中覆盖

 语法-子模板中:

    继承模板extends标签(写在模板文件的第一行)   例如:{% extends 'base.html' %}

    子模板复写父模板中的内容块  

    {% block block_name %}

    子模板块用来覆盖父模板块中的 block_name 块的内容

    {% endblock block_name %}

5、关于继承的测试

首先设计一个场景,有一个测试平台,网页上一共就有3个页面,主页、用例和测试计划,其中三个页面内的头尾一样,只有里面的显示内容不一样,

因此,我们可以使用我们的继承来实现这个逻辑,实现过程如下:
首先创建我们的主页,

base.html


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
{% block mytitle %}
<title>主页</title>
{% endblock %}
</head>
<body>
<a href="/base">主页</a>
<a href="/case">测试用例</a>
<a href="/plan">测试计划</a>
<br>
{% block info %}
这是主页
{% endblock %}
<br>
<h3>有任何问题请联系tester</h3>
</body>
</html>

 

如上:让头部的测试用例、测试计划和尾部的联系信息继承了base.html, 可以在其他页面复写mytitle和info

case.html

{% extends 'base.html' %} <!--继承主页 base.html-->

{% block mytitle %} <!--修改不同的地方 名称'mytitle'要与base.html保持一致-->
    <title>测试用例</title>
{% endblock %}

{% block info %} <!--修改不同的地方 名称'info'要与base.html保持一致-->
    欢迎进入测试用例
{% endblock %}

 

plan.html

{% extends 'base.html' %} <!--继承主页 base.html-->

{% block mytitle %} <!--修改不同的地方-->
    <title>测试计划</title>
{% endblock %}

{% block info %} <!--修改不同的地方-->
    欢迎进入测试计划
{% endblock %}

 

views.py

def base_index(request):
    return render(request, 'base.html')


def case_index(request):
    return render(request, 'case.html')


def plan_index(request):
    return render(request, 'plan.html')

 

urls.py

    path('base', views.base_index),
    path('case', views.case_index),
    path('plan', views.plan_index)

 

 

 

 6、关于继承的注意事项

  不重写,将按照父模板的效果显示

  重写,则按照重写效果显示

  模板继承时,服务器端的动态内容无法继承

如:传递的变量无法继承

views.py

def base_index(request):
    lst = ['zhansan', 'lisi']
    return render(request, 'base.html', locals())

 

 

 

 base.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    {% block mytitle %}
    <title>主页</title>
    {% endblock %}
</head>
<body>
    <a href="/base">主页</a>
    <a href="/case">测试用例</a>
    <a href="/plan">测试计划</a>
    <br>
    {% block info %}
        这是主页
    {% endblock %}
    {{ lst }}
    <br>
    <h3>有任何问题请联系tester</h3>
</body>
</html>

 

 

 

十、URL反向解析

1、代码中的URL

  模板[HTML]中:

<a href='url'>超链接</a>
<from action='url', method='post'>
from表单中的数据,用post方法提交到url

 

  视图函数中:

HttpResponseRedirect('url')
将用户地址栏中的地址重定向到url

 

2、URL书写规范

  绝对地址:

  http://127.0.0.1:8000/page/1

  相对地址:

  · '/page/1', '/'开头的相对地址,浏览器会把当前地址栏里的协议、ip和端口加上这个地址,作为最终的访问地址,

   即,如果当前的访问地址是'http://127.0.0.1:8000/page/3',则当前相对地址的最终路径为'http://127.0.0.1:8000/page/1'    

  · 'page/1', 没有'/'开头的相对地址,浏览器会根据当前url的最后一个'/'之前的内容加上该相对地址,作为最终的访问地址。

   即,如果当前的访问地址是'http://127.0.0.1:8000/test/detail',则当前相对地址的最终路径为'http://127.0.0.1:8000/test/page/1'

  · 建议使用以'/'开头的相对地址

3、URL反向解析

  定义:指在视图和模块中,用path定义的名称来动态查找或计算出相应的路由。

  语法:

    path(route, views, name='别名')

    path('page', views.page_view, name='page_url')

  根据path中的'name='关键字传参给url确定了一个唯一确定的名字,在模板或视图中,可以通过这个名字反向推断出此url的信息

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

    

 

posted @ 2022-03-25 14:08  文十七  阅读(51)  评论(0编辑  收藏  举报