十四、Django学习
目录
一、Web服务的本质
二、Django的下载
三、Django的基础创建
四、MTV模型
五、URL控制器
六、View视图函数
七、Template模板语法
一、Web服务的本质
#服务端 import socket server = socket.socket() server.bind(('127.0.0.1',8080)) server.listen(5) while True: conn,addr = server.accept() recv_data = conn.recv(1024) print('recv_data:',recv_data) #发送符合浏览器Brower解析格式 conn.send(b'HTTP/1.1 OK \r\n\r\n<h1>hello world!</h1>')
二、Django的下载
pip install django
三、Django的基础创建
#a.创建一个django project的项目 django-admin startproject 项目名 #在当前目录下创建一个django项目 #b.创建应用 python manage.py startapp app名 #c.启动django应用命令 python manage.py runserver ip:port #d.测试,访问http://ip:port
django常用命令
#将models类转化成数据库表项(orm) python manage.py makemigrations python manage.py migrate python manage.py syncdb #同步更改数据库表或字段 python manage.py flush #清空数据库 python manage.py createsuperuser #创建超级管理员 python manage.py changepassword username #修改密码
django项目的文件介绍:
mysite ---mysite ---settings #项目配置文件 ---urls #路径与视图函数的映射关系 ---wsgi #封装的socket ---manage.py #与Django项目进行交互的脚本 ---app名 ---models #数据库操作 ---view #视图函数 ---templates #自建文件夹 ---html 文件 #自建html页面
静态文件配置
STATIC主要指的是如css,js,images等文件
STATIC_URL = '/static/' #别名 STATICFILES_DIRS = ( os.path.join(BASE_DIR,"statics"),#实际文件夹名字 ) 注意点1: django对别名和实际名进行映射,引用时,只能按照别名来,不能按实际名去找,如: html代码: //错误演示,/statics/为实际名 <script src="/statics/jquery.js"></script> //正确演示,/static/为别名 <script src="/static/jquery.js"></script> 注意点2: STATICFILES_DIRS = ( ('app01',os.path.join(BASE_DIR,"app01/statics")), #不能再这里写注释,否则无法读取static路径,切记,切记,切记 )
数据库配置(MySql)
#1.在mysql数据库里先创建数据库 create database library #2.在setting.py文件里 DATABASES = { 'default':{ 'ENGINE':'django.db.backends.mysql', 'NAME':'library', 'USER':'root', 'PASSWORD':'123456', 'HOST':'127.0.0.1', 'PORT':3306 } } INSTALLED_APPS = [ 'app01.apps.App01Config', 'app02' ] #3.在app01文件里models.py,创建类表映射ORM class Book(models.Model): id = models.AutoField(primary_key=True) title = models.CharField(max_length=32) price = models.DecimalField(max_digits=8,decimal_places=2) pub_date = models.DateField() publish = models.CharField(max_length=32)
create_date = models.DateTimeField(auto_now=True)
#自定义对象返回内容
def __str__(self):
return self.title
#4.创建ORM python manage.py makemigrations python manage.py migrate ps1:如果报no module named MySQLdb错误,在步骤2,因为django如果使用mysql,默认导入的驱动是MySQLdb,而MySQLdb在python3中有很大问题,我们需要使用PyMySQL,我们只需要找到项目名文件下的__init__.py,在里面写入: import pymysql pymysql.install_as_MySQLdb()
ps2:在models.py表里创建有一个创建时间字段create_date,设置了auto_now=True,表示创建就会更新当前时间,默认在setting.py里设置的是USE_TZ = False,表示使用UTC标准时间,
若服务在供一个时区,可以使用本地时间,将USE_TZ=False
四、MTV模型
Model:模型,负责业务对象和数据库的关系映射(ORM)
Template:模板,负责如何把页面展示给用户(html)
View:视图,负责业务逻辑,并在适当的时候调用Model和Template
五、URL控制器
5.0 作用
将一个个URL的页面请求分发给不同的view处理,view再调用相应的Model和Template
5.1 url控制器的格式
#在django 1.x版本里 from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(正则表达式,views视图函数,参数,别名), ] 参数说明: 正则表达式,如r'^book/2018/$' views视图函数:一个可调用对象 参数:可选,传递给 #在django 2.x版本里 from django.contrib import admin from django.urls import path,re_path from app01 import views urlpatterns = [ path('admin/', admin.site.urls), re_path('^index/(<year>[0-9]{4})/$',views.index) ] 参数说明: path:第一个参数表示一个常规路径 re_path:第一个参数是正则表达式
5.2 url的简单实用
url(r'^book/2018/$',views.book) #默认传入参数request url(r'^book/\d{4}/$',views.book_year) #\d(4)为任意4为数字,即年份 url(r'^book/(\d{4})/$',views.book_year) #传递无名分组参数,book_year(request,year)
5.3 url的有名分组
url(r'^book/(?P<YEAR>\d{4})/$', views.book_year) #book_year(request,YEAR)
5.4 url的分发
url(r'^book/', include(app01.urls))
5.5 url的别名
url(r'^login.html$', views.login,name='login_xxx')
ps:在template文件下html文件采用模板语言里的{% url "login_xxx" %},即url里匹配字段变的时候,别名不用变,即html文件不用更新
六、View视图函数
6.1 储备知识
URL格式: 协议://域名(或IP):端口/路径/?GET参数 例如: http://www.baidu.com/article/?a=hello
主要掌握俩个参数,request,response
6.2 request
request.GET #获得get方式的类:django.http.request.QueryDict GET类的方法: 类的方法: request.GET.get(key) #获得get请求里的参数key的对应的值,没有返回None 如:请求http://127.0.0.1:8001/login.html?a=1&value2=222 request.GET.get("value2") #结果=222 request.GET.dict() #获的get请求里的参数,形成字典 如:请求http://127.0.0.1:8001/login.html?a=1&value2=222 request.GET.dict() #结果{'a': '1', 'value2': '222'} request.GET.encoding #获得get请求的编码方式,一般为utf-8 request.GET.getlist(key) #获得get请求里的参数key对应的值,放入列表 request.GET.urlencode() #获得get请求里的参数字符串,人类可读
request.POST #获得post方式的类:django.http.request.QueryDict GET类的方法: 类的方法: request.POST.get(key) #获得get请求里的参数key的对应的值,没有返回None 如:请求http://127.0.0.1:8001/login.html request.POST.get("username") #结果=lisl request.POST.dict() #获的post请求里的参数,形成字典 如:请求http://127.0.0.1:8001/login.html request.POST.dict() #结果{'username': 'lisl', 'password': '123456'} request.POST.encoding #获得post请求的编码方式,一般为utf-8 request.POST.getlist(key) #获得post请求里的参数key对应的值,放入列表
request.method #请看请求方式,如GET,POST...,是字符串 request.path #url路径,不包含请求参数 如:请求http://127.0.0.1:8001/login.html?a=1&value2=222 request.path #结果login.html request.get_full_path() #返回url路径+参数 如:请求http://127.0.0.1:8001/login.html?a=1&value2=222 request.get_full_path() #结果login.html?a=1&value2=222
6.3 response
HttpResponse("string") #响应字符串,如return HttpResponse("OK") render(request,template_name) #返回模板,如return render(request,'login.html') redirect(to_url) #重定向到指定url,如return redirect('/app01/login.html')
七、Template模板语法
7.1 变量
格式:{{ 变量}}
#1.深度查询 {{ L.0 }} #L为列表,0表示取列表第一个元素 {{ dic.name }} #dic为字典,name表示取key,结果输出value {{ person_class.name }} #person_class为类,name为类属性 #2.过滤器 格式:{{ val|filter_name:param }} 加法过滤器: {{ num|add:20 }} //num +=20 时间过滤器: {{ value|date:"Y-m-d h:i" }} #view视图里必须是使用datetime模块 默认显示过滤器: {{ book_list|default:"没有符合条件的书籍" }} #book_list为空列表,则输出default值 文件大小友好转化 {{ file_size|filesizeformat }} #将文件大小自动转成人类可读,如‘10KB’,'25.5MB'等等 关闭自动转义:禁止将标签转义成字符串 views视图: value='<a href="">点击</a>' template: {{ value|safe }} 返回长度,对字符串和列表斗气作用 {{ value|length }}
切片过滤器
{{ value|slice:"2:-1" }} #加入value是字符串,从第3个字符到倒数第一个
7.2 标签
格式:{% tag %}
7.2.1 for标签
{% for i in l %} <!--循环列表--> <div>{{ i }}</div> {% endfor %} ps:可利用{% for i in l reversed %} ,反向循环 {% for key,value in dic.items%} <!--循环字典--> <div>{{ key }}:{{ value }}</div> {% endfor %}
注意:循环序号可以通过{{forloop}}显示,相当于python里的enumerate()函数
forloop.counter <!--从索引1开始--> forloop.counter0 <!--从索引0开始--> forloop.revcounter <!--索引从大到小,最小是1--> forloop.revcounter0 <!--索引从大到小,最小是0--> forloop.first <!--判断是否是第一个元素,是返回True,不是返回False--> forloop.last <!--判断是否是最后一个元素,是返回True,不是返回False-->
for....empty搭配
for标签带有一个可选的{% empty %}从句,以便在给出的组是空的或者没有找到时,可以有所操作
{% for i in l %} <div>{{ forloop.last }} : {{ i }}</div> {% empty %} <div>此列表为空</div> {% endfor %}
7.2.2 if标签
{% if l %} <!--l列表不为空--> <div>{{ l | length }}</div>
{% elif dic %}
<div>{{ dic | length }}</div>
{% else %}
<div>没有</div> {% endif %}
7.2.3 自定义标签和过滤器
- settings中的INSTALLED_APPS配置当前app,不然django无法找到自定义simple_tag
- 在app中创建templatetags包文件夹(模块名只能是templatetags)
- 在templatetags包文件夹下创建任意.py文件,如:my_tags.py,如下
from django import template from django.utils.safestring import mark_safe register = template.Library() #定义俩数相乘 @register.filter def filter_multi(v1,v2): return v1 * v2 @register.simple_tag def simple_tag_multi(v1,v2): return v1 * v2 @register.simple_tag def my_input(id,arg): result = "<input type='text' id='%s' class='%s' />"%(id,arg,) return mark_safe(result)
- 在使用自定义simple_tag和filter的html文件中导入之前创建的my_tags.py
{% load my_tags %}
- 使用simple_tag和filter
{% load my_tags %} <div>{{ num|filter_multi:2 }}</div> <!--假如num=20,结果:40--> <div>{{ num|filter_multi:"[22,11,2]" }}</div> <!--假如num=20,结果:重复20个[22,11,2]列表--> <div>{% simple_tag_multi 2 5 %}</div> <!--结果:10--> <div>{% my_input "user" "user_content" %}</div>
- 注意:filter可以用在if等语句后,simple_tag不可以,如
{% if num|filter_multi:30 > 100 %} <div>{{ num|filter_multi:30 }}</div> {% endif %}
- 7.3 简单示例
#在view.py视图中 def login(request): if request.method =='GET': l= ['a','c','b','d'] # l= [] num =20 return render(request,'login.html',{'l':l,"num":num}) else: print(request.POST.dict()) return HttpResponse('OK')
#在template文件里的html文件<!--xx--> <div>{{ num }}</div> <!--结果:num=20--> <div>{{ l | slice:"2:-1" }}</div> <!--将列表l从第3个元素到倒数第一个进行切片,序号从0开始,取值范围[2,-1)--> <div>{{ num|filter_multi:2 }}</div> <!--使用自定义模板过滤器,求乘积,结果为40--> {% for i in l %} <!--循环--> <div>{{ forloop.last }} : {{ i }}</div> {% empty %} <div>此列表为空</div> {% endfor %} {% if l %} <!--判断--> <div>{{ l | length }}</div> {% endif %}
- 7.4 模板的继承
#介绍 假如有三个网页(分别为a,b,c.html),他们的头部header和左边的导航栏都是固定不变的,只有中间的内容块是变化的,
我们可以将不变的部分制作成模板,在此命名为base.html<!--base.html 母版---> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{% block title %}默认标题{% endblock %}</title> <style> *{ margin: 0; } #header{ width: 970px; height: 30px; background-color: aqua; } #main{ width:970px; height: 1000px; } #left{ float:left; width:300px; height: 1000px; background-color: aquamarine; } #content{ float:left; width: 670px; height: 100%; background-color: red; } </style> </head> <body> <div id="header">头部</div> <div id="main"> <div id="left">左半部</div> <div id="content"> {% block content %} 默认内容 {% endblock %} </div> </div> </body> </html>
<!--子板 A.html--> {% extends "base.html" %} {% block title %}A网页{% endblock title %} {% block content %} <h1>A网页的内容1</h1> <h1>A网页的内容2</h1> <h1>A网页的内容3</h1> {% endblock content %}
八、ORM单表操作
8.1 建立sql基本数据源
测试数据
#参考"三、Django的基础创建"中数据库配置(MySql)部分
8.2 创建表数据
#方式一 ##create方法的返回值为book_obj对象 from app01.models import * def query(request): import datetime now = datetime.datetime.now() #pub_data的格式只能是'年-月-日 时:分:秒',可以不那么详细,但是一定要按标准格式 #pub_data的值,可以由datetime模块里的datetime.datetime.now()来作为值 #返回的值是创建书的对象book_obj book_obj = Book.objects.create(name='三国演义',pub_data='2010-08-11',price=99.99,publish='人民出版社',create_date=now) return HttpResponse('ok') #方式二 from app01.models import * def query(request): import datetime now = datetime.datetime.now() #创建数据命令以下俩条 book_obj = Book(name='水浒传3',pub_data='2010-05-10',price=122,publish='机械工业出版社',create_date=now) book_obj.save() return HttpResponse('ok')
8.3查询表数据
book_obj = Book.objects.方法 关于常用查询方法: all() #查询所有结果,返回的QuerySet对象 filter(**kwargs) #查询符合条件的结果,返回QuerySet对象 get(**kwargs) #返回符合条件的结果,返回结果有且只能有一个,没有或者大于1条符合的,都会抛出异常,返回Book对象 exclude(**kwargs) #查询指定条件外的所有结果,返回QuerySet对象 order_by(*field) #对QuerySet对象进行排序,*field为指定数据表中的列名,如'name',或者'price'等等,默认是升序,返回的结果是QuerySet对象 reverse() #对QuerySet对象进行反序,返回结果是QuerySet对象,可与order_by(*field)配合使用 count() #返回数据库匹配到符合对象的数量,返回结果int类型 first() #返回queryset对象里第一条符合的book_obj对象 last() #返回queryset对象里最后一条符合的book_obj对象 exists() #如果queryset对象里有符合的数据,就返回True,否则返回False values(*field) #对Queryset对象进行符合列名显示,返回结果是QuerySet对象,但是不同的是列表元素是字典,取值的时候不是加点.,而是dic['name'],见'测试数据'示例 values_llist(*field) #与values(*field)相似,差别是上面返回的是字典,而这里返回的是元组 distinct() #去重,要针对某个字段去重,可配合values(*field)使用,见“测试数据”示例,返回结果queryset对象
#在views.py里 from django.shortcuts import render,HttpResponse,redirect from app01.models import * def query(request): #查询整张表信息 # queryset_obj = Book.objects.all() # print(queryset_obj) # print(type(queryset_obj),dir(queryset_obj)) # for book_obj in book_obj: # print (book_obj.name,book_obj.create_date) #查询书名为三国演义所有信息 # queryset_obj = Book.objects.filter(name='三国演义') # print(queryset_obj) # print(type(queryset_obj),dir(queryset_obj)) # for book_obj in queryset_obj: # print (book_obj.name,book_obj.create_date) #查询书名为水浒传 # book_obj = Book.objects.get(name='水浒传') # print(book_obj) # print(type(book_obj),dir(book_obj)) # print(book_obj.name,book_obj.create_date) #查询除三国演义外的所有信息 # queryset_obj = Book.objects.exclude(name='三国演义') # print(queryset_obj) # print(type(queryset_obj),dir(queryset_obj)) # for book_obj in queryset_obj: # print (book_obj.name,book_obj.create_date) #查询除三国演义外的所有信息,并对结果进行升序 # queryset_obj = Book.objects.exclude(name='三国演义').order_by('price') # print(queryset_obj) # print(type(queryset_obj),dir(queryset_obj)) # for book_obj in queryset_obj: # print (book_obj.name,book_obj.create_date) # queryset_obj = Book.objects.order_by('name').reverse() # print(queryset_obj) # print(type(queryset_obj),dir(queryset_obj)) # for book_obj in queryset_obj: # print (book_obj.name,book_obj.create_date) # book_int = Book.objects.all().count() # print(book_int) # print(type(book_int), dir(book_int)) # book_obj = Book.objects.all().exists() # print(book_obj) # print(type(book_obj), dir(book_obj)) # queryset_obj = Book.objects.all().values('name','publish','pub_data') # print(queryset_obj) # print(type(queryset_obj), dir(queryset_obj)) # for i in queryset_obj: # print(i['name'],i['publish'],i['pub_data']) # queryset_obj = Book.objects.all().values_list('name','publish','pub_data') # print(queryset_obj) # print(type(queryset_obj), dir(queryset_obj)) # for i in queryset_obj: # print(i[0],i[1],i[2]) queryset_obj = Book.objects.all().values('name').distinct() print(queryset_obj) print(type(queryset_obj), dir(queryset_obj)) for i in queryset_obj: print(i) return HttpResponse('ok')
基于双下划线的模糊查询