web框架-Django(简介,请求基本周期、路由层、视图函数、模板层、模型层,CBV&FBV)
Django简介、基本使用项目创建于app创建、请求执行的周期(基本)、路由系统、视图函数、模板层、模型层、
参考网址,https://www.cnblogs.com/clschao/articles/10526431.html
- pip安装,配置环境变量 ……python\script django-admin
- 创建工程项目
- 方式一:cmd命令行 django-admin startproject 项目名
- 方式二:IDE,pycharm中创建django项目
- 在使用pycharm过程中,需要设置django server:
- 名字是项目名字
- 默认ip,端口
- environment variable: DJANGO_SETTINGS_MODULE 工程项目名.settings PYTHONUNBUFFERED : 1
- python解释器
- 在使用pycharm过程中,需要设置django server:
- 运行:
- 命令行中, python manage.py runserver 指定host:端口 host和端口可省略,使用默认
- pycharm中完成配置。 在“select run /debug configuration” 中选定配置好的django ,点击运行
- django项目目录结构:
- 与项目同名的文件夹 :完成程序的整体配置
- init
- settings :配置文件
- TEMPLATES 进行模板文件配置,设置模板文件的查找路径等。
- STATIC_URL 静态路径
- STATICFILES_DIRS 静态文件路径配置,设置css,js等静态文件路径信息
- urls :url对应关系
- wsji :wsgi规范
- manage.py :管理django程序
- python manage.py 运行
- python manage.py startapp 程序名
- python manage.py makemigrations
- python manage.py migrate
- 创建app
- 在cmd命令行中,进入工程项目目录, python manage.py startapp 指定app名
- windows python中可通过 Teminal 运行上面的命令
- 常见app :cmdb templates openstack……
- app内部结构文件功能(cmdb):
- migrations: 数据修改表结构
- 内部有django自动创建的数据库修改表结构的操作记录,注意,仅记录了对表结构的修改,数据库中的记录的操作,不记录。
- __init__ 把文件夹转成包
- admin django为我们提供的后台管理
- 包括了登录、添加、删除、权限管理等基本功能。
- apps 配置当前app
- models: ORM,写入指定的类,通过命令创建和修改数据库结构
- tests: 单元测试
- views: 和cmdb相关的所有业务,业务逻辑代码
- migrations: 数据修改表结构
- 不同文件、模块间的调用过程中,注意核实settings中环境的配置
- 配置模板的路径
- 在settings中,DIRS:[os.path.join(BASE_DIR,"模板包名字")] 一般的是templates
- 配置静态文件的路径
- 在settings中,STATIC_DIR后面,加上STATICFILES_DIRS = (os.path.join(BASE_DIR,"静态文件名字"),) 一般地静态文件名为static
- django项目创建步骤
- 1 创建django工程 django-admin startproject 工程项目名
- 2 创建app cd工程文件夹 python manage.py startapp app名
- 3 静态文件配置
- 静态网页,静态网页是相对于动态网页而言,是指没有后台数据库、不含程序和不可交互的网页。
- 静态网页优势:可以公开(即副本可以证明给任何人)。托管没得任何特殊的要求。(不需要特殊的中间软件比如超文本预处理器、公共网关接口)没得网络服务器或应用服务器,比如直接从CD-ROM(激光唱片-只读存储器)或USB闪存驱动器读取内容,可以通过网络浏览器直接访问。网站更安全,HTML页面不会受Asp相关漏洞的影响;而且可以减少攻击,防SQL注入。数据库出错时,不影响网站正常访问。不需要编译,所以速度快,节省服务器资源。网址格式友好,搜索引擎容易识别。内容是固定的,交互性差,内容更新维护复杂。没有自动化的工具,维护大量的静态页面文件是不现实的。无法充分支持用户/客户的需求(外观选择,浏览器的支持,Cookie)。
- 静态文件,一般是指css,js,img等类似的,让html直接引用的,可以直接暴露给用户的文件即归为静态文件.
- 静态文件配置方式:
- 方式一:
- 在settings文件下,配置文件中已经有了静态文件的别名,STATIC_URL='/static/' 在这之后添加 STATICFILES_DIRS=[os.path.join(BASE_DIR,' ')] .使用的时候,用别名static.
- 方式一:
- 静态网页,静态网页是相对于动态网页而言,是指没有后台数据库、不含程序和不可交互的网页。
- 4 模板配置
-
- 5 csrf
- 6 定义路由规则 urls.py 请求字段——》响应函数名(视图函数、)
-
urlpatterns=[ ]
-
- 7 定义视图函数 app 下 views 判断数据发送方式,通过request拿数据,数据处理,数据返回
- HttpResponse-传字符串、 HttpResposnse(" 字符串 ")
- render-传HTML模板路径、 render(request ,"abc.html",{ 替换形式字典 })
- redirect-传 /URL) redirect(' /abc/ddd ')
- 基本周期
- 请求 一般情况下,GET方式用来获取数据,POST用于提交数据。其他的提交方式还有PUT/DELET等
- 路由关系映射
- 视图函数
- 数据 html模板
- 渲染以后返回给用户
- 完整周期:
- 常见的url匹配规则:
- 1 一 一对应静态匹配,url('index/',views.index) url('home/',views.Home.as_view()) 在设置路由关系时字段内容最后要加上$终止符,否则在匹配过程中,会由于不是截止的精确匹配,因而前后优先级导致匹配错乱。 例如,url('index/$',views.index)
- 2 利用正则实现动态匹配(类似传递位置参数) url(r'detail-(\d+).html',views.detail)
- 正则当中使用分组的情况下,会有二次匹配的情况,传递的参数会将所有的结果都传到视图函数中.
- 3 利用正则表达式的分组实现(在函数调用时,参数以关键字形式传递) url(r“detail-(?p<nid>\d+)-(?p<uid>\d+).html”,views.detail)此url路由匹配规则在传递获取的参数时,会以nid=***,uid=***进行传递 为了方便,在views定义视图函数的时候,直接用不定长参数*args,**kwargs定义。
- 注意
- 要想从路径中捕获某些信息,只需要在对应的正则内容上面加分组,进行二次匹配
- 使用正则的时候,前面开始的反斜杠不用加,会自动添加
- 正则表达式前面的r虽然是可选项,但一般情况下最好是加上.
- 由于路由系统的匹配顺序是自上而下的顺序匹配,所以,在正常的匹配规则最后,最好是加上 ‘$’ 终止符,做精准匹配,防止出现上面的url匹配规则把某类的匹配全部截获,下面的匹配规则得不到有效执行。
- 获取当前url信息,request.path_info
- 路由分发,主要的目的是实现不同app之间进行解耦.当请求到顶级(项目同名)url的时候,通过include,根据请求的关键字,对请求进行一个分发,同时在不同的app中建立局部的urls文件,避免不同app之间urls放在一起,增强系统的易读易维护性。 顶级url负责分发, 例如, url("monitor/",include("app003.urls")),url("cmdb/",include("app06.urls"))
- 首先 from urls import include
- 前面的匹配规则可以用正则,也可以为空,当为空的时候,会直接到各个app中进行进一步匹配.
- 路由的反向解析
- 目的是不在代码中把url写死,而是通过反向查询动态获取。
- 主要应用方式:
- 在模板中,利用{%url '路由中给匹配规则起得别名' %}
- 在视图函数中,reverse的应用,利用reverse函数,可以根据路由名称(别名),返回具体的路径。注意当路由中有正则表达式时,需要把代替填充的内容一并传递过去。
- url默认值,在路由系统中,可以给视图函数传递默认值,此时,需要保证视图函数有对应的形参用于接收默认值。 例如 url("index/",views.index,{"name":"root"}) ,这时候,index视图函数的name参数会接收路由调用时自动传递过来的默认值root。
- url命名空间。使用反向解析的时候,在路由分发的情况中,如果出现不同的url指向相同函数并且url所定义的别名相同等情况(例如不同app定义的url匹配规则,虽然在不同的app中,但定义别名一致时命名相同),单纯使用url的name没有办法得到确切的url路径,这时需要同时利用url的name,和定义路由时所一并定义命名空间。 定义命名空间的基本语法 url(“a/”,include("app01.urls",namespace="a1")) url(“b/”,include("app01.urls",namespace="b1")) 通过reverse( ‘ 命名空间namespace:路由name ’ ) 可以确定url路径
- url, re_path, path
- re_path实际上就是之前的版本中的url方法,一般是结合正则表达式使用
- 一般情况下,使用url、repath进行匹配后,如果规则中有正则并且分组的话,匹配出来的分组内容实际上是以字符串形式,传递给视图函数的。另外,如果正则表达式中出现有名分组,需要对捕获到的内容进行类型强转。上述情况在django2.0以上的版本适合用path方法
- path方法,与转化器
- path方法配合上内置的转化器,可以方便的将前端的数字等类型,传到后端。
- 转化器基本使用语法 path(' 包含转换器的url规则 ',视图函数,别名) 注意转换器是用尖括号包裹的<匹配转换器类型:分组名称>,同样的,url规则不需要前导斜杠。
- 当前内置的转换器,有int,str,uuid, slug, path
- 自定义转化器
- 定义转换器类
- regex 类属性,字符串类型
- to_python(self, value) 方法,value是由类属性 regex 所匹配到的字符串,返回具体的Python变量值,以供Django传递到对应的视图函数中。
- to_url(self, value) 方法,和 to_python 相反,value是一个具体的Python变量值,返回其字符串,通常用于url反向引用。
-
View Code1 # 新建py文件 2 class FourDigitYearConverter: 3 regex = '[0-9]{4}' 4 def to_python(self, value): 5 return int(value) 6 def to_url(self, value): 7 return '%04d' % value
- 进行url配置注册
- 使用register_converter 将其注册到URL配置中
-
View Code1 from django.urls import register_converter, path 2 from . import converters, views 3 register_converter(converters.FourDigitYearConverter, 'yyyy') 4 urlpatterns = [ 5 path('articles/2003/', views.special_case_2003), 6 path('articles/<yyyy:year>/', views.year_archive), 7 ... 8 ]
- 定义转换器类
- 本质上就是一个python函数,但必须有返回值,也就是必须有return,返回内容是按规定的格式。一般是存放在views.py文件中。
- 视图函数操作的对象,可以简单的分为请求对象、响应对象两部分,其中request就是请求对象,封装了前端发过来的请求信息。响应对象有HTTPResponse、render方法本质上是对响应内容的封装并以HTTPresponse对象形式返回、
- 后台数据获取
- request是前端数据的打包
- 常用的request的属性
- request.path_info 获取当前url中的【路径信息】
- request.method 拿到当前请求的请求方式,常见的有POST,GET,PULL,PUT等。常用于视图函数判断请求方式
- request.body 用户发起请求报文的请求体,通过请求体的原始数据,能够解析出请求体中的所有信息。例如,前段发起的ajax请求,如果发送的json数据,此时,contentType不是urlencoded,request.POST等是解析不出来的
- request.GET,首先通过消息头中的contentType==‘urlencoded’,然后解析出路径中的参数信息
- request.POST,首先通过消息头中的contentType==‘urlencoded’,解析出请求体中携带的参数信息,存储post请求信息
- request.FILES ,解析并存储文件信息
- 一般情况下,GET方式用来获取数据,POST用于提交数据。其他的提交方式还有PUT/DELET等
- 常用的request的方法
- request.Meta()
- request.get_full_path() 获得当前url中的 【路径信息】和【请求参数信息】
- request.POST.get() 获取指定的参数信息
- request.GET.get() 获取指定的url参数信息
- request.POST.getlist() 当提交的数据包含复选框等并列内容时,用getlist可以统一接收。
- request.FILES.get()
- 要上传文件,需要在form标签中,需要做设置,enctype='multipart/form-data'
- 上传文件时,FILES.get()获取上传的文件对象的属性信息。
- request.FILES.size()
- request.FILES.chunks()
- 分段获取的,上传的文件内容。需要读取文件内容的话,需要对FILES.chunks()进行循环。
- request中封装了url请求的所有原生信息,实际上是以类的形式存在的
- 要查看请求体的详细信息,需要导入WSGIRequest , from django.core.handlers.wsgi import WSGIRequest
- request.environ 可以拿到请求体的完整信息,字典形式存放的
- request.environ[ ] 可以拿到指定的信息内容, 例如,request.environ['HTTP_USER_AGENT']
- reverse函数,可以根据路由的名称,反向解析出完整的路由信息。
- 导入,from django.urls import reverse
- 对于未指明namespace的, reverse(路由name); 对于指明namespace的, reverse(命名空间namespace:路由name)
- 返回内容
- 包含django的模板标签的html文件,并非真正的html文件(浏览器是不能对这种文件直接进行解析的),render方法是在传输响应信息前对模板文件进行了数据渲染,替换掉了模板标签。
- return HttpResponse() 返回简单字符串 return render(request," html文件",{ 替换内容 })返回取到数据渲染后的html文件内容 return redirect( ' 重定向 url ' )
- 数据返回的时候,cookie的设置内容是通过响应头传递回去的
- FBV(function base views) 与 CBV(class base views)
- FBV 由url直接对应(映射)函数名, CBV 由url直接对应(映射)到指定的类。
- CBV 本质上,通过dispatch反射,实现根据数据请求的发送方式选择不同方法执行。执行对应请求的方法前会优先执行 dispatch 方法(在get/post/put...方法前执行),dispatch() 方法会根据请求的不同调用相应的方法来处理。其实,Django 的 url 是将一个请求分配给可调用的函数的,而不是一个类,要实现基于类的视图, 主要还是通过父类 View 提供的一个静态方法 as_view() ,as_view 方法是基于类的外部接口, 他返回一个视图函数,调用后请求会传递给 dispatch 方法,dispatch 方法再根据不同请求来处理不同的方法。
- CBV方式,可以通过重写dispatch,实现自定制功能。
- FBV代码示例
-
urls.pyurlpatterns = [ path("login/", views.login), ]
View Codefrom django.shortcuts import render,HttpResponse def login(request): if request.method == "GET": return HttpResponse("GET 方法") if request.method == "POST": user = request.POST.get("user") pwd = request.POST.get("pwd") if user == "runoob" and pwd == "123456": return HttpResponse("POST 方法") else: return HttpResponse("POST 方法1")
-
-
CBV代码示例
-
urls.pyurlpatterns = [ path("login/", views.Login.as_view()), ]
views.pyfrom django.shortcuts import render,HttpResponse from django.views import View class Login(View): def get(self,request): return HttpResponse("GET 方法") def post(self,request): user = request.POST.get("user") pwd = request.POST.get("pwd") if user == "runoob" and pwd == "123456": return HttpResponse("POST 方法") else: return HttpResponse("POST 方法 1")
-
- 装饰器(定义方式是一样的,调用方式不一致)
- 基于FBV的
-
View Code1 #---------基于FBV的装饰器实现COOKIE登录验证----------- 2 3 def auth(func): 4 def inner(request,*args,**kwargs): 5 v = request.COOKIES.get("user111") 6 if not v: 7 return redirect('/login/') 8 return func(request,*args,**kwargs) 9 return inner 10 11 @auth 12 def func01(request): 13 return HttpResponse("hello world")
- 基于CBV的
- 基于CBV的视图函数,加装饰器时,需要导入模块 from django.utils.decorators import method_decorator 然后通过@method_decorator(auth)加装饰器
- 具体调用方式:
- 方式一,可以直接对类函数进行装饰
- 方式二:对类里的方法全都装饰的情况下,可以利用dispatch函数。重写dispath函数,并加上装饰器,用super(类,self).dispatch(request,*args,**kwargs)进行正常的方法执行,在此执行的前后,可以自定义部分功能,实现装饰器的功能。
- 方式三:直接在类名上面加装饰器,本质上,方式三是对方式二的简化
-
View Code1 #---------基于CBV的装饰器实现COOKIE登录验证----------- 2 3 def auth(func): 4 def inner(request,*args,**kwargs): 5 v = request.COOKIES.get("user111") 6 if not v: 7 return redirect('/login/') 8 return func(request,*args,**kwargs) 9 return inner 10 11 @method_decorator(auth,name="dispatch") #方式三 12 class Order(views.View): 13 14 @method_decorator(auth) #方式二 15 def dispatch(self,request,*args,**kwargs): 16 return super(Order,self).dispatch(request,*args,**kwargs) 17 18 @method_decorator(auth) #方式一 19 def func1(self,request): 20 return HttpResponse("hello world普通函数")
- django默认的搜索模板的顺序是,先到project目录的Templates中搜索,如果没有,则根据settings中app的注册顺序,依次搜索。所有的静态文件的搜索都是按这个顺序执行。
- 模板基础语法只有 {{ }} 和 {% %} 两种。前者是用于传递渲染变量用的,后者是用于渲染标签的。
- 可以直接定义html,然后实现在视图函数中进行调用
- 变量的渲染与使用
- 变量的渲染是通过 {{ }} 实现的。
- 使用方式:
- 模板中用 {{ }} 定义好变量的位置
- 在视图函数中,使用render方法进行变量传递,如果是传递单个变量,可以直接以字典形式在render方法中用第三个参数传递过去,如果是变量比较多,即可以一个个的传递,也可以通过locals()方法,把视图函数中的变量打包成指定格式传递到模板中。
- 深度查询
- 在传递的变量是列表、字典、对象等类型的数据时,直接在模板中用 “ 。 ” 对需要的内容进行深度查询,从而拿到相应的内容。
- 过滤器,即函数的使用
- {{ 变量 | 内置函数:参数 }}
- 常用的内置函数(内置过滤器)
- data 定制时间显示格式,{{mydata | data:'Y-m'}} 日期显示格式为年-月
- default 定制默认显示内容,当没有接收到变量的时候,如果没有默认内容,变量的位置直接为空
- filesizeformat 格式化输出文件大小 {{ myfile | filesizeformat }} 将文件的大小直接按标准格式显示出来
- slice 切片
- truncatechars 按字节进行内容截断
- truncatewords 按单词截断
- safe 安全解析标志,在正常情况下,如果是传递包括<>的内容时,django会先通过html特殊符号对照表,对内容进行编译再传递,目的是防止不安全代码注入。
- 通过safe过滤器,把传递的内容标注为安全的,django会把这部分内容正常写入html文件,交给客户端浏览器解析,显示成正常标签内容。
- add,
- upper
- 标签的渲染和使用
- {% %} 渲染控制语句,基本的逻辑控制语法如下:
- for循环基本语法:
- {%for 条件 %} 循环体 {% endfor %}
- {%for 条件 %} 循环体 {%empty%}当遍历到的内容为空时的执行语句 {% endfor %}
- {{forloop}}可以拿到当前循环的次数,即循环的序列号。使用时直接 forloop.count,另外还有forloop.count0从0开始计数,forloop.revcounter ,forloop.revcounter0 ,forloop.last是否最后一个,forloop.first是否第一次循环。 当出现嵌套循环的时候, forloop.parentloop将每次循环过程中,父循环的上述6个参数打包。
- 条件语句基本语法
- {%if 条件%} 满足条件情况下执行的函数体或显示的标签内容 {%else 条件 %} 不满足条件时,执行或显示的内容 with as 当正常的变量名或深度查询等特别长不方便使用的时候,创建简写
- {%with 正常的变量或深度查询等 as 简写内容%} 逻辑语句 {%endwith%}
- {%csrf_token%}标签
- 在form表单中,加入{%csrf_token%},这样在渲染的时候,django会在页面中,加上一个csrf_token标签,用于进行中间件检测。
- for循环基本语法:
- {% %} 渲染控制语句,基本的逻辑控制语法如下:
- 自定义函数(过滤器)或标签
- a. app下创建templatetags目录
- b. 创建py文件
- c. 自定义标签,导入模块 from django import template from django.utils.safestring import mark_safe 创建template对象,得到register 实例化自template.Library。名字必须是register不能用其他的。
- d. 自定义过滤器,加装饰器@register.filter,如果是自定义标签,此时加装饰器 @register.simple_tag,
- e. settings中注册当前app
- f. 在引用文件顶部导入函数文件 { % load 函数所在的py文件名 % },
- g. 执行自定义过滤器或标签
- 执行标签 { % 自定义标签名 参数1 参数2 …… % }
- 调用自定义函数(过滤器)的时候格式类似调用python内置函数,{{参数|函数名:其他参数}} 当传的参数较多时,用字符串, {{参数 | 函数名:“参数二,参数三,”}}。这种方式的缺点是,参数数量有限制,函数名后最多放两个参数,并且元素之间不能有空格。优点是结合{%if 变量| 自定义函数:参数 执行条件%} 实现if判断条件,放在 template 模板流程控制中。如果参数再多的情况,则直接使用自定义标签完成。
- 继承、组件。
- 继承,在布局重复的情况下,可以使用html母版,通过继承母版的设置,提高程序的可读性、易维护性,降低维护成本
- 使用方式:
- 1 定义布局母版html ,在母版中用{%block 模块名字%}{%endblock%}定义可以替换的模块及其位置。
- 2 在引用html文件中,声明引用的母版 {%extends “布局母版html文件名字”% }
- 3 定义好当前html文件用于替换布局母版的内容。 {%block 模块名字%}自定义的内容{%endblock%}
- 4 在具体页面中还有特有的css,js的情况,在母版中留出自定制css,js的位置,一般可以在模板的style位置后加入css的block,在js包括jquery位置加js的block,在具体页面中用自定义替换即可
- 使用继承的注意事项:
- extends标签必须在引用文件的首行
- 在带引用的母版文件中,{%block 模块名字%}{%endblock%}越多越好,可以理解为越多情况下的可改造程度越高。
- 一般情况下,子版中写入内容后,会直接把母版中的{%block 模块名字%}默认内容{%endblock%},其中的默认内容直接用子版定义的内容替换掉。如果想在母版内容保留的前提下,添加内容,可以在定义子版内容的时候,加一个{{ block.super }} 的标签。
- 一个html页面,只能继承一个母版。可以理解为电脑的主板,页面的整体框架,可以从母版中继承过来。
- 使用方式:
- 组件,对于页面中的重复布局,可以使用组件,提高程序的可读性、易维护性,降低维护成本
- 1 定义组件html文件
- 2 在具体html文件中,用include对组件进行引用 基本语法,{%include ' 引用组件的html文件名称 '%}
- 组件可以理解可插拔设备。
- 对于继承的母版、页面引用的组件,django会在进行渲染之前,先把这些内容都拿过来,生成一个完成的模板文件,然后再融入数据库替换的数据,最后在进行渲染。
- 当模板html文件中,既有extend继承,又有load时,必须将load放在extend之后,主要原因是extend继承过来的是模板文件的整体框架。
- 继承,在布局重复的情况下,可以使用html母版,通过继承母版的设置,提高程序的可读性、易维护性,降低维护成本
Models,数据库操作(ORM)
- 主流ORM可以分成 db first (需要先自己登陆数据库建立表结构,此后经过执行会自动创建相应的类,对表结构进行操作的时候,可以直接对这些类进行操作来完成),code first(先写代码,创建需要的各种类,然后通过执行语句,利用创建的类创建数据库表)两类。主流的orm是code first类型。
- 当前django提供的ORM,只能完成对数据库中的表进行操作,数据库层面上的操作,还需要在数据库层面上进行布局。
- 另外需要注意的是,py3.x 的解释器进行数据库操作的时候,django默认的数据库驱动接口是mysqldb,而py3.x 用的数据库驱动接口是pymysql,所以需要使用前对驱动接口进行设置,在项目名文件目录下的init文件中,写入如下内容:
-
import pymysql pymysql.install_as_MySQLdb()
-
-
创建数据表类
-
根据类创建数据表
- 在app下,models.py中,创建类,继承models.Model。注意,models.py命名不能改,否则会报错
- 通过类创建表
- 在类中,通过models的方法,定义字段,其中可选属性null=True,定义可以为空。例如 username=models.CharField(max_length=32)
- 创建字段的方法,分为三大类,字符串、数字、时间、二进制,常用的有:CharField定义一般的字符串 IntegerField定义数字 DateField定义日期 DateTimeField定义时间 EmailField 定义邮箱格式 GenericIPAddressField定义IP类型 URLField定义URL AutoField定义自增列,必须加属性primary_key=True
- 需要注意的是,EmailField、URLField、GenericlPAddressField等类型,基本上是在使用django提供的admin时才能用得上,一般情况下,就用CharField定义一般的字符串 IntegerField定义数字 DateField定义日期 AutoField定义自增列,必须加属性primary_key=True
- 字段的常用参数有: null——》是否为空,default——》默认值,primary_key——》主键,db_column列名,db_index——》索引,uique——》唯一索引,unique_for_date,unique_for_mounth,unique_for_year,auto_now——》创建时,自动获取时间,auto_now_add——》更新时,自动获取当前时间,需要注意的是,使用update对数据进行更新的时候,这种操作的时间不会记录更新,只有用 ‘=’ 重新赋值,然后save的操作才会记录更新时间。choices——》元组形式定义分组,把内容放在内存中,运行的时候admin中显示的下拉框,实现了连表查询的显示效果,并且避免了连表查询的低效率。 blank——》在admin中,定义是否为空 verbose_name——》在admin中设置是否为中文 editable——》设置admin中是否可编辑 error_messages——》错误提示 help_text——》在admin中提示信息 validators——》自定义错误信息 protocol用于GenericIPAddressField设置ip协议类型
- settings中,INSTALLED_APPS中,注册app
- 通过manage创建表结构, python manage.py makemigrations 注意,在创建之前,需要把在settings中,把当前app名加入INSTALLED_APPS
- 用django默认的数据库是sqlite,如果用mysql,需要,1 在settings中,把数据库引擎设置修改,
#DATABASES = {
# 'default': {
# 'ENGINE': 'django.db.backends.mysql',
# 'NAME': 'dbname',
# 'USER':'root',
# 'PASSWORD':'mysql',
# 'HOST':'',
# 'PORT':'',
# }
# } - 另外,需要注意的是,利用django使用mysql时引擎默认是用的mysqldb,但是,当前python3.x中,还没有mysqldb。需要在和【项目同名】的文件夹下,__init__文件中,设置
#import pymysql
# pymysql.install_as_MySQLdb() - 当使用py3.x解释器,跑django2.0版本的时候,会报错,django.core.exceptions.ImproperlyConfigured,即版本错误。这时,需要在解释器程序中Python\Python36-32\Lib\site-packages\Django-2.0-py3.6.egg\django\db\backends\mysql 这个目录下对下面的内容注释掉
-
if version < (1, 3, 3): raise ImproperlyConfigured("mysqlclient 1.3.3 or newer is required; you have %s" % Database.__version__)
-
- 执行migrate命令,在数据库中创建表,类似于数据库的确认操作, python manage.py migrage
- 如果要查看orm执行的sql语句,可以进行settigns中设置后打印,
-
View Code1 LOGGING = { 2 'version': 1, 3 'disable_existing_loggers': False, 4 'handlers': { 5 'console':{ 6 'level':'DEBUG', 7 'class':'logging.StreamHandler', 8 }, 9 }, 10 'loggers': { 11 'django.db.backends': { 12 'handlers': ['console'], 13 'propagate': True, 14 'level':'DEBUG', 15 }, 16 } 17 }
-
- 对数据库的表单结构修改(字段内容)后,即对定义表的类进行修改以后,用manage.py 执行makemigrations,migrate命令进行确认操作。
-
- 数据库单表操作与多表操作(外键),增删改查
- 单表操作
- 根据类对数据库表中的数据进行各种操作,注意:增加、更新、查询传递参数时,都可以通过 ** 传递字典进行操作
- 增加:
- 方式一,直接创建 models . 表名 .objects.create(字段1:数值,字段2……) 当字段较多,可以先建一个存储信息的字典,然后把字典穿进去,当传递字典时,需要在字典名前加 ** models . 表名 .objects.create(**字典名) 执行的时候是有返回值的,返回的是创建的记录对象。
- 方式二,通过创建一个对象信息,然后把保存对象 obj=models . 表名(字段1:数值,字段2……) obj.save() 执行的时候是有返回值的,返回的是创建的记录对象。
- 当定义字段时,使用models.EmailField() models.GenericIPAddressField()等特殊格式时,如果用 create创建,或者用update更新,都不会有格式验证。只有在执行django admin时会有格式验证。
- 查询:
- models.表名.objects 拿到的是一个可以对表进行操作的句柄。
- all()拿到的是对象形式存储信息的QuerySet(形式上类似于列表) models.数据表名.objects.all()
- 对于查询的结果,可以通过 .order_by()进行排序 models.数据表名.objects.all().order_by() models.UserInfo.objects.filter(id__gt=1).order_by()
- .first() 结果中的第一个 .count()对结果进行计数 .last() 结果中的最后一个
- 利用filter添加where查询条件,结果也是以QuerySet存储 models.数据表名.objects.filter(筛选条件),可以通过“__”实现逻辑模糊查询。gt->greater than,gte->greater than or equal,lt->less than ,lte->less than or equal
- models.UserInfo.objects.filter(id=1) # 拿到id=1的对象,结果是queryset
- models.UserInfo.objects.filter(id__gt=1) # 拿到id大于1的对象,结果是queryset
- models.UserInfo.objects.filter(id__lt=1) # 拿到id小于1的对象,结果是queryset
- models.UserInfo.objects.filter(id__gte=1) # 拿到id大于等于1的对象,结果是queryset
- models.UserInfo.objects.filter(id__lte=1) # 拿到id小于等于1的对象,结果是queryset
- models.UserInfo.objects.filter(name__contains='H') # 拿到name字段中包含大写H的对象,结果是queryset
- models.UserInfo.objects.filter(name__icontains='H') # 拿到name字段中包含大写H及小写h的对象,结果是queryset
- 筛选条件中,多条件并列时,可以直接用“,”对多条件进行连接。
- 另外,用models.数据表名.objects.get(筛选条件) 能取到单条数据,取不到内容或者是取到的结果是有多条时,报错!需要try一下。需要注意的是,大部分的查询结果是queryset存储的结果,但get方法是获取的单个的对象。
- models.数据表名.objects.exclude(筛选条件) 可以实现反向查询,即选出不满足筛选条件的记录,并把结果存入queryset中存储。
- 一般情况下,查询的结果,不论是all()或者是通过fiter()取到的都是queryset形式储存的对象的序列,再链一个values() 拿到的是queryset形式存储的字典的序列可以指定取出的字段 例如models.UserInfo.objects.filter(id__gt=1).values(‘id’,'name'), 如果链一个values_list() 拿到的则是queryset形式存储的元组的序列,可以通过索引值,拿到指定的字段
- queryset可以调用的其他常用方法
- order_by()方法,对queryset结果,按指定规则进行排序,返回值仍然是queryset。排序规则支持多条件,可以直接用“,”对条件进行连接。
- reverse() 方法,也是queryset进行反向操作时进行调用,返回值仍然是queryset。
- values(指定键值)方法,可以从queryset的对象列表中,拿到每个对象的指定键值对即字典形式,返回结果以queryset形式存储的字典键值对。
- values_list(指定键值) ,功能类似于values,但不同的是,返回的结果是queryset形式存储的元祖,不含键只有值。在取值的时候,用索引值。
- distinct() ,主要功能是进行去重。
- first( )当queryset中有对象时,取到的是第一个对象,没有对象时,取到的是none。用起来比get方法更方便。
- 删除:
- 方式一,可以在queryset直接调用delete方法
- models.数据表名.objects.filter(筛选条件).delete()
- 方式二,可以在queryset中利用first,last等取到【记录对象】后,直接调用delete
- models.数据表名.objects.filter(筛选条件).first().delete()
- 方式一,可以在queryset直接调用delete方法
- 修改(更新):
- 只能由queryset进行方法调用
- models.数据表名.objects.filter(筛选条件).update(字段=修改的数值)
- 多表(外键)
- 定义数据表结构的类中,定义外键对应关系。 外键关系名 = models.ForeignKey(to=关联表名,to_field=关联字段,default=指定默认值, on_delete=models.CASCADE) 外键关系名_id ——》外键字段(自动) on_delete=models.CASCSDE 是在django2.x以后版本加入的,最明显的一个作用,是避免两个表之间的数据不一致。models.CASCADE是默认情况下的取值,另外的取值分别为:
-
- CASCADE:此值设置,是级联删除。
PROTECT:此值设置,是会报完整性错误。
SET_NULL:此值设置,会把外键设置为null,前提是允许为null。
SET_DEFAULT:此值设置,会把设置为外键的默认值。
SET():此值设置,会调用外面的值,可以是一个函数。
- CASCADE:此值设置,是级联删除。
-
- 调用执行过程中,外键关系名指向关联表的对象
- 当用all(),filter()等方法直接拿到结果的时候,跨表拿内容,直接用 “ queryset存储的表对象 . 外键关系名 . 字段名 ” 来获取 例如item.group_foreignkey.name。此时的外键关系可理解为封装在queryset对象中的子级对象,指向关联表。
- 当用values(),或者values_list() 拿到结果的时候,跨表拿内容,不能用 “ . ” 需要改成双下划綫“ __ ” 例如:item.group_foreignkey__name。并且,在用values,或者values_list() 须在视图函数中完成
- 一对一关系,实际上是对一张字节比较多的表,进行的拆分。建立方式可以是通过唯一的外键
- 一对多关系,通过建立外键,可以实现表之间的一对多的关系创建
- 用建立外键关系后,通过 ‘ .外键关系_id ’ 可以获取从属表中,保存的外键值,利用 ‘ . 外键关系 ’ 则可以直接取得对应的对象,直接用连接符 ‘ . ’ 可进一步通过跨表查询获取具体的属性。
- 一对多关系常见的查询方式:
- 如果通过 ‘ . ’ 跨表查询获得的是外键链接的对象,当这个对象中仍然包含其他的外键关系时,可以依次用 ‘ . ’ 跨表查询获得
- 双下划綫,实现跨表查询,当跨表查询的结果作为参数使用时,利用 __。例如在,value()中传递参数的时候。
- 多对多关系建立
- 方式一,通过手动建立第三张表作为关系表,分别通过外键和另外的两张表建立外键关联,最终实现两张关联表之间的多对多
- 方式二,利用r=models.ManyToManyField() ,在创建原始的关联表的时候,由django自动创建多对多的第三张关系表。r作为操作句柄可以实现对第三张关系表的操作。
- 利用r操作对应关系的时候,先获取一张关联表(创建r的表)中的对象, 例如, obj=models.关联表名.get(id=1)
- 然后通过r对关联关系进行操作。 obj.r.add(2) obj.r.add(1,2,3) obj.r.add(*[3,4,5,6]) obj.r.remove(2,3) obj.r.clear() obj.r.set([1,2,3]) 用set设定更新关系时,传列表不用加* 。 obj.r.all() 拿到的是一个另一张表的对象, obj.r.filter()
- 方式二默认的只可以创建两张表之间的关系。如果需要多张表之间建立关系,需要用方式一。
- 定义数据表结构的类中,定义外键对应关系。 外键关系名 = models.ForeignKey(to=关联表名,to_field=关联字段,default=指定默认值, on_delete=models.CASCADE) 外键关系名_id ——》外键字段(自动) on_delete=models.CASCSDE 是在django2.x以后版本加入的,最明显的一个作用,是避免两个表之间的数据不一致。models.CASCADE是默认情况下的取值,另外的取值分别为:
- 反向查询
- 单表操作
