Django基础
本节内容:
1、什么是web框架(web应用程序)
2、Django介绍
3、Django在PyCharm下的创建
4、Django的工作流程
5、Djang的四个重点
一、web框架
web(World Wide Web)即全球广域网,也称为万维网,它是基于超文本和HTTP的、全球性的、动态交互的、跨平台分布式图形信息系统。是建立在lnternet上的一种网络服务,为浏览者在lnternet上查找和浏览信息提供图形化得、易于访问的直观界面,其中的文档及超级链接lnternet上的节点,组织成一个互为关联的网状结构。(百度搜索
一、超文本(hypertext)
超文本是一种用户接口方式,用以显示文本及与文本相关的内容。现时超文本普遍以电子文档的方式存在,其中的文字包含有可以链接到其他字段或者文档的超文本链接,允许从当前阅读位置直接切换到超文本链接所指向的文字。
超媒体室内效果图大课堂
超文本的格式有很多,最常使用的是超文本标记语言(标准通用标记语言下的一个应用)及富文本格式(RTF)。我们日常浏览的网页都属于超文本。
超文本链接一种全局性的信息结构,它将文档中的不同部分通过关键字建立链接,使信息得以用交互方式搜索。
二、超媒体(hypermedia)
超媒体是超文本(hypertext)和多媒体在信息浏览环境下的结合。它是超级媒体的简称。用户不仅能从一个文本跳到另一个文本,而且可以激活一段声音,显示一个图形,甚至可以播放一段动画。
Internet采用超文本和超媒体的信息组织方式,将信息的链接扩展到整个Internet上。Web就是一种超文本信息系统,Web的一个主要的概念就是超文本链接。它使得文本不再像一本书一样是固定的线性的,而是可以从一个位置跳到另外的位置并从中获取更多的信息,还可以转到别的主题上。想要了解某一个主题的内容只要在这个主题上点一下,就可以跳转到包含这一主题的文档上。正是这种多连接性把它称为Web。
三、超文本传输协议(HTTP)HyperText Transfer Protocol超文本在互联网上的传输协议。
)
框架:特指为解决一个开放性问题(需求不一样)而设计的具有一定约束性的支撑结构,使用框架可以帮你快速开发特定的系统,简单地说,就是你用别人搭建好的舞台来做表演。
对于web的应运:,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端。
web应运流程:
//首先浏览器发送一个HTTP请求(里面是有很多内容的,请求头和请求体) //服务器接收到这个请求,生成一个HTML文档。 //服务器要把这个HTML文档,作为HTTP的响应体发送给浏览器(还有个响应头,这里没有体现这个过程) //最后一步是浏览器当收到HTTP这个响应体之后,渲染一下,把这个页面(HTML文档)给用户展示 //这个过程中漏掉的是HTTP协议下的解析和设定过程(这个过程,自己写是完全没有问题的,前提是你得会 HTTP规范,这个工作是相当繁杂的)这个接口就是WSGI (Web Server Gateway Interface。) Web 服务器 Gateway网关 Interface接口
二、Django介绍
Django是一个开放源代码的Web应运框架,由Python写成。采用MTV框架模式,即模型M、T模板、视图V。
Model(模型):负责业务对象与数据库的对象(ORM)s
Template(模版):负责如何把页面展示给用户
View(视图):负责业务逻辑,并在适当的时候调用Model和Template
Django是一个Web框架——一套用于帮助开发交互式网站的工具。Django能够响应网页请求,还能让你轻松 的读写数据库、管理用户等。
他最初是被开发,用于管理劳伦斯出版集团旗下的一些以新闻内容为主的网站。并与2005年7月在BSD许可证下发布。
这套框架是以比利时的吉普赛爵士吉他手Django Reinhardt来命名的。
此外,Django还有一个url分发器,它的作用是将一个个URL的页面请求分发给不同的view处理,view再调用相应的Model和Template

三、Django在PyCharm下的创建(可以在终端安装创建,但是步骤比较多)
第一步

第二部

第三步

第四步(第一个文件名字就比如是微信,是一个总的 。第二个文件名就相当于,微信下的其他功能,聊天,支付,朋友圈,他们是各自独立的,都有各自独立的功能,各自的执行语句。但是都是属于微信的app)

文件的名字介绍
四、Django的工作流程(简单的介绍,后面会详细的编写)

简单的介绍一下这些文件 都是干什么的(和上面那张图对应一下)

图片的页面是引入 静态文件 方法
1,创建URL

2、写视图函数(视图函数和html文档不在一个文件夹下为什么可以读到:jango已经把路径写好了,写在settings配置文件里面,他是jango运行首先要做的一件事情,会把所有的配置读到自己脑子里面)

3、显示页面的HTML文档(form后面的login.html意思就是交给这个URL去处理,把里面的那些值。都封装到对应URL的视图函数参数里了)


4、启动

5,链接

五、Django、四个重点(四个圈起来的)

一、Django(URL匹配相对应的函数)
URL配置(URLconf)就像Django 所支撑网站的目录。它的本质是URL模式以及要为该URL模式调用的视图函数之间的映射表;你就是以这种方式告诉Django,对于这个URL调用这段代码,对于那个URL调用那段代码。
urlpatterns = [
path( 'URL路径(正则表达式)' , views视图函数,参数,别名),
]
#在Django2.0以后 URL换成了path,里面原先的正则表达式,换成直接单引号里面的写就行,开头不用加^ 结尾不用加$
参数说明:
- 一个正则表达式字符串
- 一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串
- 可选的要传递给视图函数的默认参数(字典形式)
- 一个可选的name参数

上面那种是FBV URL——》def函数
也可以通过类来实现 CBV
URL——》类
类的得这么写
path('login.html/',views.Login.as_view()),
# 先引入views from django import views # 继承里面方法 class Login(views.View): #如果是get请求走这个函数 def get(self,requese, *args, **kwargs): return render(requese, 'login.html',{'msg':''}) # 如果是post请求经过一些验证走这个 def post(self,request,*args,**kwargs): user = request.POST.get('user') pwd = request.POST.get('pwd') c = models.Administrator.objects.filter(username=user, password=pwd,).count() if c: request.session['is_login'] = True request.session['username'] = user rep = redirect('/index.html') return rep else: message = "用户名或密码错误" return render(request, "login.html", {'msg': message})
类的这种 先知道一下
路由分发后blog下的url

简单的写完URL后就可以写视图函数了,(URL视图函数后面可以加name=名字,为的是以后假如,URL index想换名字了,他一换,前端有关这个全得跟着改,以及一系列的操作,就相当于起一个别名,以后主名改成什么,我都可以通过这个别名找到这个URL)form表单提交是时候 {% url "别名"%}
二,Django Views(视图函数)

http请求中产生两个核心对象:
http请求:HttpRequest对象
http响应:HttpResponse对象
所在位置:django.http
之前我们用到的参数request就是HttpRequest (就是函数后面,括号里面加的参数)
简单的几个方法
1、HttpRequest对象的属性和方法:
# path: 请求页面的全路径,不包括域名 # # method: 请求中使用的HTTP方法的字符串表示。全大写表示。例如 # # if req.method=="GET": # # do_something() # # elseif req.method=="POST": # # do_something_else() # # GET: 包含所有HTTP GET参数的类字典对象 # # POST: 包含所有HTTP POST参数的类字典对象 # # 服务器收到空的POST请求的情况也是可能发生的,也就是说,表单form通过 # HTTP POST方法提交请求,但是表单中可能没有数据,因此不能使用 # if req.POST来判断是否使用了HTTP POST 方法;应该使用 if req.method=="POST"
2 HttpResponse对象:
对于HttpRequest对象来说,是由django自动创建的,但是,HttpResponse对象就必须我们自己创建。每个view请求处理方法必须返回一个HttpResponse对象,必须是字符串。
HttpResponse类在django.http.HttpResponse
在HttpResponse对象上扩展的常用方法:
页面渲染: render()(推荐)<br> render_to_response(),
页面跳转: redirect("路径")
locals(): 可以直接将函数中所有的变量传给模板
实例

登录页面login.html

补充
-----------------------------------url.py path("login", views.login), path("kuan_back", views.kuan_back), -----------------------------------views.py def login(req): if req.method=="POST": if 1: # return redirect("/kuan_back/") name="wangkuan" return render(req,"my backend.html",locals()) return render(req,"login.html",locals()) def kuan_back(req): name="王宽" return render(req,"my backend.html",locals()) -----------------------------------login.html <form action="/login/" method="post"> <p>姓名<input type="text" name="username"></p> <p>性别<input type="text" name="sex"></p> <p>邮箱<input type="text" name="email"></p> <p><input type="submit" value="submit"></p> </form> -----------------------------------my backend.html <h1>用户{{ name }}你好</h1> #总结: render和redirect的区别: # 1 if render的页面需要模板语言渲染,需要的将数据库的数据加载到html,那么所有的这一部分 # 除了写在kuan_back的视图函数中,必须还要写在login中,代码重复,没有解耦. # 2 the most important: url没有跳转到/kuan_back/,而是还在/login/,所以当刷新后 # 又得重新登录.
三、Template 基础
什么是模板语言:
HTML + 逻辑控制语句
为什么叫模板 ,不叫HTML文件
因为里面有逻辑控制代码,如果没有,就是单纯的HTML文件(里面有了控制的内容,控制的变量,控制的语句在了,他就是一个模板)
作用:
前端,后端的纽带作用(中间的过度过程,后端的一些内容,要显示到前端,通过一些固定的语法)
1,模板语句 :{{变量}}
后端获取当前时间,用一个变量接收,然后再把当前获取的时间传递给前端输出
----------------------------urls.py path("current_time",views.current_time) ----------------------------views.py def current_time(req): now=datetime.datetime.now() return render(req,'current_time.html'{'current_date':now}) -----------------------------current_time.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>当前时间{{ current_date }}</h1> </body> </html>
return render(req, 'current_datetime.html', {'current_date':now})
render 是方法
req 是请求对象
'current_datetime.html' 是模板
{'current_date':now} 是上下文
2、深度的变量查找---------万能的句点号(.)
在 Django 模板中遍历复杂数据结构的关键是句点字符 (.)。
根据列表的索引取值

HTML 里 . 2 就是取 索引位置第2个

浏览器

字典的形式

根据 . 键取值

浏览器输出

输出当前时间

看还有时间两个属性

自己创建一个


HTML

浏览器输出

3、------- {% if %}的使用
{% if %}标签计算一个变量值,如果是“true”,即它存在、不为空并且不是false的布尔值,系统则会显示{% if %}和{% endif %}间的所有内容

结果

加elif

结果

例如:

4,--------------------{%for%}的使用
{% for %}标签允许你按顺序遍历一个序列中的各个元素,每次循环模板系统都会渲染{% for %}和{% endfor %}之间的所有内容
{%for i in obj%}
循环列表

HTML

输出

取索引值
对应的就输出了
取字点的键

不加 0 就从1 开始

结果
取值,对象 . 键 就行
5、-------变量的过滤器(filter)的使用
语法格式: {{obj|filter:param}}

1 add : 给变量加上相应的值 # # 2 addslashes : 给变量中的引号前加上斜线 # # 3 capfirst : 首字母大写 # # 4 cut : 从字符串中移除指定的字符 # # 5 date : 格式化日期字符串 # # 6 default : 如果值是False,就替换成设置的默认值,否则就是用本来的值 # # 7 default_if_none: 如果值是None,就替换成设置的默认值,否则就使用本来的值 #value2=5 {{ value2|add:3 }}<br> #value3='he llo wo r ld' {{ value3|cut:' ' }}<br> #把中间空格全去了 #import datetime #value4=datetime.datetime.now() {{ value4|date:'Y-m-d' }}<br> #获取时间 中间用- 隔开 #value5=[] {{ value5|default:'空的' }}<br> #如果value 是空的 就显示中文空的 #value6='<a href="#">跳转</a>' {"obj":value6 } {% autoescape off %} {{ obj }} {% endautoescape %} #如果你在后端写了HTML 格式的 前端是不认识的 ,然后申明一下 安全的 #可以进行渲染 ^^^^^^^^下面简单方法 {{ obj|safe }} #这个和上面的结果是一样的 #如果你在后端写了HTML 格式的 前端是不认识的 ,然后申明一下 安全的 #可以进行渲染 #value7='1234' {{ value7|filesizeformat }} #查看数据大小占有量, 多少KB {{ value7|length }} #长度 {{ value7|slice:":-1" }} #切片 拿到 1 2 3 #value8='http://www.baidu.com/?a=1&b=3' {{ value8|urlencode }} #编码 看到的就不是明文了 后面的 value9='hello I am kuan' {{value9|truncatechars:'6'}} #结果是hello I 按字符截最后六个 {{value9|truncatewords:'2'}} #结果是hel按单词截 最后两个
6,
------{%csrf_token%}:csrf_token标签
用于生成csrf_token的标签,用于防治跨站攻击验证。注意如果你在view的index里用的是render_to_response方法,加了也不会生效
其实,这里是会生成一个input标签,和其他表单标签一起提交给后台的。(form表单提交数据,不加这个 禁止提交的,类似于一个通行证的东西,)
7,------{% url %}: 引用路由配置的地址
#写完URL 视图函数,后面可以加name=别名 万一URL改名字了 这也不用改 依然可以找到 <form action="{% url "别名"%}" > <input type="text"> <input type="submit"value="提交"> {%csrf_token%} </form>
8、------{% verbatim %}: 禁止render ,视图函数里的render不进行渲染了
{% verbatim %}
{{ hello }}
{% endverbatim %}
#页面显示的还是{{ hello }}
9、自定义filter和simple_tag
------a、在app中创建templatetags模块(必须的)
------b、创建任意 .py 文件,如:my_tags.py
----------(filter参数不能超两个)
from django import template from django.utils.safestring import mark_safe register = template.Library() #register的名字是固定的,不可改变 @register.filter def filter_multi(v1,v2): return v1 * v2
from django import template from django.utils.safestring import mark_safe register = template.Library() #register的名字是固定的,不可改变 @register.simple_tag def simple_tag_multi(v1,v2): return v1 * v2
------c、在使用自定义simple_tag和filter的html文件中导入之前创建的 my_tags.py :{% load my_tags %}
------d、使用simple_tag和filter(如何调用)
-------------------------------.html {% load xxx %} #首行 # num=12 {{ num|filter_multi:2 }} #24
{% simple_tag_multi 2 5 %} 参数不限,但不能放在if for语句中
------e、在settings中的INSTALLED_APPS配置当前app,不然django无法找到自定义的simple_tag.
10、模板继承 extend
模板继承简单来讲,比如博客园,外面的框架,都是一样只有里面的内容是,每次都不一样的,按我们之前的方法,每一个页面跳转都得写一个HTML,这样就造成了大量的重复,然而我们只需要写好一个大体的HTML(重复的地方我们只写好一个HTML)不重复的地方我们写上一个盒子,
以后要是写HTML就需要把这个盒子调用一下,里面写不同的内容就可以了(不用每次HTML都去写重复的css,设计一样的长宽高,)
本质上来说,模板继承就是先构造一个基础框架模板,而后在其子模板中对它所包含站点公用部分和定义块进行重载。
举例 ,商城我们登录成功以后,可以看到订单,购物车,外面的框架是一样的,只有购物车,订单里面的内容不一样
from django.contrib import admin from django.urls import path,include from blog import views urlpatterns = [ path('admin/', admin.site.urls), #订单路由 path("ordered/",views.ordered), #购物车路由 path("shopping_car/",views.shopping_car), ]
def ordered(req): return render(req,"ordered.html") def shopping_car(req): return render(req,"shopping_car.html")
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .page-header{ height: 50px; background-color: rebeccapurple; } .page-body .menu{ height: 500px; background-color: antiquewhite; float: left; width: 20%; } .page-body .content{ height: 500px; background-color: cornflowerblue; float: left; width: 80%; } .page-footer{ height: 30px; background-color: darkcyan; clear:both; } </style> </head> <body> <div> <div class="page-header"></div> <div class="page-body"> <div class="menu"> <a href="/ordered/">订单</a><br> <a href="/shopping_car/">购物车</a> </div> {# 这就是盒子 名字自己定义,但是不能重复#} {% block abc %} {% endblock %} </div> <div class="page-footer"></div> </div>
{% extends "base.html" %} {#必须写在第一行,要引入总框架#} {% block abc %} <div class="content"> 订单2 </div> {% endblock %}
{% extends "base.html" %} {#必须写在第一行,引入总的框架#} {% block abc %} <div class="content"> 购物车2 </div> {% endblock %}
以下是其工作方式:
在加载 订单.html 模板时,模板引擎发现了 {% extends %} 标签, 注意到该模板是一个子模板。 模板引擎立即装载其父模板,即本例中的 base.html 。此时,模板引擎注意到 base.html 中的一个 {% block %} 标签(可以是多个),并用子模板的内容替换这些 block 。因此,引擎将会使用我们在 { block abc %} 中定义的标题, 所以,网页标题一块将由{% block abc %}替换。
这个方法可最大限度地重用代码,并使得向公共区域(如区域级的导航)添加内容成为一件轻松的工作。
以下是使用模板继承的一些诀窍:
<1>如果在模板中使用 {% extends %} ,必须保证其为模板中的第一个模板标记。 否则,模板继承将不起作用。
<2>一般来说,基础模板中的 {% block %} 标签越多越好。 记住,子模板不必定义父模板中所有的代码块,因此
你可以用合理的缺省值对一些代码块进行填充,然后只对子模板所需的代码块进行(重)定义。 俗话说,钩子越
多越好。
<3>如果发觉自己在多个模板之间拷贝代码,你应该考虑将该代码段放置到父模板的某个 {% block %} 中。
如果你需要访问父模板中的块的内容,使用 {{ block.super }}这个标签吧,这一个魔法变量将会表现出父模
板中的内容。 如果只想在上级代码块基础上添加内容,而不是全部重载,该变量就显得非常有用了。
<4>不允许在同一个模板中定义多个同名的 {% block %} 。 存在这样的限制是因为block 标签的工作方式是双向的。
也就是说,block 标签不仅挖了一个要填的坑,也定义了在父模板中这个坑所填充的内容。如果模板中出现了两个
相同名称的 {% block %} 标签,父模板将无从得知要使用哪个块的内容。
四,Models
models的作用是定义出对象的模型,一般都是和数据库里表对应,一个表一个models类,表里的字段对应的models类的属性
ORM(对象关系映射)
用于实现面向对象编程语言里不同类型系统的数据之间的转换,换言之,就是用面向对象的方式去操作数据库的创建表以及增删改查等操作
优点: 1 ORM使得我们的通用数据库交互变得简单易行,而且完全不用考虑该死的SQL语句。快速开发,由此而来。
2 可以避免一些新手程序猿写sql语句带来的性能问题。
下面要开始Django ORM语法
创建表:单表
关联表 :(一对一)(一对多{重点})(多对多{重点})
操作表:
(增、删、改、查){重点}
怎样在Pycharm里生成数据库表,在Django的models.py里写
简单看一下格式(下面会仔细介绍)

多对多还可以重新自己建立个表,通过两个字段和两个表建立外键来实现多对多
__str__方法

这个方法的目的是,当返回打印对象的时候,不要显示一堆内存地址,(看不懂它是什么)我是想打印出来跟他实例相关的一些信息,一打印我就知道它是谁。
#然后下面打开终端执行 python manage.py makemigrations python manage.py migrate #执行完这两句 数据库表生成

常用的字段类型参数
<1> CharField #字符串字段, 用于较短的字符串. #CharField 要求必须有一个参数 maxlength, 用于从数据库层和Django校验层限制该字段所允许的最大字符数. <2> IntegerField #用于保存一个整数. <3> FloatField # 一个浮点数. 必须 提供两个参数: # # 参数 描述 # max_digits 总位数(不包括小数点和符号) # decimal_places 小数位数 # 举例来说, 要保存最大值为 999 (小数点后保存2位),你要这样定义字段: # # models.FloatField(..., max_digits=5, decimal_places=2) # 要保存最大值一百万(小数点后保存10位)的话,你要这样定义: # # models.FloatField(..., max_digits=19, decimal_places=10) # admin 用一个文本框(<input type="text">)表示该字段保存的数据. <4> AutoField # 一个 IntegerField, 添加记录时它会自动增长. 你通常不需要直接使用这个字段; # 自定义一个主键:my_id=models.AutoField(primary_key=True) # 如果你不指定主键的话,系统会自动添加一个主键字段到你的 model. <5> BooleanField # A true/false field. admin 用 checkbox 来表示此类字段. <6> TextField # 一个容量很大的文本字段. # admin 用一个 <textarea> (文本区域)表示该字段数据.(一个多行编辑框). <7> EmailField # 一个带有检查Email合法性的 CharField,不接受 maxlength 参数. <8> DateField # 一个日期字段. 共有下列额外的可选参数: # Argument 描述 # auto_now 当对象被保存时,自动将该字段的值设置为当前时间.通常用于表示 "last-modified" 时间戳. # auto_now_add 当对象首次被创建时,自动将该字段的值设置为当前时间.通常用于表示对象创建时间. #(仅仅在admin中有意义...) <9> DateTimeField # 一个日期时间字段. 类似 DateField 支持同样的附加选项. <10> ImageField # 类似 FileField, 不过要校验上传对象是否是一个合法图片.#它有两个可选参数:height_field和width_field, # 如果提供这两个参数,则图片将按提供的高度和宽度规格保存. <11> FileField # 一个文件上传字段. #要求一个必须有的参数: upload_to, 一个用于保存上载文件的本地文件系统路径. 这个路径必须包含 strftime #formatting, #该格式将被上载文件的 date/time #替换(so that uploaded files don't fill up the given directory). # admin 用一个<input type="file">部件表示该字段保存的数据(一个文件上传部件) . #注意:在一个 model 中使用 FileField 或 ImageField 需要以下步骤: #(1)在你的 settings 文件中, 定义一个完整路径给 MEDIA_ROOT 以便让 Django在此处保存上传文件. # (出于性能考虑,这些文件并不保存到数据库.) 定义MEDIA_URL 作为该目录的公共 URL. 要确保该目录对 # WEB服务器用户帐号是可写的. #(2) 在你的 model 中添加 FileField 或 ImageField, 并确保定义了 upload_to 选项,以告诉 Django # 使用 MEDIA_ROOT 的哪个子目录保存上传文件.你的数据库中要保存的只是文件的路径(相对于 MEDIA_ROOT). # 出于习惯你一定很想使用 Django 提供的 get_<#fieldname>_url 函数.举例来说,如果你的 ImageField # 叫作 mug_shot, 你就可以在模板中以 {{ object.#get_mug_shot_url }} 这样的方式得到图像的绝对路径. <12> URLField # 用于保存 URL. 若 verify_exists 参数为 True (默认), 给定的 URL 会预先检查是否存在( 即URL是否被有效装入且 # 没有返回404响应). # admin 用一个 <input type="text"> 文本框表示该字段保存的数据(一个单行编辑框) <13> NullBooleanField # 类似 BooleanField, 不过允许 NULL 作为其中一个选项. 推荐使用这个字段而不要用 BooleanField 加 null=True 选项 # admin 用一个选择框 <select> (三个可选择的值: "Unknown", "Yes" 和 "No" ) 来表示这种字段数据. <14> SlugField # "Slug" 是一个报纸术语. slug 是某个东西的小小标记(短签), 只包含字母,数字,下划线和连字符.#它们通常用于URLs # 若你使用 Django 开发版本,你可以指定 maxlength. 若 maxlength 未指定, Django 会使用默认长度: 50. #在 # 以前的 Django 版本,没有任何办法改变50 这个长度. # 这暗示了 db_index=True. # 它接受一个额外的参数: prepopulate_from, which is a list of fields from which to auto-#populate # the slug, via JavaScript,in the object's admin form: models.SlugField # (prepopulate_from=("pre_name", "name"))prepopulate_from 不接受 DateTimeFields. <13> XMLField #一个校验值是否为合法XML的 TextField,必须提供参数: schema_path, 它是一个用来校验文本的 RelaxNG schema #的文件系统路径. <14> FilePathField # 可选项目为某个特定目录下的文件名. 支持三个特殊的参数, 其中第一个是必须提供的. # 参数 描述 # path 必需参数. 一个目录的绝对文件系统路径. FilePathField 据此得到可选项目. # Example: "/home/images". # match 可选参数. 一个正则表达式, 作为一个字符串, FilePathField 将使用它过滤文件名. # 注意这个正则表达式只会应用到 base filename 而不是 # 路径全名. Example: "foo.*\.txt^", 将匹配文件 foo23.txt 却不匹配 bar.txt 或 foo23.gif. # recursive可选参数.要么 True 要么 False. 默认值是 False. 是否包括 path 下面的全部子目录. # 这三个参数可以同时使用. # match 仅应用于 base filename, 而不是路径全名. 那么,这个例子: # FilePathField(path="/home/images", match="foo.*", recursive=True) # ...会匹配 /home/images/foo.gif 而不匹配 /home/images/foo/bar.gif <15> IPAddressField # 一个字符串形式的 IP 地址, (i.e. "24.124.1.30"). <16># CommaSeparatedIntegerField # 用于存放逗号分隔的整数值. 类似 CharField, 必须要有maxlength参数.
<1> null : 数据库中字段是否可以为空 <2> blank: django的 Admin 中添加数据时是否可允许空值 <3> default:设定缺省值 <4> editable:如果为假,admin模式下将不能改写。缺省为真 <5> primary_key:设置主键,如果没有设置django创建表时会自动加上: id = meta.AutoField('ID', primary_key=True) primary_key=True implies blank=False, null=False and unique=True. Only one primary key is allowed on an object. <6> unique:数据唯一 <7> verbose_name Admin中字段的显示名称 <8> validator_list:有效性检查。非有效产生 django.core.validators.ValidationError 错误 <9> db_column,db_index 如果为真将为此字段创建索引 <10>choices:一个用来选择值的2维元组。第一个值是实际存储的值,第二个用来方便进行选择。 如SEX_CHOICES= (( ‘F’,'Female’),(‘M’,'Male’),) gender = models.CharField(max_length=2,choices = SEX_CHOICES)
分析代码:
<1> 每个数据模型都是django.db.models.Model的子类,它的父类Model包含了所有必要的和数据库交互的方法。并提供了一个简介漂亮的定义数据库字段的语法。
<2> 每个模型相当于单个数据库表(多对多关系例外,会多生成一张关系表),每个属性也是这个表中的字段。属性名就是字段名,它的类型(例如CharField)相当于数据库的字段类型(例如varchar)。大家可以留意下其它的类型都和数据库里的什么字段对应。
<3> 模型之间的三种关系:一对一,一对多,多对多。
一对一:实质就是在主外键(author_id就是foreign key)的关系基础上,给外键加了一个UNIQUE=True的属性;(不能再重复)
一对多:就是主外键关系;(foreign key)
多对多:(ManyToManyField) 自动创建第三张表(当然我们也可以自己创建第三张表:两个foreign key)
增、删、改、查
在视图函数 相对应的函数里写
-------------------------------------增(create , save) -------------------------------
两种形式四种方法
推荐: dic={"title":"go","price":45}
models.Book.objects.create(**dic)
from app01.models import * #create方式一: models.表名.objects.create(字段='内容') #create方式二: models.表名.objects.create(**{"name":"alex"}) #增加的是字典两个星** 列表 一个* #save方式一: 创建对象=表名(name="alvin") author.save() #保存 #save方式二: 对象=表名() 对象.name="alvin" 对象.save() 推荐第二种 前面加两个星的字典形式 因为按正常需求来说,不会每一条数据我们都自己定好,而更多的情况,我们们从前端,或其他地方接收到用户信息。用户输入过来,我们接受到,接收到的信息就是一个字典,我们不需要做什么修改,直接把这个字典放在那里面插入进去,插入字典前前面要加两个星
重点增(一对多和,多对多):
A表
C表
当创建创建表的时候,给这个表里建立了外键 一对多,怎么样给外见的字段 增加数据
比如在A表下建立外键,和c表要进行关联(外键要建立在多的那个表里 一个出板社 可以出多本书 但是一本书只能有一个出版社 (要是键在出版社后面,一个出版社,得出过多少本书,也不能那么建立))
aaa=models.Foreignkey("C") 要想给aaa字段增加数据 就得 后面加 _id
比如 这样加 models.A.objects.create(aaa_id=1) 这就在A表的外键add_id列 增加了ccc表里对应的那个ID 1
为什么后面加_id,只是你在建立外键的时候Django 内部自动帮你生成的
不加_id还有一种方法
pud=models.C.objects.filter(id=1)
models.A.objects.create(aaa=pud[0])
因为filter(id=1)取到的是一个集合,pud必须是一个对象,不能是对象集合因为绑定的出版社只能有一个(因为是一对多,所以只能有一个对象)
pud取到的id=1的出版社 集合 通过后面加上[0] 渠道索引,就是对象 不是集合
虽然外键建立在了A表里,但只要绑定了关系,C表也不是单纯的单表了,也是关联表
多对多(键在两个表那个表也行)(ManyToManyField()) 自动生成第三张表 自己创建第3 张表 可以通过两个外键 建立多对多
多对多的情况就是 一个作者可以写多本书,一本书也可以有多个作者一块编写,彼此间的关系就是多对多
class Book (models.Model)
字段名 F =models.ManyToManyField("另一张表名[作者表]")
如果是这种创建方式,只能通过下面这种添加 add 方法
正向查询,在Book表里面增加
abc1=models.作者表.objects.get(id=3)
abc2=models.作者表.objects.get(id=4)
取到了id等于3 4 的作者
book=models.Book.objects.filter(id=3)[0]
取到书id等于3的一本书 ,第一个位置对象
book.F.add(*[abc1,abc2])
如果你要取消你所建立的关系 通过 book.F.remove(*[abc1,abc2])
3 3
3 4 这两条数据就删除了 下面反向的也是一样
这的F就是在Book建立多对多时候的字段 第三张表里的字段是自己生成的 取得两张表的主键ib生成字段
反向查询,作者表里添加,因为是多对多的关系,也可以在作者表里去插入数据,但是作者表里不能调用 F 字段了,因为没有,就得通过一个方法(.book_set) book就是Book的表名,得换成小写的
a=models.作者表.objects.get(id=3)
b=models.作者.objects.get(id=4)
c=models.Book.objects.filter(id=3)[0]
给两个作者插入了同一本书
a.book_set.objects.add(c)
b.book_set.objects.add(c)
要给book id等于3的这本书建立多对多的关系

自己创建多对多
class 表名(models.Model)
book= models.Foreignkey("Book")
author=models.Foreignkey("Author")
还有两个字段的联合唯一 ,两个字段不能重复(根据需求)
class Book2Author(models.Model) book= models.Foreignkey("Book") author=models.Foreignkey("Author") #建立联合唯一 class Meta: unique_together = ["book","author"] 给 两个字段添加数据 def 函数(req): models. Book2Author.objects.create( book_id=2, author_id=3, )
#一对多(ForeignKey): #方式一: 由于绑定一对多的字段,比如publish,存到数据库中的字段名叫publish_id,所以我们可以直接给这个 # 字段设定对应值: Book.objects.create(title='php', publisher_id=2, #这里的2是指为该book对象绑定了Publisher表中id=2的行对象 publication_date='2017-7-7', price=99) #方式二: # <1> 先获取要绑定的Publisher对象: pub_obj=Publisher(name='河大出版社',address='保定',city='保定', state_province='河北',country='China',website='http://www.hbu.com') OR pub_obj=Publisher.objects.get(id=1) # <2>将 publisher_id=2 改为 publisher=pub_obj #多对多(ManyToManyField()): author1=Author.objects.get(id=1) author2=Author.objects.filter(name='alvin')[0] book=Book.objects.get(id=1) book.authors.add(author1,author2) #等同于: book.authors.add(*[author1,author2]) book.authors.remove(*[author1,author2]) #------------------- book=models.Book.objects.filter(id__gt=1) authors=models.Author.objects.filter(id=1)[0] authors.book_set.add(*book) authors.book_set.remove(*book) #------------------- book.authors.add(1) book.authors.remove(1) authors.book_set.add(1) authors.book_set.remove(1) #注意: 如果第三张表是通过models.ManyToManyField()自动创建的,那么绑定关系只有上面一种方式 # 如果第三张表是自己创建的: class Book2Author(models.Model): author=models.ForeignKey("Author") Book= models.ForeignKey("Book") # 那么就还有一种方式: author_obj=models.Author.objects.filter(id=2)[0] book_obj =models.Book.objects.filter(id=3)[0] s=models.Book2Author.objects.create(author_id=1,Book_id=2) s.save() s=models.Book2Author(author=author_obj,Book_id=1) s.save()
----------------------------------------删(delete)-----------------------------
级联删除 和这个表里有 一对多 或多对多的 的其他表里 相关内容也会删除
表名.objects.filter(id=1).delete() #查询到那个表里id等于1 的 通过.delete()删除
-----------------------------------------改(update和save)--------------
表名.objects.filter(name='wangkuan').update(name='wk') #update 不能用get filter,渠道的是一个集合,就把所有等于wangkuan的替换成wk #get 只会取到一个对象,没有就报错,他不能调用update 推荐使用上面这个方法 他要比save效率高 update方法只会改你规定,字段的内容 save会把其他的即使你没有,改的也会重新改一遍,很多没有意义的操作 对象=表名.objects.get(id=5) 找到以后 对象.字段='内容' 重新赋值 对象.save 保存
-----------------------------------------------------查--------------------
------------------查询API(提前设定的函数,快捷方式)
# 查询相关API: 变量接收=models.objects.filter(id=2) # <1>filter( = ) 通过一组组的键值对来放 比如 name=wk,age=18 用逗号隔开,拿到的是集合对象 # <2>all(): 查询所有结果,也是集合对象里面没有参数 # <3>get( = ): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个(单个行的对象),如果符合筛选条件的对象超过一个或者没有都会抛出错误。 变量接收=models.objects.filter(id=2)[0] 为什么加[0] 因为取到的是一个集合类似于一个列表,取第一个值,切片(因为它里面也是有序的) #-----------下面的方法都是对查询的结果再进行处理:比如 objects.filter.values()-------- 变量接收=models.objects.filter(id=2) 这样整行都去出来了 通过一个方法 变量接收=models.objects.filter(id=2).values("字段名")比如 name 就是把id=2 的name列 取出来了 是字典的形式 [{"name":"wk"}] 为什么放在字典里面,因为你也许取出来的不只有一个 以下的这些方法 都是在 .filter .all 后调用 # <4>values( ): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列 model的实例化对象,而是一个可迭代的字典序列 # <5>exclude( = ): 它包含了与所给筛选条件不匹配的对象 比如id=2 出来id=2 的都取出来 # <6>order_by("id"): 对查询结果排序,比如对id进行排序 是字符串 但是他认识 id前加- 负号 反着排 # <7>reverse(): 对查询结果反向排序 # <8>distinct(): 从返回结果中剔除重复纪录(去重) # <9>values_list(“字段”): 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列 # <10>count(): 返回数据库中匹配查询(QuerySet)的对象数量。(把你取到的集合技算一下,到底有多少条) # <11>first(): 返回第一条记录 # <12>last(): 返回最后一条记录 # <13>exists(): 如果QuerySet包含数据,就返回True,否则返回False。(查询里面有没有这个数据)
---------->惰性机制:
所谓惰性机制:Publisher.objects.all()或者.filter()等都只是返回了一个QuerySet(查询结果集对象),它并不会马上执行sql,而是当调用QuerySet的时候才执行。
QuerySet特点:
<1> 可迭代的
<2> 可切片
#objs=models.Book.objects.all()#[obj1,obj2,ob3...] #QuerySet: 可迭代 # for obj in objs:#每一obj就是一个行对象 # print("obj:",obj) # QuerySet: 可切片 # print(objs[1]) # print(objs[1:4]) # print(objs[::-1])
根据书名来找出版社的名字
正向查找
def 函数(req): obj=models.Book.objects.filter(title="GO")[0] #先找到书名 a=obj.创建外键的字段名.name print(a) 取到出版社名字
反向查找
通过出版社找出,出过那几本书
#先找到出版社 obj=models.出版社表.objects.filter(name="人民出版社")[0] a=obj.书小写的表名_set.all().values("书的字段").distinct()#去重 print(a)
双下滑线
# models.Tb1.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值 # # models.Tb1.objects.filter(id__in=[11, 22, 33]) # 获取id等于11、22、33的数据 # models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in # # models.Tb1.objects.filter(name__contains="ven") name字段里包含ven的取出来 # models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感 # # models.Tb1.objects.filter(id__range=[1, 2]) # 范围 id 1 2 之间的 # # __startswith=,必须以什么开头 istartswith, endswith,以什么结尾 iendswith,
# 正向查找(条件) # ret3=models.Book.objects.filter(title='Python').values('id') # print(ret3)#[{'id': 1}] #正向查找(条件)之一对多 ret4=models.Book.objects.filter(title='Python').values('publisher__city') print(ret4) #[{'publisher__city': '北京'}] #正向查找(条件)之多对多 ret5=models.Book.objects.filter(title='Python').values('author__name') print(ret5) ret6=models.Book.objects.filter(author__name="alex").values('title') print(ret6) #注意 #正向查找的publisher__city或者author__name中的publisher,author是book表中绑定的字段 #一对多和多对多在这里用法没区别 # 反向查找(条件) #反向查找之一对多: ret8=models.Publisher.objects.filter(book__title='Python').values('name') print(ret8)#[{'name': '人大出版社'}] 注意,book__title中的book就是Publisher的关联表名 ret9=models.Publisher.objects.filter(book__title='Python').values('book__authors') print(ret9)#[{'book__authors': 1}, {'book__authors': 2}] #反向查找之多对多: ret10=models.Author.objects.filter(book__title='Python').values('name') print(ret10)#[{'name': 'alex'}, {'name': 'alvin'}] #注意 #正向查找的book__title中的book是表名Book #一对多和多对多在这里用法没区别
F查询和Q查询
仅仅靠单一的关键字参数查询已经很难满足查询要求。此时Django为我们提供了F和Q查询:
F 使用查询条件的值,专门取对象中某列值的操作

# F 使用查询条件的值,专门取对象中某列值的操作 # from django.db.models import F # models.Tb1.objects.update(num=F('num')+1)
Q 分装关键查询
Q 构建搜索条件 可以组合使用&,|操作符,当一个操作符是用于两个Q的对象,它产生一个新的Q对象。 & and | or ~ not from django.db.models import Q obj=models.Book.objects.filter(Q(id=3)|Q(title="php")) #找到book表里id=3或 title=php的 models.Book.objects.filter(Q(price__ge=50)&(Q(id=3)|Q(title="php"))) #大于50的 每个查找函数都接受关键字参数(例如filter()), # exclude(), get())也可以作为一个或多个Q对象传递 还可以加关键字 要放在最后面 .filter(Q(price__ge=50)&(Q(id=3)|Q(title="php")).color="yellow") #加个大于50 id=3 或书名是PHP 颜色是黄色的
admin的配置
admin是django强大功能之一,它能共从数据库中读取数据,呈现在页面中,进行管理。默认情况下,它的功能已经非常强大,如果你不需要复杂的功能,它已经够用,但是有时候,一些特殊的功能还需要定制,比如搜索功能,下面这一系列文章就逐步深入介绍如何定制适合自己的admin应用。
如果你觉得英文界面不好用,可以在setting.py 文件中修改以下选项
LANGUAGE_CODE = 'en-us' #LANGUAGE_CODE = 'zh-hans'
当我们访问http://127.0.0.1:8080/admin/时,会出现:

前提是先把默认的数据库生 在设定所以我们需要为进入这个项目的后台创建超级管理员:python manage.py createsuperuser,设置好用户名和密码后便可登录啦!
掌握一些常用的设置技巧
- list_display: 指定要显示的字段
- search_fields: 指定搜索的字段
- list_filter: 指定列表过滤器
- ordering: 指定排序字段

浙公网安备 33010602011771号