HTTP 请求/响应的步骤:php
客户端链接到Web服务器css
一个HTTP客户端,一般是浏览器,与Web服务器的HTTP端口(默认为80)创建一个TCP套接字链接。例如,http://www.luffycity.com。html
发送HTTP请求前端
经过TCP套接字,客户端向Web服务器发送一个文本的请求报文,一个请求报文由请求行、请求头部、空行和请求数据4部分组成。python
服务器接受请求并返回HTTP响应mysql
Web服务器解析请求,定位请求资源。服务器将资源复本写到TCP套接字,由客户端读取。一个响应由状态行、响应头部、空行和响应数据4部分组成。web
释放链接TCP链接正则表达式
若connection 模式为close,则服务器主动关闭TCP链接,客户端被动关闭链接,释放TCP链接;若connection 模式为keepalive,则该链接会保持一段时间,在该时间内能够继续接收请求;sql
客户端浏览器解析HTML内容shell
客户端浏览器首先解析状态行,查看代表请求是否成功的状态代码。而后解析每个响应头,响应头告知如下为若干字节的HTML文档和文档的字符集。客户端浏览器读取响应数据HTML,根据HTML的语法对其进行格式化,并在浏览器窗口中显示。
HTTP/1.1协议中共定义了八种方法(也叫“动做”)来以不一样方式操做指定的资源:
get:
head:
post:
向指定资源提交数据,请求服务器进行处理(例如提交表单或者上传文件)。数据被包含在请求本文中。这个请求可能会建立新的资源或修改现有资源,或两者皆有。
<form action="http://127.0.0.1:8001" method="post"> 默认是get请求 <input type="text" name="user"> <input type="password" name="pwd"> <input type="submit"> </form>
put:
delete:
trace:
options:
connect:
全部HTTP响应的第一行都是状态行,依次是当前HTTP版本号,3位数字组成的状态代码,以及描述状态的短语,彼此由空格分隔
状态代码的第一个数字表明当前响应的类型:
超文本传输协议(HTTP)的统一资源定位符将从因特网获取信息的五个基本元素包括在一个简单的地址中:
传送协议。
层级URL标记符号(为[//],固定不变)
访问资源须要的凭证信息(可省略)
服务器。(一般为域名,有时为IP地址)
端口号。(以数字方式表示,若为HTTP的默认值“:80”可省略)
路径。(以“/”字符区别路径中的每个目录名称)
查询。(GET模式的窗体参数,以“?”字符为起点,每一个参数以“&”隔开,再以“=”分开参数名称与数据,一般以UTF8的URL编码,避开字符冲突的问题)
片断。以“#”字符为起点
以http://www.luffycity.com:80/news/index.html?id=250&page=1 为例, 其中: http,是协议; www.luffycity.com,是服务器; 80,是服务器上的默认网络端口号,默认不显示; /news/index.html,是路径(URI:直接定位到对应的资源); ?id=250&page=1,是查询
import socket from threading import Thread sk = socket.socket() sk.bind(('127.0.0.1',8008)) sk.listen() def html(conn): with open('demo2.html', 'rb') as f: data = f.read() conn.send(data) conn.close() def css(conn): with open('test.css', 'rb') as f: data = f.read() conn.send(data) conn.close() def js(conn): with open('test.js', 'rb') as f: data = f.read() conn.send(data) conn.close() def jpg(conn): with open('1.png', 'rb') as f: data = f.read() conn.send(data) conn.close() def ico(conn): with open('jd.ico', 'rb') as f: data = f.read() conn.send(data) conn.close() urlpatterns = [ ('/',html),('/test.css',css), ('/1.png',jpg),('/test.js',js),('/jd.ico',ico),] while True: conn,addr = sk.accept() mes = conn.recv(1024).decode('utf-8') path = mes.split('\r\n')[0].split(' ')[1] print(path) conn.send(b'http/1.1 200 ok \r\n\r\n') for i in urlpatterns: if path == i[0]: t = Thread(target=i[1],args=(conn,)) t.start() # <link rel="icon" href="jd.ico"> 在head标签中设置ico,(小图标)
# 在上面的基础上修改 def html(conn): time_tag = str(time.time()) with open('demo2.html', 'r',encoding='utf-8') as f: data = f.read() # html中随便添加一个内容,而后将其替换 data = data.replace('xxoo',time_tag).encode('utf-8') conn.send(data) conn.close()
wsgiref自己就是个web框架,提供了一些固定的功能(请求和响应信息的封装,不须要咱们本身写原生的socket了也不须要我们本身来完成请求信息的提取了,提取起来很方便
environ : 是所有加工好的请求信息,加工成了一个字典,经过字典取值的方式就能拿到不少你想要拿到的信息
start_response: 帮你封装响应信息的(响应行和响应头),注意下面的参数
import time from wsgiref.simple_server import make_server def html(): time_tag = str(time.time()) with open('demo2.html', 'r',encoding='utf-8') as f: data = f.read() data = data.replace('xxoo',time_tag).encode('utf-8') return data def css(): with open('rr.css', 'rb') as f: data = f.read() return data def js(): with open('test.js', 'rb') as f: data = f.read() return data def jpg(): with open('1.jpg', 'rb') as f: data = f.read() return data def ico(): with open('jd.ico', 'rb') as f: data = f.read() return data urlpatterns = [ ('/',html),('/rr.css',css), ('/1.jpg',jpg),('/test.js',js),('/jd.ico',ico),] def application(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html'),('k1','v1')]) path = environ['PATH_INFO'] # 拿到每一个请求 print(path) for i in urlpatterns: if path == i[0]: ret = i[1]() break else: ret = b'404 not found!!!!' return [ret] httpd = make_server('127.0.0.1', 8080, application) print('Serving HTTP on port 8080...') httpd.serve_forever()
# HTML文件 <h1>{{userinfo}}</h1> <ul> {% for k,v in userinfo.items()%} <li>{{k}}--{{v}}</li> {% endfor %} </ul> # py文件 在上面基础上修改 from jinja2 import Template def html(): user = showdata() with open('demo2.html', 'r',encoding='utf-8') as f: data = f.read() tem = Template(data) data = tem.render({'userinfo':user}) data = data.encode('utf-8') return data
所谓的mvc就是把web应用分为模型(M),控制器(C),和视图(V),他们之间以一种插件式的,松耦合的方式链接在一块儿的,模型负责业务对象与数据库的映射(ORM),视图负责与用户的交互,控制器接收用户的输入调用模型和视图完成用户的请求
Django的MTV模式本质上和mvc是同样的,也是为了各组件保持松耦合的关系,只是定义上有些不一样,Django的MTV分别是值
除了以上三层外,还须要一个URL分发器,它的做用是将一个URL的页面请求分发给不一样的View处理,View在调用相应的Model和Template,响应模式以下
https://www.djangoproject.com/download/
1 建立项目 first_pro 2 建立app app01 作一个登陆页面的web项目,浏览器输入一个网址获得一个web页面 用户: http:127.0.0.1:8001/login/ 1 urls.py from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ # url(r'^admin/', admin.site.urls), url(r'^index/', views.index), #配置路径,r'^/index/',这个前置导航斜杠不须要添加. ] # urls.py里面须要注意的问题 url(r'^index/', views.index), 第一个参数:路径正则字符串 第二个参数:对应的视图函数 2 写逻辑视图(Views) from django.shortcuts import render,HttpResponse # Create your views here. def index(request): print(request.method) # 'POST' 'GET' if request.method == 'GET': return render(request,'login.html') else: username = request.POST.get('username') password = request.POST.get('password') if username == 'xin' and password == '123': return HttpResponse('登陆成功!') else: return HttpResponse('登陆失败!') 3 建立html文件(Template文件下) 在templates文件夹中建立一个login.html文件 <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Bootstrap 101 Template</title> </head> <body> <form action="/login/" method="post"> 姓名:<input type="text" name="username"> 密码:<input type="password" name="password"> <input type="submit"> </form> </body> </html> 4. views.py from django.shortcuts import render,HttpResponse # Create your views here. def login(request): if request.method == 'GET': return render(request,'login.html') else: name = request.POST.get('username') ped = request.POST.get('password') if name== 'xin' and ped == '666': return HttpResponse('成功') else: return HttpResponse('失败')
基本格式
from django.conf.urls import url #循环urlpatterns,找到对应的函数执行,匹配上一个路径就找到对应的函数执行,就再也不往下循环了,并给函数传一个参数request,和wsgiref的environ相似,就是请求信息的全部内容 urlpatterns = [ url(正则表达式, views视图函数,参数,别名), ]
参数说明
基本配置
urls.py: from django.conf.urls import url from django.contrib import admin from app02 import views urlpatterns = [ url(r'^books/(\d{4})/$', views.books), # 匹配年 url(r'^books/(\d{4})/(\d{1,2})/', views.books), # 匹配年月 ] views.py: # 第一个参数必须是request,后面跟的三个参数是对应着上面分组正则匹配的每一个参数的 def books(request,year,month): return HttpResponse(year+month)
补充说明:
# 是否开启URL访问地址后面不为/跳转至带有/的路径的配置项 APPEND_SLASH=True
from django.conf.urls import url from app01 import views urlpatterns = [ url(r'^articles/(\d{4})/$', views.year_archive), # year_archive(request,n),小括号为分组,有分组,那么这个分组获得的用户输入的内容,就会做为对应函数的位置参数传进去,别忘了形参要写两个了 url(r'^articles/(?P<year>\d{4})/$', views.year_archive),#某年的,(?P<year>[0-9]{4})这是命名参数,那么函数year_archive(request,year),形参名称必须是year这个名字。并且注意若是你这个正则后面没有写$符号,即使是输入了月份路径,也会被它拦截下拉,由于它的正则也能匹配上 url(r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/$', views.month_archive),#某年某月的 url(r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/$', views.article_detail), #某年某月某日的 ]
视图函数中指定默认值
# urls.py中 from django.conf.urls import url from app01 import views urlpatterns = [ url(r'^blog/$', views.page), url(r'^blog/page(?P<num>\d+)/$', views.page), ] # views.py中,能够为num指定默认值 def page(request, num="1"): pass
# 项目文件夹下的urls.py文件中的url写法: from django.conf.urls import url,include from django.contrib import admin from app01 import views urlpatterns = [ #首页 url(r'^$', views.base), url(r'^app01/', include('app01.urls')), url(r'^app02/', include('app02.urls')), ] # app01下urls.py内容写法 from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^$', views.app01base), ] # app02下urls.py内容写法 from django.conf.urls import url from django.contrib import admin from app02 import views urlpatterns = [ url(r'^$', views.app02base), ]
def index(request): # http相关请求信息---封装--HttpRequest对象 if request.method == 'GET': print(request.body) # 获取post请求提交过来的原始数据 print(request.GET) # 获取GET请求提交的数据 # print(request.META) # 请求头相关信息,就是一个大字典 print(request.path) # /index/ 路径 print(request.path_info) # /index/ 路径 print(request.get_full_path()) # /index/?username=dazhuang&password=123 return render(request,'index.html') else: print(request.body) # b'username=dazhuang' print(request.POST) # 获取POST请求提交的数据 return HttpResponse('男宾三位,拿好手牌!')
HttpResponse --- 回复字符串的时候来使用 render --- 回复一个html页面的时候使用 redirect -- 重定向 示例: # views.py from django.shortcuts import render,HttpResponse,redirect def login(request): if request.method == 'GET': return render(request,'login.html') else: username = request.POST.get('username') password = request.POST.get('password') if username == 'taibai' and password == 'dsb': return redirect('/home/') # 重定向 else: return HttpResponse('滚犊子,赶忙去充钱!!!') def home(request): return render(request,'home.html') # urls.py urlpatterns = [ url(r'^test/', views.test), url(r'^home/', views.home), ]
1)301和302的区别。 301和302状态码都表示重定向,就是说浏览器在拿到服务器返回的这个状态码后会自动跳转到一个新的URL地址,这个地址能够从响应的Location首部中获取 (用户看到的效果就是他输入的地址A瞬间变成了另外一个地址B)——这是它们的共同点。 他们的不一样在于。301表示旧地址A的资源已经被永久地移除了(这个资源不可访问了),搜索引擎在抓取新内容的同时也将旧的网址交换为重定向以后的网址; 302表示旧地址A的资源还在(仍然能够访问),这个重定向只是临时地从旧地址A跳转到地址B,搜索引擎会抓取新的内容而保存旧的网址。 SEO302好于301 2)重定向缘由: (1)网站调整(如改变网页目录结构); (2)网页被移到一个新地址; (3)网页扩展名改变(如应用须要把.php改为.Html或.shtml)。 这种状况下,若是不作重定向,则用户收藏夹或搜索引擎数据库中旧地址只能让访问客户获得一个404页面错误信息,访问流量白白丧失;再者某些注册了多个域名的 网站,也须要经过重定向让访问这些域名的用户自动跳转到主站点等。
临时重定向(响应状态码:302)和永久重定向(响应状态码:301)对普通用户来讲是没什么区别的,它主要面向的是搜索引擎的机器人。
FBV(function based views) : 就是在视图里使用函数处理
def home(request): print('home!!!') return render(request,'home.html')
CBV(class based views) : 在视图里使用类处理请求
views.py from django.views import View class LoginView(View): # 经过请求方法找到本身写的视图类里面对应的方法 def get(self,request): return render(request,'login2.html') def post(self,request): username = request.POST.get('uname') password = request.POST.get('pwd') print(username,password) return HttpResponse('登陆成功!') urls.py url(r'^login2/', views.LoginView.as_view()),
FBV加装饰器
def wrapper(f): def inner(*args,**kwargs): print('请求以前') ret = f(*args,**kwargs) print('请求以后') return ret return inner @wrapper def home(request): print('home!!!') return render(request,'home.html')
CBV加装饰器
from django.views import View from django.utils.decorators import method_decorator def wrapper(f): def inner(*args,**kwargs): print('请求以前') ret = f(*args,**kwargs) print('请求以后') return ret return inner @method_decorator(n1,name='get') # 方式三 class LoginView(View): @method_decorator(n1) # 方式2 给全部方法加装饰器 def dispatch(self, request, *args, **kwargs): # print('请求来啦') ret = super().dispatch(request, *args, **kwargs) # print('到点了,走人了') return ret @method_decorator(n1) # 方式1 def get(self,request): print('get方法执行了') return render(request,'login2.html') def post(self,request): username = request.POST.get('uname') password = request.POST.get('pwd') return HttpResponse('登陆成功!')
CBV的dispatch方法
from django.views import View class LoginView(View): # GET def dispatch(self, request, *args, **kwargs): print('请求来啦') ret = super().dispatch(request, *args, **kwargs) print('到点了,走人了') return ret def get(self,request): print('get方法执行了') return render(request,'login2.html') def post(self,request): username = request.POST.get('uname') password = request.POST.get('pwd') print(username,password) return HttpResponse('登陆成功!')
# 示例 html代码: <p>{{ num }}</p> <p>{{ name }}</p> <p>{{ name_list.2 }}</p> # 经过 .索引 来取值 <p>{{ d1.age }}</p> # 经过 .键 取值 <p>{{ a.kind }}</p> <p>{{ a.eat }}</p> # 调用类中方法 views.py代码 def index(request): num = 100 name = 'shige' name_list = ['大壮','小壮','壮壮'] d1 = {'name':'大壮','age':73,'hobby':'xuefei+xiangxi'} class Animal: def __init__(self): self.kind = 'dog' def eat(self): return 'shi' a = Animal() return render(request,'index.html',{'num':num,'name':name,'namelist':name_list,'d1':d1,'a':a}) # return render(request,'index.html',locals()) locals() 获取函数内部全部变量的值,并加工成{'变量名':'变量值'....}这样一个字典
default : 若是一个变量是false或者为空,使用给定的默认值.不然使用变量的值
{{ value|default:"nothing"}}
length : 返回值的长度,做用于字符串和列表。
mes = 'I love you three thousand times' {{ mes|length }} # 31
filesizeformat : 将值格式化为一个 “人类可读的” 文件尺寸 (例如 '13 KB'
, '4.1 MB'
, '102 bytes'
, 等等)
filesize = 234352452 {{ filesize|filesizeformat }} # 223.5 MB
slice : 切片,若是 value="hello world",还有其余可切片的数据类型
{{value|slice:"2:-1"}}
date : 格式化,若是 value=datetime.now()
{{ value|date:"Y-m-d H:i:s"}}
safe : 将字符串识别成标签
val = '<a href="http://www.baidu.com">百度</a>' ret = "<script>alert('123')</script>" {{ val|safe }} # 生成a标签的样式 {{ ret|safe }} # 有js的样式
truncatechars : 若是字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾。
mes = 'I love you three thousand times' {{ value|truncatechars:10}} #注意:最后那三个省略号也是9个字符里面的,也就是这个9截断出来的是6个字符+3个省略号,获得结果 : I love ... (空格一算一个字符)
truncatewords : 在必定数量的字后截断字符串,是截多少个单词。
mes = 'I love you three thousand times' {{ value|truncatewords:3}} # I love you ...
cut : 移除全部的与给出变量相同的字符串
mes = 'I love you three thousand times' {{ value|cut:' ' }} # Iloveyouthreethousandtimes
join : 使用字符串链接列表,相似于python中str.join(list)
lis = [11,22,33] {{ lis|join:'-' }} # 11-22-33
for标签
遍历每个元素: 写个for,而后 tab键自动生成for循环的结构
dic = {'name':'alex','age':77} {% for k,v in dic.items %} # 循环字典 <li>{{ k }} - {{ v }}</li> {% endfor %} # name - alex # age - 77
for循环的其余方法
forloop.counter 当前循环的索引值(从1开始),forloop是循环器,经过点来使用功能 forloop.counter0 当前循环的索引值(从0开始) forloop.revcounter 当前循环的倒序索引值(从1开始) forloop.revcounter0 当前循环的倒序索引值(从0开始) forloop.first 当前循环是否是第一次循环(布尔值) forloop.last 当前循环是否是最后一次循环(布尔值) forloop.parentloop 本层循环的外层循环的对象,再经过上面的几个属性来显示外层循环的计数等 forloop.parentloop.counter
{# {% for key,value in d1.items %}#} {# {{ forloop.counter }}#} {# <li>{{ key }} -- {{ value }}</li>#} {# {% endfor %}#} {# {% for key,value in d1.items %}#} {# {{ forloop.counter0 }}#} {# <li>{{ key }} -- {{ value }}</li>#} {# {% endfor %}#} {# {% for key,value in d1.items %}#} {# {{ forloop.revcounter }}#} {# <li>{{ key }} -- {{ value }}</li>#} {# {% endfor %}#} {# {% for key,value in d1.items %}#} {# {{ forloop.revcounter0 }}#} {# <li>{{ key }} -- {{ value }}</li>#} {# {% endfor %}#} {# {% for key,value in d1.items %}#} {# {{ forloop.first }}#} {# <li>{{ key }} -- {{ value }}</li>#} {# {% endfor %}#} <!-- forloop.parentloop示例 --> {#<ul>#} {# {% for dd2 in d2 %}#} {# <li>#} {# {% for ddd2 in dd2 %}#} {# {{ forloop.parentloop.counter }}#} {# {{ forloop.counter }}#} {# <a href="">{{ ddd2 }}</a>#} {# {% endfor %}#} {##} {# </li>#} {# {% endfor %}#} {#</ul>#} <!-- empty示例 --> {#<ul>#} {# {% for foo in d3 %}#} {# <li>{{ foo }}</li>#} {# {% empty %}#} {# <li>查询的内容啥也没有</li>#} {# {% endfor %}#} {##} {#</ul>#}
if 标签
{% if num > 100 %} <p>excellent</p> {% elif num == 100 %} <p>beautiful</p> {% else %} <p>nice</p> {% endif %} 1. Django的模板语言不支持连续判断,即不支持如下写法: {% if a > b > c %} ... {% endif %} 2. Django的模板语言中属性的优先级大于方法(了解) def xx(request): d = {"a": 1, "b": 2, "c": 3, "items": "100"} return render(request, "xx.html", {"data": d})
with标签
使用一个简单地名字缓存一个复杂的变量,多用于给一个复杂的变量起别名,当你须要使用一个“昂贵的”方法(好比访问数据库)不少次的时候是很是有用的,注意等号不要加空格
# 两种方式 {% with total=business.employees.count %} {{ total }} <!--只能在with语句体内用--> {% endwith %} {% with business.employees.count as total %} {{ total }} {% endwith %}
csrf_token
安全认证机制 咱们以post方式提交表单的时候,会报错,还记得咱们在settings里面的中间件配置里面把一个csrf的防护机制给注销了啊,自己不该该注销的,而是应该学会怎么使用它,而且不让本身的操做被forbiden,经过这个东西就能搞定。 这个标签用于跨站请求伪造保护, 在页面的form表单里面(注意是在form表单里面)任何位置写上{% csrf_token %},这个东西模板渲染的时候替换成了<input type="hidden" name="csrfmiddlewaretoken" value="8J4z1wiUEXt0gJSN59dLMnktrXFW0hv7m4d40Mtl37D7vJZfrxLir9L3jSTDjtG8">,隐藏的,这个标签的值是个随机字符串,提交的时候,这个东西也被提交了,首先这个东西是咱们后端渲染的时候给页面加上的,那么当你经过我给你的form表单提交数据的时候,你带着这个内容我就认识你,不带着,我就禁止你,由于后台咱们django也存着这个东西,和你这个值相同的一个值,能够作对应验证是否是我给你的token,存储这个值的东西咱们后面再学,你先知道一下就好了,就像一个咱们后台给这个用户的一个通行证,若是你用户没有按照我给你的这个正常的页面来post提交表单数据,或者说你没有先去请求我这个登录页面,而是直接模拟请求来提交数据,那么我就能知道,你这个请求是非法的,反爬虫或者恶意攻击个人网站。
模板继承
{% extends "base.html" %} # 写在开始 钩子:{% block title %} xxx {% endblock %} 钩子:{% block title %} xxx {% endblock title %} 钩子:{% block title %} {{ block.super }} # 显示继承模板的内容 xxx
组件
{% include 'navbar.html' %} # 引用组件的html文件 组件是提供某一完整功能的模块,如:编辑器组件,QQ空间提供的关注组件 等。 而插件更倾向封闭某一功能方法的函数。 这二者的区别在 Javascript 里区别很小,组件这个名词用得很少,通常统称插件。
自定义过滤器
在settings中的 INSTALL_APPS 配置当前的app,否则Django没法找到自定义的过滤器
app应用文件夹中建立一个templatetags文件件,必须是这个名字
templatetags文件夹中建立一个 xx.py 文件,文件名字随便起
在新建的 xx.py 文件中建立自定义过滤器
from Django import template register = template.Library() # register固定名字,注册器 @register.filter def oo(v1): # 不带参数的过滤器,第一个参数v1是views视图函数中传过来的 s = v1 + 'xxoo' return s @register.filter def oo(v1,v2): # 带参数的过滤器 s = v1 + v2 return s
使用html文件中的数据
{% load xx %} {{ values|oo }} -- 无参数 {{ values|oo:'asdf' }} -- 有参数
参数最多两个
自定义标签
在settings中的 INSTALL_APPS 配置当前的app,否则Django没法找到自定义的过滤器
app应用文件夹中建立一个templatetags文件件,必须是这个名字
templatetags文件夹中建立一个 xx.py 文件,文件名字随便起
在新建的 xx.py 文件中建立自定义过滤器
from Django import template register = template.Library() # register固定名字,注册器 @register.simple_tag def mytag(v1,v2,v3): # 第一个参数v1是views视图函数中传过来的 s = v1 + v2 + v3 return s
使用
{% load xx %} {% mytag s1 '啦啦' '呵呵' %}
inclusion_tag : 多用于返回html代码片断
# views.py def index(request): lis = [11,22,33,44,55,66] return render(request,'index.html',{'lis':lis}) # index.html {% load one %} {% func lis %} # one.py from django import template register = template.Library() @register.inclusion_tag('test.html') # 将test.html里面的内容用下面函数的返回值渲染,而后做为一个组件同样,加载到使用这个函数的HTML里面 def func(v1): return {'data':v1} # v1 是传过来的lis列表 # test.html <ul> {% for d in data %} <li>{{ d }}</li> {% endfor %} </ul> 流程: 先执行index函数,将lis传给index.html,index.html中将lis做为func的参数传进去,v1=lis,在one.py中,将v1传给test.html进行渲染,最后将渲染的结果返回给index.html,在页面显示出来
js,css,img 等都叫作静态文件,那么在关于jango中静态文件的配置,咱们就须要在settings配置文件中写上下面内容
# 在项目目录下建立一个文件用来存放静态文件,一般名称为 : static STATIC_URL = '/static/' # 别名 STATICFILES_DIRS = [ os.path.join(BASE_DIR,'static'), # 注意别忘了写逗号,第二个参数就是项目中你存放静态文件的文件夹名称 ]
目录 : 别名也是一种安全机制,浏览器上经过调试台你能看到的是别名的名字,这样别人就不知道你静态文件的名字了,否则别人就能经过这个文件夹路径进行攻击
前端页面引入静态文件的写法,由于别名也可能会修改,因此使用路径的时候经过load static来找别名,经过别名映射路径的方式来获取静态文件
{% static %}
{% load static %} <img src="{% static "images/hi.jpg" %}" alt="Hi!" />
引用JS文件时使用
{% load static %} <script src="{% static "mytest.js" %}"></script>
某个文件多处被用到的能够存为一个变量
{% load static %} {% static "/images/hi.jpg" as myphoto %} <img src="{{ myphoto }}"></img>
注意:
一个html文件中写相对路径是须要注意一个问题
<form action="/login/"></form> <img src="/static/1.jpg" alt=""> 等标签须要写路径的地方,若是写的是相对路径,那么前置的/这个斜杠必须写上,否则这个请求会拼接当前网页的路径来发送请求,就不能匹配咱们的后端路径了
ORM是 对象--关系--映射 的简称.实现了数据模型与数据库的解耦,即数据库的设计不须要依赖特定的数据库,经过简单的配置就能够轻松更换数据库
类对象 --> sql --> pymysql --> mysql服务端 --> 磁盘,orm其实就是将类对象的语法翻译成sql语句的一个引擎
在python中orm的对应关系有三种: 类 ---------->表 类对象 ---------->行(记录) 类属性 ---------->表的字段(重点
建立表
# app 应用下的 models.py 文件中写 from django.db import models class UserInfo(models.Model): # UserInfo 为表名 id = models.AutoField(primary_key=True) name = models.CharField(max_length=10) age = models.IntegerField() current_date = models.DateField()
更多字段和参数
字段
<1> CharField 字符串字段, 用于较短的字符串. CharField 要求必须有一个参数 maxlength, 用于从数据库层和Django校验层限制该字段所容许的最大字符数. <2> IntegerField 用于保存一个整数. <3> DecimalField 一个浮点数. 必须 提供两个参数: <4> AutoField 一个 IntegerField, 添加记录时它会自动增加. 你一般不须要直接使用这个字段; 自定义一个主键:my_id=models.AutoField(primary_key=True) 若是你不指定主键的话,系统会自动添加一个主键字段到你的 model.
参数
(1)null 若是为True,Django 将用NULL 来在数据库中存储空值。 默认值是 False. (1)blank 若是为True,该字段容许不填。默认为False。 要注意,这与 null 不一样。null纯粹是数据库范畴的,而 blank 是数据验证范畴的。 若是一个字段的blank=True,表单的验证将容许该字段是空值。若是字段的blank=False,该字段就是必填的。 (2)default 字段的默认值。能够是一个值或者可调用对象。若是可调用 ,每有新对象被建立它都会被调用,若是你的字段没有设置能够为空,那么未来若是咱们后添加一个字段,这个字段就要给一个default值 (3)primary_key 若是为True,那么这个字段就是模型的主键。若是你没有指定任何一个字段的primary_key=True, Django 就会自动添加一个IntegerField字段作为主键,因此除非你想覆盖默认的主键行为, 不然不必设置任何一个字段的primary_key=True。 (4)unique 若是该值设置为 True, 这个数据字段的值在整张表中必须是惟一的 (5)choices 由二元组组成的一个可迭代对象(例如,列表或元组),用来给字段提供选择项。 若是设置了choices ,默认的表单将是一个选择框而不是标准的文本框,<br>并且这个选择框的选项就是choices 中的选项。 (6)db_index 若是db_index=True 则表明着为此字段设置数据库索引。 DatetimeField、DateField、TimeField这个三个时间字段,均可以设置以下属性。 (7)auto_now_add 配置auto_now_add=True,建立数据记录的时候会把当前时间添加到数据库。 (8)auto_now 配置上auto_now=True,每次更新数据记录的时候会更新该字段,标识这条记录最后一次的修改时间。
settings配置
若想将模型转为mysql数据库中的表,须要在 settings.py 中配置:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME':'库名', # 要链接的数据库,链接前须要建立好 'USER':'root', # 链接数据库的用户名 'PASSWORD':'', # 链接数据库的密码 'HOST':'127.0.0.1', # 链接主机,默认本级 'PORT':3306 , # 端口 默认3306 } }
项目文件夹下的 init.py文件中,写下面两句
import pymysql pymysql.install_as_MySQLdb()
执行数据库同步指令
python manage.py makemigrations # 生成记录,每次修改了models里面的内容或者添加了新的app,新的app里面写了models里面的内容,都要执行这两条 python manage.py migrate # 执行上面这个语句的记录来建立表,生成的表名字前面会自带应用的名字,例如:你的book表在mysql里面叫作app01_book表
model.py :
from django.db import models class Data(models.Model): name = models.CharField(max_length=10) age = models.IntegerField() current_data = models.DateField() def __str__(self): return self.name
建立方式一:
from app import models student_obj = models.Data( name = 'alex', age = 73, current_data= '2008-08-08' ) student_obj.save()
方式二(经常使用此建立)
from app import models new_obj = models.Data.objects.create( name = 'wusir', age = 83, current_data= '2008-08-15', ) print(new_obj) # Data object --> model对象 print(new_obj.name,new_obj.age) # .属性 能够获取对应字段的数据
方式三:
from app import models lis = [] for i in range(10): obj = models.Data( name = 'xin', age = 18, current_data= '2010-10-10' ) lis.append(obj) models.Data.objects.bulk_create(lis) # 批量插入,速度快
建立方式四: update_or_create 有就更新,没有就建立
from app import models models.Data.objects.update_or_create( name = 'taibai', # 有就更新 defaults={'age':89,'current_data':'2011-11-11'} name = 'xuefei', # 没有就建立 defaults={'age':18,'current_data':'2000-08-08'} )
# all() 查询全部的数据,返回的是queryset集合 all_objs = models.Data.objects.all() print(all_objs) for i in all_objs: print(i.name) # 拿到每个名字 # 条件查询: filter()方法, 返回的也是queryset集合,查询不到内容不会报错,返回一个<QuerySet []>空的queryset objs = models.Data.objects.filter(id=15) print(objs) objs = models.Data.objects.filter(id=1,name='alex').update(name='eva',age=20) print(objs) 打散的形式传参 objs = models.Data.objects.filter(**{'id':15,'name':'xuefei'}) print(objs) # 条件查询 : get()方法,返回的是model对象,并且get方法有且必须只有一个结果 objs = models.Data.objects.get(id=15) print(objs) 查询的数据不存在会报错,获得的结果有两个时会报错 # exclude(**kwargs):排除的意思,包含了与所给筛选条件不匹配的对象,没有不等于操做, objects控制器和queryset集合均可以调用,返回值是queryset类型. ex = models.Data.objects.exclude(name='xin') ex = models.Data.objects.all().exclude(name='xin') print(ex) # order_by(): queryset类型的数据来调用,查询结果进行排序,默认是按照id的升序排序的,返回值仍是queryset类型,在字段前面加个 - 号,就是降序排序 ord = models.Data.objects.order_by('-age','id') # 多条件排序,按照age进行降序,age相同的按照id升序排序 print(ord) # reverse() : queryset类型的数据来调用,对查询结果反向排序,返回值仍是queryset类型 rev = models.Data.objects.order_by('id').reverse() print(rev) # count() : queryset类型的数据来调用,返回数据库中匹配查询(QuerySet)的对象数量。 con = models.Data.objects.all().count() print(con) # first() : queryset类型的数据来调用,返回第一条记录,获得的都是model对象 obj = models.Data.objects.all().first() print(obj) # last(): queryset类型的数据来调用,返回最后一条记录,结果为model对象类型 obj = models.Data.objects.all().last() print(obj) # exists() : queryset类型的数据来调用,若是QuerySet包含数据,就返回True,不然返回False,空的queryset类型数据也有布尔值True和False,可是通常不用它来判断数据库里面是否是有数据,若是有大量的数据,你用它来判断,那么就须要查询出全部的数据,效率太差了,用count或者exits # values(*field) : 用的比较多,queryset类型的数据来调用,返回一个ValueQuerySet——一个特殊的QuerySet,运行后获得的并非一系列,model的实例化对象,而是一个可迭代的字典序列,只要是返回的queryset类型,就能够继续链式调用queryset类型的其余的查找方法,其余方法也是同样的。 # values_list(*field): 它与values()很是类似,它返回的是一个元组序列 obj = models.Data.objects.all().filter(age=16).values('name','age') print(obj) obj = models.Data.objects.all().filter(age=16).values_list('name','age') print(obj) # distinct(): values和values_list获得的queryset类型的数据来调用,从返回结果中剔除重复纪录,结果仍是queryset query = models.Data.objects.all().values('age').distinct() print(query)
mes = models.Data.objects.filter(price__in=[100,200,300]) # price值等于这三个里面的任意一个的对象 mes = models.Data.objects.filter(price__gt=100) # 大于,大于等因而price__gte=100,别写price>100,这种参数不支持 mes = models.Data.objects.filter(price__lt=100) # 小于 mes = models.Data.objects.filter(price__range=[100,200]) # sql的between and,大于等于100,小于等于200 mes = models.Data.objects.filter(title__contains="python") #title值中包含python的 mes = models.Data.objects.filter(title__icontains="python") #不区分大小写 mes = models.Data.objects.filter(title__startswith="py") #以什么开头,istartswith 不区分大小写 all_books = models.Book.objects.filter(pub_date__year=2012) #找2012年的全部书籍 all_books = models.Book.objects.filter(pub_date__year__gt=2012) # 找大于2012年的全部书籍 all_books = models.Book.objects.filter(pub_date__year=2019,pub_date__month=2) #找2019年月份的全部书籍
delete queryset 和model对象均可以调用 models.Student.objects.get(id=3).delete() # model对象来调用的delete方法 models.Student.objects.filter(name='Alex').delete() models.Student.objects.all().delete() # 删除全部
model对象不能调用更新方法 报错信息'Student' object has no attribute 'update' 只能queryset调用 models.Student.objects.get(name='alex').update(age=38) # 报错 models.Student.objects.filter(name='alex').update(age=38)