上回精彩回顾

视图函数:request对象request.path    请求路径request.GET     GET请求数据 QueryDict {}request.POST    POST请求数据 QueryDict {}request.method  请求方式    "GET"   "POST"request.is_ajax()   是否是Ajax请求request.get_full_path() 包含请求数据的路径return HttpResponse("响应体字符串")render  : 渲染render(request, "index.html")render(request, "index.html", {"name": name})redirect  : 重定向两次请求

render没有第3个参数时,直接读取文件;有第3个参数时,判断有没有{}语法,然后替换。

redirect是服务器向浏览器发送302指令,它是2次请求;form表单提交时,url变动了。因为它必然会发生一次请求!当form表单的action属性为空时,单击提交。它会获取当前url作为action的属性,它和当前url没有任何关系。

思考题:

假设访问的是login,login的视图函数代码为:

def login(request):return render(request,'login.html')  

访问页面是正常的:

如果改为这样呢?

def login(request):return redirect('/login/')

分析一下:

现在直接访问login页面,看看会不会一直跳转。

页面提示:google浏览器提示重定向次数过多

Edge浏览器是直接提示

一  变量{{ }}1 深度查询2 过滤器{{ now|date:"Y-m-d" }}{{ file_size:filesizeformat }}{{ link|safe }}
二  标签{% %}1.{% for i in  [] %}{{ forloop.counter }}{{ forloop.last }}{% endfor %}2.{% if 条件 %}<p>1111</p>{% elif %}<p>2222</p>{% else %}<p>3333</p>{% endif %}3. with4. url{% url '别名' 参数 %}5.{% csrf_token %}  

注意:datetime也可以做格式化,比如:

def login(request):import datetimenow = datetime.datetime.now().strftime("%Y-%m-%d  %H:%M:%S")return HttpResponse(now)  

访问页面输出:

也就是说,后端可以定义格式,前端也可以定义格式,看你喜欢哪种。

重点掌握if和for语法,还有csrf_token

一、模板自定义标签和过滤器

标签,是为了做一些功能。过滤器,是对斜杠前面的数据做过滤。

为什么要自定义标签和过滤器?因为字典的不够用,需要结合需求,来自定义。

自定义标签和过滤器需要执行3个步骤:

1、在setting中的INSTALLED_APPS配置当前app,不然django无法找到自定义的simple_tag。
2、在app中创建templatetags模块(模块名必须是templatetags)
3、创建任意.py文件,如:my_tags.py

自定义过滤器

举例:增加一个乘法过滤器

修改settings.py中的INSTALLED_APPS,最后一行添加当前的app。

django开头的,都是一些自带的app。它内置在django源码里面!

INSTALLED_APPS = ['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','app1.apps.App1Config',
]  

在app1目录里面新建一个templateages目录,目录名必须是这个!!!否则django找不到。

目录里面创建my_filter_tag.py这个py文件,可以随便定义。内容如下:

from django import template
from django.utils.safestring import mark_saferegister = template.Library()@register.filter
def multi_filter(x, y):return x * y  

注意:头部的3行,是固定写法,不能改变。

增加@register.filter,是为了将函数转换成过滤器。函数的名字,可以自定义。

修改views.py里面的index函数,内容如下:

def index(request):num = 100return render(request,'index.html',{'num': num})  

修改index.html,修改body部分

注意:在使用自定义标签和过滤器,必须在html文件中,导入之前创建的my_filter_tag

{% load my_filter_tag %}
<p>{{ num|multi_filter:5 }}</p>

load表示导入模块。p标签中的内容,是执行了multi_filter过滤器。

注意:它接收了2个参数。一个是num,一个是5。因为multi_filter过滤器,定义了2个形参,使用它必须传2个参数才行。

访问index页面,输出:

是因为自定义的模块,没有导入成功,提示找不到!为啥呢?因为django项目启动时,会导入settings定义的模块,由于app1的自定义模块是启动之后加的,所以它并没有加载进去。

重启django项目,就可以加载了。再次访问index,页面输出:

如果要完成3个数的乘法呢?过滤器可以增加一个形参,但是index.html怎么加第3个参数呢?

答案是,它不能加第3个参数。所以只能在后端,将参数形式修改成列表、元组、字典等方式,就可以了。

举例1:计算4*5*6

修改index视图函数

def index(request):num1 = 4num2 = 5num3 = 6num_list = [num1,num2,num3]return render(request,'index.html',{'num_list': num_list})  

修改my_filter_tag.py中的过滤器

@register.filter
def multi_filter(num_list):res = 1for i in num_list:res *= ireturn res  

修改index.html,修改body部分

{% load my_filter_tag %}
<p>{{ num_list|multi_filter }}</p>  

访问网页,输出:

举例2:显示a标签

修改my_filter_tag.py文件,增加link_tag过滤器

@register.filter
def link_tag(href):return "<a href=%s>click</a>" % href  

修改index视图函数

def index(request):link = "http://www.py3study.com/"return render(request,'index.html',{'link': link})  

修改index.html,修改body部分

{% load my_filter_tag %}
<p>{{ link|link_tag }}</p>  

访问网页,输出:

发现结果不是我们想要的,查看浏览器控制台,查看响应体,发现被转义了

因为django遇到html或者js标签,会转义,它认为是不安全的!那么如何告诉它,是安全的呢?

需要在过滤器中导入make_safe模块

修改my_filter_tag.py文件中的link_tag过滤器,完整代码如下:

使用make_safe方法,告诉django是安全的,不需要转义

from django import template
from django.utils.safestring import mark_saferegister = template.Library()@register.filter
def link_tag(href):return mark_safe("<a href=%s>click</a>" % href)  

重启django项目,因为网页有缓存,懒得清理了,所以直接重启django项目,见效快!

再次访问效果就出来了。

自定义标签

标签,是为了做一些功能

举例:4个参数的乘法运算

修改my_filter_tag.py,增加multi_tag函数

@register.simple_tag
def multi_tag(x,y,z):return x*y*z

@register.simple_tag表示将函数转换为自定义标签

修改index.html,修改body部分

注意:调用标签,使用{% 标签过滤器名 参数1,参数2,参数3... %}

参数不限,但不能放在if for语句中  

{% load my_filter_tag %}
<p>{% multi_tag 7 8 9 %}</p>  

重启django项目,访问网页,输出:

自定义标签和自定义过滤器的区别:

1.  标签,是为了做一些功能。过滤器,是对斜杠前面的数据做过滤

2.  标签可以写任意个形参,而过滤器最大只能写2个形参。如果过滤器需要接收多个参数,需要将参数存放在列表,元组,字典等数据中。

3.  过滤器可以用在if等语句后,标签不可以

二、模板继承 (extend)

Django模板引擎中最强大也是最复杂的部分就是模板继承了。模板继承可以让您创建一个基本的“骨架”模板,它包含您站点中的全部元素,并且可以定义能够被子模版覆盖的blocks。

通过从下面的例子开始,可以容易的理解模板继承:

include

新建advertise.html,使用Bootstrap构建2个面板

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css">
</head>
<body><div class="row"><div class="col-md-4"><div class="advertise"><div class="panel panel-danger"><div class="panel-heading">菜单一</div><div class="panel-body">Panel content</div></div><div class="panel panel-success"><div class="panel-heading">菜单一</div><div class="panel-body">Panel content</div></div></div></div>
</div></body>
</html>  

修改urls.py,增加advertise路径

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

修改views.py,增加advertise视图函数

def advertise(request):return render(request, 'advertise.html')  

访问url:http://127.0.0.1:8000/advertise/

如果首页,也想显示左边的菜单栏呢?代码复制一遍?

这样代码就重复了,使用include,就可以了。

修改advertise.html,将相同的部分分离处理

<div class="row"><div class="col-md-4"><div class="advertise"><div class="panel panel-danger"><div class="panel-heading">菜单一</div><div class="panel-body">Panel content</div></div><div class="panel panel-success"><div class="panel-heading">菜单一</div><div class="panel-body">Panel content</div></div></div></div>
</div>  

修改index.html,使用include导入advertise.html文件

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css">
</head>
<body>
{% include 'advertise.html' %}
</body>
</html>  

访问首页,效果同上。

extend

访问博客园的个人博客,发现很多页面,有几处相同的部分。比如右侧的侧边栏,顶部的导航栏,尾部部分...等等。那么公共区域,不需要自己重复写,继承下来就可以了!

举例:图书网页

编辑index.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"><style>* {margin: 0;padding: 0;}.header {width: 100%;height: 60px;background-color: #369;}.title {line-height: 60px;color: white;font-weight: 100;margin-left: 20px;font-size: 20px;}.container{margin-top: 20px;}</style>
</head>
<body>
<div class="header"><p class="title">路飞学诚</p>
</div>
<div class="container"><div class="row"><div class="col-md-3"><div class="panel panel-danger"><div class="panel-heading">菜单一</div><div class="panel-body">Panel content</div></div><div class="panel panel-success"><div class="panel-heading">菜单二</div><div class="panel-body">Panel content</div></div><div class="panel panel-warning"><div class="panel-heading">菜单三</div><div class="panel-body">Panel content</div></div></div><div class="col-md-9"><div class="jumbotron"><h1>Hello, INDEX!</h1><p>...</p><p><a class="btn btn-primary btn-lg" href="#" role="button">Learn more</a></p></div></div></div>
</div>
</body>
</html>  

访问index页面,输出:

如果要访问子页面,比如书籍管理和作者管理?

修改urls.py,增加articles、authors路径

urlpatterns = [path('admin/', admin.site.urls),path('index/',views.index),path('articles/',views.articles),path('authors/',views.authors),
]  

修改views.py,增加2个视图函数

def articles(request):return render(request, 'articles.html')def authors(request):return render(request, 'authors.html')  

新建articles.html,将index.html的代码全部复制粘贴过来,修改中间内容

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"><style>* {margin: 0;padding: 0;}.header {width: 100%;height: 60px;background-color: #369;}.title {line-height: 60px;color: white;font-weight: 100;margin-left: 20px;font-size: 20px;}.container{margin-top: 20px;}</style>
</head>
<body>
<div class="header"><p class="title">路飞学诚</p>
</div>
<div class="container"><div class="row"><div class="col-md-3"><div class="panel panel-danger"><div class="panel-heading">菜单一</div><div class="panel-body">Panel content</div></div><div class="panel panel-success"><div class="panel-heading">菜单二</div><div class="panel-body">Panel content</div></div><div class="panel panel-warning"><div class="panel-heading">菜单三</div><div class="panel-body">Panel content</div></div></div><div class="col-md-9"><div class="article_list"><ul><li>红楼梦</li><li>三国演义</li><li>西游记</li><li>水浒传</li></ul></div></div></div>
</div>
</body>
</html>  

访问articles页面,效果如下:

新建authors.html,将index.html的代码全部复制粘贴过来,修改中间内容

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"><style>* {margin: 0;padding: 0;}.header {width: 100%;height: 60px;background-color: #369;}.title {line-height: 60px;color: white;font-weight: 100;margin-left: 20px;font-size: 20px;}.container{margin-top: 20px;}</style>
</head>
<body>
<div class="header"><p class="title">路飞学诚</p>
</div>
<div class="container"><div class="row"><div class="col-md-3"><div class="panel panel-danger"><div class="panel-heading">菜单一</div><div class="panel-body">Panel content</div></div><div class="panel panel-success"><div class="panel-heading">菜单二</div><div class="panel-body">Panel content</div></div><div class="panel panel-warning"><div class="panel-heading">菜单三</div><div class="panel-body">Panel content</div></div></div><div class="col-md-9"><div class="author_list"><ul><li>曹雪芹</li><li>罗贯中</li><li>吴承恩</li><li>施耐庵</li></ul></div></div></div>
</div>
</body>
</html>  

访问authors页面,效果如下:

问题来了,菜单和导航,都是重复的。有了继承,就可以解决这个问题。公共部分有,继承的子页面就会哟。没有的部分,子页面也不会有。

这个模板,我们把它叫做base.html,它定义了一个可以用于两列排版页面的简单HTML骨架。“子模版”的工作是用它们的内容填充空的blocks。

在这个例子中,block标签定义了三个可以被子模版内容填充的block。block告诉模板引擎:子模版可能会覆盖模板中的这些位置。

子模版可能看起来是这样的:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>title</title><link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"><style>* {margin: 0;padding: 0;}.header {width: 100%;height: 60px;background-color: #369;}.title {line-height: 60px;color: white;font-weight: 100;margin-left: 20px;font-size: 20px;}.container{margin-top: 20px;}</style>
</head>
<body><div class="header"><p class="title">路飞学诚</p>
</div><div class="container"><div class="row"><div class="col-md-3"><div class="panel panel-danger"><div class="panel-heading"><a href="http://127.0.0.1:8008/index/">首页</a></div><div class="panel-body">Panel content</div></div><div class="panel panel-success"><div class="panel-heading"><a href="http://127.0.0.1:8008/authors/">作者</a></div><div class="panel-body">Panel content</div></div><div class="panel panel-warning"><div class="panel-heading"><a href="http://127.0.0.1:8008/articles/">文章管理</a></div><div class="panel-body">Panel content</div></div></div><div class="col-md-9">{% block content %}{% endblock %}</div></div>
</div></body>
</html>  

修改index.html,删除多余的代码。继承base.html

它是先继承,再填充内容。

extends标签是这里的关键,它告诉模板引擎,这个模板“继承”了另一个模板,当模板系统处理这个模板时,首先,它将定位父模板——在此例中,就是“base.html”。

那时,模板引擎将注意到base.html中的三个block标签,并用子模版中的内容来替换这些block。根据blog_entries的值,输出可能看起来是这样的:

{% extends 'base.html' %}{% block content %}
<div class="jumbotron"><h1>Hello, INDEX!</h1><p>...</p><p><a class="btn btn-primary btn-lg" href="#" role="button">Learn more</a></p>
</div>
{% endblock %}  

访问index页面,效果如下:

修改articles.html,继承base.html

{% extends 'base.html' %}{% block content %}
<div class="article_list"><ul><li>红楼梦</li><li>三国演义</li><li>西游记</li><li>水浒传</li></ul>
</div>
{% endblock %}  

访问articles页面,效果如下:

修改authors.html,继承base.html

{% extends 'base.html' %}{% block content %}
<div class="author_list"><ul><li>曹雪芹</li><li>罗贯中</li><li>吴承恩</li><li>施耐庵</li></ul>
</div>
{% endblock %}  

访问authors页面,效果如下:

这样,就解决了代码重复问题

需求,访问不同页面时,更改title标签的属性

怎么做呢?很简单,在base.html里面的title标签位置,定义一个block

在花括号中间的title标签,表示默认值。如果子页面不设置block title,那么显示默认值。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8">{% block title %}<title>title</title>{% endblock title %}<link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"><style>* {margin: 0;padding: 0;}.header {width: 100%;height: 60px;background-color: #369;}.title {line-height: 60px;color: white;font-weight: 100;margin-left: 20px;font-size: 20px;}.container{margin-top: 20px;}</style>
</head>
<body><div class="header"><p class="title">路飞学诚</p>
</div><div class="container"><div class="row"><div class="col-md-3"><div class="panel panel-danger"><div class="panel-heading"><a href="http://127.0.0.1:8008/index/">首页</a></div><div class="panel-body">Panel content</div></div><div class="panel panel-success"><div class="panel-heading"><a href="http://127.0.0.1:8008/authors/">作者</a></div><div class="panel-body">Panel content</div></div><div class="panel panel-warning"><div class="panel-heading"><a href="http://127.0.0.1:8008/articles/">文章管理</a></div><div class="panel-body">Panel content</div></div></div><div class="col-md-9">{% block content %}{% endblock %}</div></div>
</div></body>
</html>  

修改articles.html,增加一个block

{% extends 'base.html' %}{% block content %}{{ block.super }}<div class="article_list"><ul><li>红楼梦</li><li>三国演义</li><li>西游记</li><li>水浒传</li></ul>
</div>
{% endblock %}{% block title %}
<title>Article</title>
{% endblock %}  

访问articles页面,标题就出来了,效果如下:

访问authors页面,由于没有设置block title,它显示默认值,效果如下:

现在有一个问题,右侧内容,写死了。比如文章页中的内容

修改views.py,2个视图,分别增加一个列表

def articles(request):acticle_list = ['红楼梦','三国演义','西游记','水浒传']return render(request, 'articles.html',{'acticle_list':acticle_list})def authors(request):author_list = ['曹雪芹','罗贯中','吴承恩','施耐庵']return render(request, 'authors.html',{'author_list':author_list})  

修改articles.html,增加一个for循环

{% extends 'base.html' %}{% block content %}<div class="article_list"><ul>{% for article in acticle_list %}<li>{{ article }}</li>{% endfor %}</ul>
</div>
{% endblock %}{% block title %}
<title>Article</title>
{% endblock %}  

修改authors.html,增加一个for循环

{% extends 'base.html' %}{% block content %}
<div class="author_list"><ul>{% for author in author_list %}<li>{{ author }}</li>{% endfor %}</ul>
</div>
{% endblock %}{% block title %}
<title>Author</title>
{% endblock %}  

重新访问2个页面,效果同上。

请注意,子模板并没有定义sidebar block,所以系统使用了父模板中的值。父模板的{% block %}标签中的内容总是被用作备选内容(fallback)。

这种方式使代码得到最大程度的复用,并且使得添加内容到共享的内容区域更加简单,例如,部分范围内的导航。

这里是使用继承的一些提示:

  • 如果你在模板中使用{% extends %}标签,它必须是模板中的第一个标签。其他的任何情况下,模板继承都无法工作。 

举例:下面这种写法是错误的。extends必须在block上面才行。

{% block content %}
<div class="jumbotron"><h1>Hello, INDEX!</h1><p>...</p><p><a class="btn btn-primary btn-lg" href="#" role="button">Learn more</a></p>
</div>
{% endblock %}{% extends 'base.html' %}  

访问网页,就会报错

  • 在base模板中设置越多的{% block %}标签越好。请记住,子模版不必定义全部父模板中的blocks,所以,你可以在大多数blocks中填充合理的默认内容,然后,之定义你需要的那一个。多一点钩子总比少一点好。

比如:base.html虽然定义了2个blocks,authors页面可以只继承一个。

  • 如果你发现你自己在大量的模板中复制内容,那可能意味着你应该把内容移动到父模板中的一个{ % block %}中。
  • If you need to get the content of the block from the parent template, the {{ block.super }} variable will do the trick. This is useful if you want to add to the contents of a parent block instead of completely overriding it. Data inserted using {{ block.super }} will not be automatically escaped (see the next section), since it was already escaped, if necessary, in the parent template.

翻译:

如果您需要从父模板获取块的内容,则{{block.super}}变量将执行该操作。如果你想添加父块的内容而不是完全覆盖父块的内容,这很有用。使用{{block.super}}插入的数据不会自动转义(请参阅下一节),因为它已经在父模板中被转义(如有必要)。

举例:

在base.html中block content里面增加一个h3标签。即系统子页面显示h3标签,同时子标签填充block content里面的内容时,h3标签不会被覆盖。加入一个{{ block.super}} 就可以了。

修改base.html,加入h3标签。修改block content部分

{% block content %}
<h3>详细内容</h3>
{% endblock %}  

修改articles.html,在block content下面一行,增加{{ block.super }}

{% extends 'base.html' %}{% block content %}
{{ block.super }}<div class="article_list"><ul>{% for article in acticle_list %}<li>{{ article }}</li>{% endfor %}</ul>
</div>
{% endblock %}{% block title %}
<title>Article</title>
{% endblock %}  

访问articles页面,效果如下

注意:如果子页面没有写{{ block.super }},那么h3标签就会被覆盖!

  • 为了更好的可读性,你页可以给你的{% endblock %}标签一个名字。例如:
{% block content %}
...
{% endblock content %}   

在大型模板中,这个方法帮你清楚的看到哪一个{% block %}标签被关闭了。

比如base.html中的block title,就是遵循这种写法。

  • 不能在一个模板中定义多个相同名字的block标签,否则会被覆盖 

需求:现在的页面是手动跳转的,需要点击菜单时,自动跳转页面。

修改base.html,增加3个a标签。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8">{% block title %}<title>title</title>{% endblock title %}<link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"><style>* {margin: 0;padding: 0;}.header {width: 100%;height: 60px;background-color: #369;}.title {line-height: 60px;color: white;font-weight: 100;margin-left: 20px;font-size: 20px;}.container{margin-top: 20px;}</style>
</head>
<body><div class="header"><p class="title">路飞学诚</p>
</div><div class="container"><div class="row"><div class="col-md-3"><div class="panel panel-danger"><div class="panel-heading"><a href="/index/">首页</a></div><div class="panel-body">Panel content</div></div><div class="panel panel-success"><div class="panel-heading"><a href="/authors/">作者</a></div><div class="panel-body">Panel content</div></div><div class="panel panel-warning"><div class="panel-heading"><a href="/articles/">文章管理</a></div><div class="panel-body">Panel content</div></div></div><div class="col-md-9">{% block content %}<h3>详细内容</h3>{% endblock %}</div></div>
</div></body>
</html>  

效果如下:

三、Django的模型层

ORM简介

ORM,全称是boject relation mapping。翻译过来,就是对象关系映射。

主要来学习MySQL操作,MySQL是一个软件。它的优点:1.免费  2.开源

pymysql,就是Mysql给python提供的接口。早期的接口叫mysqldb

ORM可以实现不写sql语句,就可以实现操作数据库。

核心是:用python类操作表,用对象操作记录。

ORM把对相应的类和属性操作,转换为sql语句,来操作数据库。它做了一个翻译的过程!

学习ORM,就是用什么语法,能翻译成什么样的sql语句。

看下图:

ORM的优点:

1.  符合python语法。

2.  自己写的sql语句,效率不够高。因为它直接传参,就可以使用了。

3.  它不属于硬编码,不针对于MySQL。同样适用于oracle等等数据库。

如果项目中的sql语句写死了,只要一涉及到换数据库,那么项目中的所有sql语句,逗得更换。如果用了ORM,只需要改一处,直接修改settings.py中的数据库引擎,换成oracle,就可以了。这样,方便数据库迭代,这时它最大的优点。

ORM的缺点:  

1.  执行效率低。看上图,它是从上层到下层的操作。

它有一个翻译的过程。所以不如直接写sql操作的执行效率高。

但是影响不大。真遇到这种情况,优化SQL就可以了。

效率问题,跟SQL有很大的关系。

现在不关心ORM效率问题。除非SQL语句的造诣达到了一定级别的时候,就需要使用原生SQL语句。

orm还提供了,执行原生SQL的接口。可以直接执行原生SQL。

刚开始写ORM时,一定要对应SQL语句,去写ORM

  • MVC或者MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库,这极大的减轻了开发人员的工作量,不需要面对因数据库变更而导致的无效劳动
  • ORM是“对象-关系-映射”的简称。

上图有一个错误,不是DATA而是DATE。

sql中的表

#sql中的表                                                      #创建表:CREATE TABLE employee(                                     id INT PRIMARY KEY auto_increment ,                    name VARCHAR (20),                                      gender BIT default 1,                                  birthday DATA ,                                         department VARCHAR (20),                                salary DECIMAL (8,2) unsigned,                          );#sql中的表纪录                                                  #添加一条表纪录:                                                          INSERT employee (name,gender,birthday,salary,department)            VALUES   ("alex",1,"1985-12-12",8000,"保洁部");               #查询一条表纪录:                                                           SELECT * FROM employee WHERE age=24;                               #更新一条表纪录:                                                           UPDATE employee SET birthday="1989-10-24" WHERE id=1;              #删除一条表纪录:                                                          DELETE FROM employee WHERE name="alex"                             #python的类
class Employee(models.Model):id=models.AutoField(primary_key=True)name=models.CharField(max_length=32)gender=models.BooleanField()birthday=models.DateField()department=models.CharField(max_length=32)salary=models.DecimalField(max_digits=8,decimal_places=2)#python的类对象#添加一条表纪录:emp=Employee(name="alex",gender=True,birthday="1985-12-12",epartment="保洁部")emp.save()#查询一条表纪录:Employee.objects.filter(age=24)#更新一条表纪录:Employee.objects.filter(id=1).update(birthday="1989-10-24")#删除一条表纪录:Employee.objects.filter(name="alex").delete()

class类的属性和字段是对应的。

decimal(10,2)表示最大长度为10位,小数点2位。那么整数部分,最大只能由8位。

ORM的映射关系:

          ORM引擎
python ---------------> sql类名                        表名
属性变量                    字段
属性值                      约束条件对象                        一条记录  

比如save(),就可以增加一条记录。所以是对象对应一条记录。

写项目的注意点:

写任何一个项目,
第一件事情,就是产品经理给你提需求。
最关键的时候,了解产品需求,逻辑关系。判断中途是否有bug!
如果做不了,一定要直接说,不能藏着。否则后期拖进度,就麻烦了。
一开始做宏观的梳理,否则后面会出现bug。导致项目推到重构!!!
对于表的设计,要慎重考虑。
早期,会经历很多碰壁的过程,这样你就能成长!
先创建表,分模块来创建表。
到了写代码的时候,反而是最简单的。
比如一个商城项目,设计表,梳理流程,花了2个月。写代码,几个星期就完成了。  

单表操作

创建表

1.  创建模型

默认在应用文件下,有一个models.py文件,比如app01应用。

在app01下的models.py中创建模型:

from django.db import models# Create your models here.class Book(models.Model):id=models.AutoField(primary_key=True)title=models.CharField(max_length=32)state=models.BooleanField()pub_date=models.DateField()price=models.DecimalField(max_digits=8,decimal_places=2)publish=models.CharField(max_length=32)

ORM没法创建数据库,它只能操作表!

类名,首先字母要大写,它必须继承models.Model。这是固定写法!  

2. 更多字段和参数

每个字段有一些特有的参数,例如,CharField需要max_length参数来指定VARCHAR数据库字段的大小。还有一些适用于所有字段的通用参数。这些参数在文档中有详细定义,这里我们只简单介绍一些最常用的:

更多字段:  

<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> BooleanFieldA 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-#populatethe 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如果为True,Django 将用NULL 来在数据库中存储空值。 默认值是 False.(1)blank如果为True,该字段允许不填。默认为False。
要注意,这与 null 不同。null纯粹是数据库范畴的,而 blank 是数据验证范畴的。
如果一个字段的blank=True,表单的验证将允许该字段是空值。如果字段的blank=False,该字段就是必填的。(2)default字段的默认值。可以是一个值或者可调用对象。如果可调用 ,每有新对象被创建它都会被调用。(3)primary_key如果为True,那么这个字段就是模型的主键。如果你没有指定任何一个字段的primary_key=True,
Django 就会自动添加一个IntegerField字段做为主键,所以除非你想覆盖默认的主键行为,
否则没必要设置任何一个字段的primary_key=True。(4)unique如果该值设置为 True, 这个数据字段的值在整张表中必须是唯一的(5)choices
由二元组组成的一个可迭代对象(例如,列表或元组),用来给字段提供选择项。 如果设置了choices ,默认的表单将是一个选择框而不是标准的文本框,<br>而且这个选择框的选项就是choices 中的选项。

3. settings配置

首先是注册app:

修改mysite下的settings.py文件里面的INSTALLED_APPS。注册你的app,最后一行添加,我用的app名是app01

INSTALLED_APPS = ['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','app01',
]  

不注册它,你的数据库就不知道该给哪个app创建表。

若想将模型转为mysql数据库中的表,需要在settings中配置:

DATABASES = {'default': {'ENGINE': 'django.db.backends.mysql',   # 数据库引擎mysql'NAME': 'book',       # 你要存储数据的库名,事先要创建之'USER': 'root',      # 数据库用户名'PASSWORD': '',      # 密码'HOST': 'localhost', # 主机'PORT': '3306',      # 数据库使用的端口}
}  

注意1:NAME即数据库的名字,在mysql连接前该数据库必须已经创建,而上面的sqlite数据库下的db.sqlite3则是项目自动创建USER和PASSWORD分别是数据库的用户名和密码。

由于ORM不能创建数据库,需要手动创建。

进入mysql,创建数据库book。

C:\Users\xiao>mysql -u root
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 9
Server version: 5.7.22-log MySQL Community Server (GPL)Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.mysql> CREATE DATABASE book DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
Query OK, 1 row affected (0.01 sec)mysql>  

django连接MySQL,使用的是pymysql模块,必须得安装2个模块。否则后面会创建表不成功!或者提示no module named MySQLdb   

pip3 install pymysql
pip3 install mysqlclient  

接下来要在pycharm的teminal中通过命令创建数据库的表。有2条命令,分别是:

python  manage.py  makemigrations

它的作用相当于在该app下建立migrations目录,并记录下你所有的关于modes.py的改动,比如0001.initial.py,但是这个改动还没有作用到数据库文件

再输入命令:

python  manage.py  migrate 

它是将该改动作用到数据库文件,比如创建表,修改表字段之类的操作。

注意2:如果想打印orm转换过程中的sql,需要在settings中进行如下配置:

位置无所谓,但建议最后一行添加!

LOGGING = {'version': 1,'disable_existing_loggers': False,'handlers': {'console':{'level':'DEBUG','class':'logging.StreamHandler',},},'loggers': {'django.db.backends': {'handlers': ['console'],'propagate': True,'level':'DEBUG',},}
}  

转载于:https://www.cnblogs.com/Black-rainbow/p/9231197.html

Django模板自定义标签和过滤器,模板继承(extend),Django的模型层相关推荐

  1. django中自定义标签和过滤器

    django中自定义标签和过滤器 原文:http://www.cnblogs.com/MnCu8261/p/5934203.html 纪念如何填了半天的坑,红色重点 想要实现自定义标签和过滤器需要进行 ...

  2. python-django_自定义标签和过滤器_模板的导入与继承_静态文件使用方式_inclusion_tag的用法

    django 1. 自定义标签和过滤器 1. 自定义过滤器 -第一步:在settings中的INSTALLED_APPS配置当前app,不然django无法找到自定义的simple_tag-第二步:在 ...

  3. django “如何”系列4:如何编写自定义模板标签和过滤器

    django的模板系统自带了一系列的内建标签和过滤器,一般情况下可以满足你的要求,如果觉得需更精准的模板标签或者过滤器,你可以自己编写模板标签和过滤器,然后使用{% load %}标签使用他们. 代码 ...

  4. Django 2.1.3 文档-模板-内置标签和过滤器(tagfilter)

    内置标签和过滤器 1.内置标签 一览 autoescape block comment csrf_token cycle debug extends filter(标签filter而不是过滤器filt ...

  5. Django内建模版标签和过滤器

    第四章列出了许多的常用内建模板标签和过滤器.然而,Django自带了更多的内建模板标签及过滤器.这章附录列出了截止到编写本书时,Django所包含的各个内建模板标签和过滤器,但是,新的标签是会被定期地 ...

  6. Django07:模板语法/标签/inclusion_tag/模版的继承

    模板语法传值 列表:l=['a','b','c'] 集合:se{'a','yy','ss'} 元组:t=(111,222,333) render(request.'index,html',locals ...

  7. Django 六——自定义标签、图片验证码、发送邮件、评论树、组合搜索

    1.自定义标签 2.图片验证码 3.生成邮箱验证码.发送邮件 4.评论树实现 5.组合搜索(Q) 1.自定义标签 配置: a.在app中新建文件夹  templatetags,里面新建  xx.py文 ...

  8. The Definitive Guide To Django 2 学习笔记(八) 第四章 模板 (四)基本的模板标签和过滤器...

    标签 下面的部分概述了常见的Django标签. if/else {%if%} 标签 对一个变量值进行测试,如果结果为true,系统将会显示在{%if%} 和 {%endif%}之间的一切,看个例子: ...

  9. 【django】三、常用的模板标签和过滤器

    文章目录 添加跳转方法 前端页面 访问某个博客url设置 访问主页url设置 添加博客总数的显示 判断为空,添加一条提示 长博客显示限制 过滤时间,添加显示字段 博客类跳转到标签的功能 常用的模板标签 ...

最新文章

  1. Linux 内核中的 GCC 特性(zz)
  2. Flask/Django/Tornado语法对比(持续更新中)
  3. 汇编语言(二十八)之统计单词
  4. 用C语言实现:判断1000-2000年之间的闰年。
  5. 查看oracle空间使用率,Oracle 查看表空间使用率
  6. android 应用使用Root权限执行linux命令
  7. 解决Ubuntu ssh 登录慢问题
  8. 分享几款常用的MySQL管理工具
  9. win10杜比全景声评测_Win10安装杜比全景声音效教程
  10. 信源编码的三种方式与实现
  11. Mac本换ssd注意事项
  12. 【科研】沈向洋、华刚:读科研论文的三个层次、四个阶段与十个问题
  13. 云计算 | Gartner最新IaaS魔力象限详读
  14. Spring Security Oauth2:授权模式、简单模式 、密码模式 和 客户端模式
  15. Revit教程合集110部
  16. get-element-by-id转换为getElementById
  17. 从SAP的核心优势看SAP四大战略成功的可能
  18. libvlc_media_player_stop死锁问题解决
  19. 网易视频云分享:如何搭建MP4媒体服务器
  20. 软件测试:Jmeter性能测试以及压力测试

热门文章

  1. Math: Fibonacci
  2. BZOJ 4602: [Sdoi2016]齿轮 dfs
  3. 学习OpenCV——BOW特征提取函数(特征点篇)
  4. nodejs版本更新问题:express不是内部或外部命令
  5. LoNg wAy tO Go
  6. Unicode和UTF-8之间的转换详解
  7. impala的详细介绍--图文描述
  8. Java定时器的cron设置详解Quartz
  9. python基础之元组定义进阶操作、字典定义进阶操作
  10. 塑料壳上下扣合的卡扣设计_一种塑料件卡扣结构制造技术