Django2.0使用

创建项目:

  1. 通过命令行的方式:首先要进入到安装了django的虚拟环境中。然后执行命令:
    django-admin startproject [项目的名称]
    
    这样就可以在当前目录下创建一个项目了。
  2. 通过pycharm的方式:文件->新建项目->选择django。然后指定项目所在的路径,以及Python解释器,再点击Create就可以创建项目了。

运行项目:

  1. 终端:进入到项目文件夹中,然后执行以下命令即可运行:
    python manage.py runserver
    
  2. pycharm:直接点击右上角的绿色三角箭头按钮就可以了。注意:用pycharm运行项目,要避免一个项目运行多次。。在项目配置中,把“只用单一实例”那个选项勾选上,避免以上的问题。

改变端口号:

  1. 在终端:运行的时候加上一个端口号就可以了。命令为:python manage.py runserver 9000
  2. 在pycharm中:右上角->项目配置->port。改成你想要的端口号,重新运行。

让同局域网中的其他电脑访问本机的项目:

  1. 让项目运行到额时候,host为0.0.0.0。

    • 在终端,使用命令:python manage.py runserver 0.0.0.0:8000
    • 在pycharm,右上角->项目配置->host。改成0.0.0.0
  2. settings.py文件中,配置ALLOWED_HOSTS,将本机的ip地址添加进去。示例代码如下:

    ALLOWED_HOSTS = ['192.168.0.103']
    

    注意:要关闭自己电脑的防火墙才行。

项目结构分析:

  1. manange.py:以后和项目交互基本上都是基于这个文件。一般都是在终端输入python manage.py [子命令]。可以输入python manage.py help看下能做什么事情。除非你知道你自己在做什么,一般情况下不应该编辑这个文件。
  2. settings.py:保存项目所有的配置信息。
  3. urls.py:用来做url与视图函数映射的。以后来了一个请求,就会从这个文件中找到匹配的视图函数。
  4. wsig.py:专门用来做部署的。不需要修改。

django推荐的项目规范:

按照功能或者模块进行分层,分成一个个app。所有和某个模块相关的视图都写在对应的app的views.py中,并且模型和其他的也是类似。然后django已经提供了一个比较方便创建app的命令叫做python manage.py startapp [app的名称]。把所有的代码写在各自的app中。

DEBUG模式:

  1. 如果开启了DEBUG模式,那么以后我们修改了Django项目的代码,然后按下ctrl+s,那么Django就会自动的给我们重启项目,不需要手动重启。
  2. 如果开启了DEBUG模式,那么以后Django项目中的代码出现bug了,那么在浏览器中和控制台会打印出错信息。
  3. 在生产环境中,禁止开启DEBUG模式,不然有很大的安全隐患。
  4. 如果将DEBUG设置为False,那么必须要设置ALLOWED_HOSTS.

ALLOWED_HOSTS:

这个变量是用来设置以后别人只能通过这个变量中的ip地址或者域名来进行访问。

视图函数

  1. 视图函数的第一个参数必须是request。这个参数绝对不能少。
  2. 视图函数的返回值必须是django.http.response.HttpResponseBase的子类的对象。

url相关:django2.0

url映射:

不使用缓存去加载页面ctrl+shift+r

  1. 为什么会去urls.py文件中寻找映射呢? 是因为在settings.py文件中配置了ROOT_URLCONFurls.py。所有django会去urls.py中寻找。
  2. urls.py中我们所有的映射,都应该放在urlpatterns这个变量中。
  3. 所有的映射不是随便写的,而是使用path函数或者是re_path函数进行包装的。

url传参数:

  1. 采用在url中使用变量的方式:在path的第一个参数中,使用<参数名>的方式可以传递参数。然后在视图函数中也要写一个参数,视图函数中的参数必须和url中的参数名称保持一致,不然就找不到这个参数。另外,url中可以传递多个参数。path("book/detail/<book_id>/<category_id>/",views.book_detail)多个参数

  2. 采用查询字符串的方式:在url中,不需要单独的匹配查询字符串的部分。只需要在视图函数中使用request.GET.get('参数名称')的方式来获取。示例代码如下:

    def author_detail(request):  author_id = request.GET['id']  text = '作者的id是:%s' % author_id  return HttpResponse(text)
    

    因为查询字符串使用的是GET请求,所以我们通过request.GET来获取参数。并且因为GET是一个类似于字典的数据类型,所有获取值跟字典的方式都是一样的。

url参数的转换器:

path("book/publisher/<path:publisher_id>/",views.publisher_detail)

  1. str:除了斜杠/以外所有的字符都是可以的。
  2. int:只有是一个或者多个的阿拉伯数字。
  3. path:所有的字符都是满足的。
  4. uuid:只有满足uuid.uuid4()这个函数返回的字符串的格式。
  5. slug:英文中的横杆或者英文字符或者阿拉伯数字或者下划线才满足

urls模块化(路由转发):

如果项目变得越来越大。那么url会变得越来越多。如果都放在主urls.py文件中,那么将不太好管理。因此我们可以将每个app自己的urls放到自己的app中进行管理。一般我们会在app中新建一个urls.py文件用来存储所有和这个app相关的子url。 需要注意的地方:

  1. 应该使用include函数包含子urls.py,并且这个urls.py的路径是相对于项目的路径。示例代码如下:
    # 父url
    urlpatterns = [  path('admin/', admin.site.urls),  path('book/',include('book.urls')) ] # 子url urlpatterns = [  path('reports/', credit_views.report),  path('reports/<int:id>/', credit_views.report), ]
    
  2. appurls.py中,所有的url匹配也要放在一个叫做urlpatterns的变量中,否则找不到。
  3. url是会根据主urls.py和app中的urls.py进行拼接的,因此注意不要多加斜杠。

include函数的用法:

  1. include(module,namespace=None):
    • module:子url的模块字符串。
    • namespace:实例命名空间。这个地方需要注意一点。如果指定实例命名空间,那么前提必须要先指定应用命名空间。也就是在子urls.py中添加app_name变量。
  2. include((pattern_list, app_namespace), namespace=None):include函数的第一个参数既可以为一个字符串,也可以为一个元组,如果是元组,那么元组的第一个参数是子urls.py模块的字符串,元组的第二个参数是应用命名空间。这样的话,namespace就可传可不传。也就是说,应用命名空间既可以在子urls.py中通过app_name指定,也可以在include函数中指定。
  3. include(pattern_list):pattern_list是一个列表。这个列表中装的是path或者re_path函数。也就是说,可以把子url中的path放在这个列表中,实例代码如下:
    path('movie/',include([  path('',views.movie),  path('list/',views.movie_list), ]))
    

url命名:

为什么需要url命名?

因为url是经常变化的。如果在代码中写死可能会经常改代码。给url取个名字,以后使用url的时候就使用他的名字进行反转就可以了,就不需要写死url了。

如何给一个url指定名称?

path函数中,传递一个name参数就可以指定。示例代码如下:

urlpatterns = [
 path('',views.index,name='index'),  path('login/',views.login,name='login') ]
应用命名空间:

在多个app之间,有可能产生同名的url。这时候为了避免反转url的时候产生混淆,可以使用应用命名空间,来做区分。定义应用命名空间非常简单,只要在appurls.py中定义一个叫做app_name的变量,来指定这个应用的命名空间即可。示例代码如下:

# 应用命名空间
app_name = 'front'  urlpatterns = [  path('',views.index,name='index'),  path('login/',views.login,name='login') ]

以后在做反转的时候就可以使用应用命名空间:url名称的方式进行反转。示例代码如下:

login_url = reverse('front:login')
应用(app)命名空间和实例命名空间:

一个app,可以创建多个实例。可以使用多个url映射同一个app。所以这就会产生一个问题。以后在做反转的时候,如果使用应用命名空间,那么就会发生混淆。为了避免这个问题。我们可以使用实例命名空间。实例命名空间也是非常简单,只要在include函数中传递一个namespace变量即可。示例代码如下:

urlpatterns = [
 path('',include('front.urls')),  # 同一个app下有两个实例  path('cms1/',include('cms.urls',namespace='cms1')),  path('cms2/',include('cms.urls',namespace='cms2')), ]

以后在做反转的时候,就可以根据实例命名空间来指定具体的url。示例代码如下:

def index(request):  username = request.GET.get("username")  if username:  return HttpResponse('CMS首页')  else:  # 获取当前的命名空间  current_namespace = request.resolver_match.namespace  return redirect(reverse("%s:login"%current_namespace))

re_path

  1. re_path和path的作用都是一样的。只不过re_path是在写url的时候可以用正则表达式,功能更加强大。

  2. 写正则表达式都推荐使用原生字符串。也就是以r开头的字符串。

  3. 在正则表达式中定义变量,需要使用圆括号括起来。这个参数是有名字的,那么需要使用?P<参数的名字>。然后在后面添加正则表达式的规则。示例代码如下:

    from django.urls import re_path from . import views  urlpatterns = [  # r"":代表的是原生字符串(raw)  re_path(r'^$',views.article),  # /article/list/<year>/  re_path(r"^list/(?P<year>\d{4})/$",views.article_list),  re_path(r"^list/(?P<month>\d{2})/$",views.article_list_month) ]
    
  4. 如果不是特别要求。直接使用path就够了,省的把代码搞的很麻烦(因为正则表达式其实是非常晦涩的,特别是一些比较复杂的正则表达式,今天写的明天可能就不记得了)。除非是url中确实是需要使用正则表达式来解决才使用re_path

reverse

  1. 如果在反转url的时候,需要添加参数,那么可以传递kwargs参数到revers函数中。示例代码如下:
    detail_url = reverse('detail',kwargs={
                     "article_id":1,'page':2})
    
  2. 如果想要添加查询字符串的参数,则必须手动的进行拼接。示例代码如下:
    login_url = reverse('login') + "?next=/"
    

在“文章分类”参数传到视图函数之前要把这些分类分开来存储到列表中。 比如参数是python+django,那么传到视图函数的时候就要变成['python','django']

以后在使用reverse反转的时候,限制传递“文章分类”的参数应该是一个列表,并且要将这个列表变成python+django的形式。

自定义URL转换器

第一种办法:

之前已经学到过一些django内置的url转换器,包括有int、uuid等。有时候这些内置的url转换器并不能满足我们的需求,因此django给我们提供了一个接口可以让我们自己定义自己的url转换器。

自定义url转换器按照以下五个步骤来走就可以了:

  1. 为了模块化,在app里建一个单独的文件如:converters.py,在其中定义一个类,直接继承自object就可以了。
  2. 在类中定义一个属性regex,这个属性是用来限制url转换器规则的正则表达式。
  3. 实现to_python(self,value)方法,这个方法是将url中的值转换一下,然后传给视图函数的。
  4. 实现to_url(self,value)方法,这个方法是在做url反转的时候,将传进来的参数转换后拼接成一个正确的url。
  5. 将定义好的转换器,使用django.urls.converters.register_converter方法注册到django中。
  6. 需要在当前app包中的__init__.py中引入一下这个包from . import converters
  7. 源码参照from django.urls import converters中已经定义好的去写。

示例代码如下:

from django.urls import register_converter  class CategoryConverter(object):  regex = r'\w+|(\w+\+\w+)+'   def to_python(self,value):  # python+django+flask  # ['python','django','flask']  result = value.split("+")  return result   def to_url(self,value):  # value:['python','django','flask']  # python+django+flask  if isinstance(value,list):  result = "+".join(value)  return result  else:  raise RuntimeError("转换url的时候,分类参数必须为列表!")  register_converter(CategoryConverter,'cate')

第二种办法:

写一个类,并包含下面的成员和属性:

  • 类属性regex:一个字符串形式的正则表达式属性;
  • to_python(self, value) 方法:一个用来将匹配到的字符串转换为你想要的那个数据类型,并传递给视图函数。如果转换失败,它必须弹出ValueError异常;
  • to_url(self, value)方法:将Python数据类型转换为一段url的方法,上面方法的反向操作。

例如,新建一个converters.py文件,与urlconf同目录,写个下面的类:

class FourDigitYearConverter:
    regex = '[0-9]{4}'

    def to_python(self, value):
 return int(value)   def to_url(self, value):  return '%04d' % value

写完类后,在URLconf 中注册,并使用它,如下所示,注册了一个xxxx:

from django.urls import register_converter, path  from . import converters, views  register_converter(converters.FourDigitYearConverter, 'xxxx') # 注册  urlpatterns = [  path('articles/2003/', views.special_case_2003),  path('articles/<xxxx:year>/', views.year_archive),  ... ]

URL映射的时候指定默认参数

使用path或者是re_path的后,在route中都可以包含参数,而有时候想指定默认的参数,这时候可以通过以下方式来完成。示例代码如下:

from django.urls import path  from . import views  urlpatterns = [  path('blog/', views.page),  path('blog/page<int:num>/', views.page), ]  # View (in blog/views.py) def page(request, num=1):  # Output the appropriate page of blog entries, according to num.  ...

当在访问blog/的时候,因为没有传递num参数,所以会匹配到第一个url,这时候就执行view.page这个视图函数,而在page函数中,又有num=1这个默认参数。因此这时候就可以不用传递参数。而如果访问blog/1的时候,因为在传递参数的时候传递了num,因此会匹配到第二个url,这时候也会执行views.page,然后把传递进来的参数传给page函数中的num。

使用正则表达式

Django2.0的url虽然改‘配置’了,但它依然向老版本兼容。而这个兼容的办法,就是用re_path()方法代替path()方法。re_path()方法在骨子里,根本就是以前的url()方法,只不过导入的位置变了。下面是一个例子,对比一下Django1.11时代的语法,有什么太大的差别?

from django.urls import path, re_path  from . import views  urlpatterns = [  path('articles/2003/', views.special_case_2003),  re_path(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),  re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),  re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<slug>[\w-]+)/$', views.article_detail), ]

path()方法不同的在于两点:

  • year中匹配不到10000等非四位数字,这是正则表达式决定的
  • 传递给视图的所有参数都是字符串类型。而不像path()方法中可以指定转换成某种类型。在视图中接收参数时一定要小心。

自定义错误页面

当Django找不到与请求匹配的URL时,或者当抛出一个异常时,将调用一个错误处理视图。Django默认的自带的错误视图包括400、403、404和500,分别表示请求错误、拒绝服务、页面不存在和服务器错误。它们分别位于:

  • handler400 —— django.conf.urls.handler400。
  • handler403 —— django.conf.urls.handler403。
  • handler404 —— django.conf.urls.handler404。
  • handler500 —— django.conf.urls.handler500。

这些值可以在根URLconf中设置。在其它app中的二级URLconf中设置这些变量无效。

Django有内置的HTML模版,用于返回错误页面给用户,但是这些403,404页面实在丑陋,通常我们都自定义错误页面。

首先,在根URLconf中额外增加下面的条目,并导入views模块:

from django.contrib import admin from django.urls import path from app import views  urlpatterns = [  path('admin/', admin.site.urls), ]  # 增加的条目 handler400 = views.bad_request handler403 = views.permission_denied handler404 = views.page_not_found handler500 = views.error

然后在,app/views.py文件中增加四个处理视图:

def bad_request(request):  return render(request, '400.html')   def permission_denied(request):  return render(request, '403.html')   def page_not_found(request):  return render(request, '404.html')   def error(request):  return render(request, '500.html') 

再根据自己的需求,创建对应的400、403、404、500.html四个页面文件,就可以了(要注意好模板文件的引用方式,视图的放置位置等等)。

模板

在之前的章节中,视图函数只是直接返回文本,而在实际生产环境中其实很少这样用,因为实际的页面大多是带有样式的HTML代码,这可以让浏览器渲染出非常漂亮的页面。目前市面上有非常多的模板系统,其中最知名最好用的就是DTL和Jinja2。DTL是Django Template Language三个单词的缩写,也就是Django自带的模板语言。当然也可以配置Django支持Jinja2等其他模板引擎,但是作为Django内置的模板语言,和Django可以达到无缝衔接而不会产生一些不兼容的情况。因此建议大家学习好DTL。

DTL与普通的HTML文件的区别

DTL模板是一种带有特殊语法的HTML文件,这个HTML文件可以被Django编译,可以传递参数进去,实现数据动态化。在编译完成后,生成一个普通的HTML文件,然后发送给客户端。

渲染模板:

渲染模板有多种方式。这里讲下两种常用的方式。

  1. render_to_string:找到模板,然后将模板编译后渲染成Python的字符串格式。最后再通过HttpResponse类包装成一个HttpResponse对象返回回去。示例代码如下:
from django.template.loader import render_to_string  from django.http import HttpResponse  def book_detail(request,book_id):  html = render_to_string("detail.html")  return HttpResponse(html)
  1. 以上方式虽然已经很方便了。但是django还提供了一个更加简便的方式,直接将模板渲染成字符串和包装成HttpResponse对象一步到位完成。示例代码如下:
 from django.shortcuts import render  def book_list(request):  return render(request,'list.html')

模版查找路径

在项目的settings.py文件中。有一个TEMPLATES配置,这个配置包含了模板引擎的配置,模板查找路径的配置,模板上下文的配置等。模板路径可以在两个地方配置。

  1. DIRS:这是一个列表,在这个列表中可以存放所有的模板路径,以后在视图中使用render或者render_to_string渲染模板的时候,会在这个列表的路径中查找模板。
  2. APP_DIRS:默认为True,这个设置为True后,会在INSTALLED_APPS的安装了的APP下的templates文件加中查找模板。
  3. 查找顺序:比如代码render('list.html')。先会在DIRS这个列表中依次查找路径下有没有这个模板,如果有,就返回。如果DIRS列表中所有的路径都没有找到,那么会先检查当前这个视图所处的app是否已经安装,如果已经安装了,那么就先在当前这个app下的templates文件夹中查找模板,如果没有找到,那么会在其他已经安装了的app中查找。如果所有路径下都没有找到,那么会抛出一个TemplateDoesNotExist的异常。
  4. DIRS > 当前APP > 其他APP

模版变量

  1. 在模版中使用变量,需要将变量放到{ { 变量 }}中。
  2. 如果想要访问对象的属性,那么可以通过对象.属性名来进行访问。
    class Person(object):  def __init__(self,username):  self.username = username  context = {  'person': p }
    
    以后想要访问personusername,那么就是通过person.username来访问。
  3. 如果想要访问一个字典的key对应的value,那么只能通过字典.key的方式进行访问,不能通过中括号[]的形式进行访问。
    context = {
     'person': {  'username':'zhiliao'  } }
    
    那么以后在模版中访问username。就是以下代码person.username
  4. 因为在访问字典的key时候也是使用点.来访问,因此不能在字典中定义字典本身就有的属性名当作key,否则字典的那个属性将编程字典中的key了。
    context = {
     'person': {  'username':'zhiliao',  'keys':'abc'  } }
    
    以上因为将keys作为person这个字典的key了。因此以后在模版中访问person.keys的时候,返回的不是这个字典的所有key,而是对应的值。
  5. 如果想要访问列表或者元组,那么也是通过点.的方式进行访问,不能通过中括号[]的形式进行访问。这一点和python中是不一样的。示例代码如下:
    {
             { persons.1 }}
    

if语句

  1. 所有的标签都是在{%%}之间。
  2. if标签有闭合标签。就是{% endif %}
  3. if标签的判断运算符,就跟python中的判断运算符是一样的。==、!=、<、<=、>、>=、in、not in、is、is not这些都可以使用。
  4. 还可以使用elif以及else等标签。

for...in...

for...in…标签

for...in...类似于Python中的for...in...。可以遍历列表、元组、字符串、字典等一切可以遍历的对象。示例代码如下:

{
       % for person in persons %} <p>{
                   { person.name }}</p> {
                            % endfor %}

如果想要反向遍历,那么在遍历的时候就加上一个reversed。示例代码如下:

{
       % for person in persons reversed %} <p>{
                    { person.name }}</p> {
                             % endfor %}

遍历字典的时候,需要使用itemskeysvalues等方法。在DTL中,执行一个方法不能使用圆括号的形式。遍历字典示例代码如下:

{
       % for key,value in person.items %} <p>key{
                         { key }}</p> <p>value{
                                     { value }}</p> {
                                            % endfor %}

for循环中,DTL提供了一些变量可供使用。这些变量如下:

  • forloop.counter:当前循环的下标。以1作为起始值。
  • forloop.counter0:当前循环的下标。以0作为起始值。
  • forloop.revcounter:当前循环的反向下标值。比如列表有5个元素,那么第一次遍历这个属性是等于5,第二次是4,以此类推。并且是以1作为最后一个元素的下标。
  • forloop.revcounter0:类似于forloop.revcounter。不同的是最后一个元素的下标是从0开始。
  • forloop.first:是否是第一次遍历。
  • forloop.last:是否是最后一次遍历。
  • forloop.parentloop:如果有多个循环嵌套,那么这个属性代表的是上一级的for循环。

** 模板中的for...in...没有continue和break语句,这一点和Python中有很大的不同,一定要记清楚! **

for...in...empty`标签

这个标签使用跟for...in...是一样的,只不过是在遍历的对象如果没有元素的情况下,会执行empty中的内容。示例代码如下:

{
       % for person in persons %} <li>{
                   { person }}</li> {
                          % empty %} 暂时还没有任何人 {
                                  % endfor %}

with标签

  1. 在模板中,想要定义变量,可以通过with语句来实现。
  2. with语句有两种使用方式,第一种是with xx=xxx的形式,第二种是with xxx as xxx的形式。
  3. 定义的变量只能在with语句块中使用,在with语句块外面使用取不到这个变量。 示例代码如下:
    {
       % with zs=persons.0%}  <p>{
                     { zs }}</p>  <p>{
                               { zs }}</p>  {
                                      % endwith %}  下面这个因为超过了with语句块,因此不能使用  <p>{
                                                   { zs }}</p>   {
                                                           % with persons.0 as zs %}  <p>{
                                                                         { zs }}</p>  {
                                                                                % endwith %}

url标签

url标签:在模版中,我们经常要写一些url,比如某个a标签中需要定义href属性。当然如果通过硬编码的方式直接将这个url写死在里面也是可以的。但是这样对于以后项目维护可能不是一件好事。因此建议使用这种反转的方式来实现,类似于django中的reverse一样。示例代码如下:

<a href="{
           % url 'book:list' %}">图书列表页面</a>

如果url反转的时候需要传递参数,那么可以在后面传递。但是参数分位置参数和关键字参数。位置参数和关键字参数不能同时使用。示例代码如下:

# path部分
path('detail/<book_id>/',views.book_detail,name='detail')  # url反转,使用位置参数 <a href="{
                             % url 'book:detail' 1 %}">图书详情页面</a>  # url反转,使用关键字参数 <a href="{
                                               % url 'book:detail' book_id=1 %}">图书详情页面</a>

如果想要在使用url标签反转的时候要传递查询字符串的参数,那么必须要手动在在后面添加。示例代码如下:

<a href="{
           % url 'book:detail' book_id=1 %}?page=1">图书详情页面</a>

如果需要传递多个参数,那么通过空格的方式进行分隔。示例代码如下:

<a href="{
           % url 'book:detail' book_id=1 page=2 %}">图书详情页面</a>

autoescape自动转义

  1. DTL中默认已经开启了自动转义。会将那些特殊字符进行转义。比如会将<转义成&lt;等。
  2. 如果你不知道自己在干什么,那么最好是使用DTL的自动转义。这样网站才不容易出现XSS漏洞。
  3. 如果变量确实是可信任的。那么可以使用autoescape标签来关掉自动转义。示例代码如下:
    {
             % autoescape off %}  {
                    { info }} {
                        % endautoescape %}
    

verbatim标签

verbatim标签:默认在DTL模板中是会去解析那些特殊字符的。和其他模板相冲突的时候,需要关闭解析的时候,比如{%%}以及{ { 等。如果你在某个代码片段中不想使用DTL的解析引擎。那么你可以把这个代码片段放在verbatim标签中。示例代码下:

{
       % verbatim %} {
             {
             if dying}}Still alive.{
                    {
                    /if}} // 这样就是原始字符不会被当成变量解析 {
                           % endverbatim %}

Django模板过滤器

为什么需要过滤器?

因为在DTL中,不支持函数的调用形式(),因此不能给函数传递参数,这将有很大的局限性。而过滤器其实就是一个函数,可以对需要处理的参数进行处理,并且还可以额外接收一个参数(也就是说,最多只能有2个参数)。

add过滤器:

将传进来的参数添加到原来的值上面。这个过滤器会尝试将参数转换成整形然后进行相加。如果转换成整形过程中失败了,那么会将参数进行拼接。如果是字符串,那么会拼接成字符串,如果是列表,那么会拼接成一个列表。示例代码如下:

{
       { value|add:"2" }}

如果value是等于4,那么结果将是6。如果value是等于一个普通的字符串,比如abc,那么结果将是abc2add过滤器的源代码如下:

def add(value, arg): """Add the arg to the value.""" try: return int(value) + int(arg) except (ValueError, TypeError): try: return value + arg except Exception: return ''

cut过滤器

移除值中所有指定的字符串。类似于python中的replace(args,"")。示例代码如下:

{
       { value|cut:" " }}

以上示例将会移除value中所有的空格字符。cut过滤器的源代码如下:

def cut(value, arg): """Remove all values of arg from the given string.""" safe = isinstance(value, SafeData) value = value.replace(arg, '') if safe and arg != ';': return mark_safe(value) return value

date过滤器

将一个日期按照指定的格式,格式化成字符串。示例代码如下:

# 数据
context = { "birthday": datetime.now() }  # 模版 {
                        { birthday|date:"Y/m/d" }}

那么将会输出2018/02/01。其中Y代表的是四位数字的年份,m代表的是两位数字的月份,d代表的是两位数字的日。
还有更多时间格式化的方式。见下表。

格式字符 描述 示例
Y 四位数字的年份 2018
m 两位数字的月份 01-12
n 月份,1-9前面没有0前缀 1-12
d 两位数字的天 01-31
j 天,但是1-9前面没有0前缀 1-31
g 小时,12小时格式的,1-9前面没有0前缀 1-12
h 小时,12小时格式的,1-9前面有0前缀 01-12
G 小时,24小时格式的,1-9前面没有0前缀 1-23
H 小时,24小时格式的,1-9前面有0前缀 01-23
i 分钟,1-9前面有0前缀 00-59
s 秒,1-9前面有0前缀 00-59

default

如果值被评估为False。比如[]""None{}等这些在if判断中为False的值,都会使用default过滤器提供的默认值。为True 时,则会使用value的值,示例代码如下:

{
       { value|default:"nothing" }}

如果value是等于一个空的字符串。比如"",那么以上代码将会输出nothing

default_if_none

如果值是None,那么将会使用default_if_none提供的默认值。这个和default有区别,default是所有被评估为False的都会使用默认值。而default_if_none则只有这个值是等于None的时候才会使用默认值。示例代码如下:

{
       { value|default_if_none:"nothing" }}

如果value是等于""也即空字符串,那么以上会输出空字符串。如果value是一个None值,以上代码才会输出nothing

first

返回列表/元组/字符串中的第一个元素。示例代码如下:

{
       { value|first }}

如果value是等于['a','b','c'],那么输出将会是a

last

返回列表/元组/字符串中的最后一个元素。示例代码如下:

{
       { value|last }}

如果value是等于['a','b','c'],那么输出将会是c

floatformat

使用四舍五入的方式格式化一个浮点类型。如果这个过滤器没有传递任何参数。那么只会在小数点后保留一个小数,如果小数后面全是0,那么只会保留整数。当然也可以传递一个参数,标识具体要保留几个小数。

  1. 如果没有传递参数:
value 模版代码 输出
34.23234 `{ { value floatformat }}`
34.000 `{ { value floatformat }}`
34.260 `{ { value floatformat }}`
  1. 如果传递参数:
value 模版代码 输出
34.23234 `{ {value floatformat:3}}`
34.0000 `{ {value floatformat:3}}`
34.26000 `{ {value floatformat:3}}`

join

类似与Python中的join,将列表/元组/字符串用指定的字符进行拼接。示例代码如下:

{
       { value|join:"/" }}

如果value是等于['a','b','c'],那么以上代码将输出a/b/c

length

获取一个列表/元组/字符串/字典的长度。示例代码如下:

{
       { value|length }}

如果value是等于['a','b','c'],那么以上代码将输出3。如果valueNone,那么以上将返回0

lower

将值中所有的字符全部转换成小写。示例代码如下:

{
       { value|lower }}

如果value是等于Hello World。那么以上代码将输出hello world

upper

类似于lower,只不过是将指定的字符串全部转换成大写。

random

在被给的列表/字符串/元组中随机的选择一个值。示例代码如下:

{
       { value|random }}

如果value是等于['a','b','c'],那么以上代码会在列表中随机选择一个。

safe

标记一个字符串是安全的。也即会关掉这个字符串的自动转义。示例代码如下:

{
       {
       value|safe}}

如果value是一个不包含任何特殊字符的字符串,比如<a>这种,那么以上代码就会把字符串正常的输入。如果value是一串html代码,那么以上代码将会把这个html代码渲染到浏览器中。

也可以把返回的字符串通过导入from django.utils.safestring import mark_safe mark_safe(字符串)

slice

类似于Python中的切片操作。示例代码如下:

{
       { some_list|slice:"2:" }}

以上代码将会给some_list2开始做切片操作。

stringtags

删除字符串中所有的html标签。示例代码如下:

{
       { value|striptags }}

如果value<strong>hello world</strong>,那么以上代码将会输出hello world

truncatechars

如果给定的字符串长度超过了过滤器指定的长度。那么就会进行切割,并且会拼接三个点来作为省略号。示例代码如下:

{
       { value|truncatechars:5 }}

如果value是等于北京欢迎您~,那么输出的结果是北京...。可能你会想,为什么不会北京欢迎您...呢。因为三个点也占了三个字符,所以北京+三个点的字符长度就是5。

truncatechars_html

类似于truncatechars,只不过是不会切割html标签。示例代码如下:

{
       { value|truncatechars:5 }}

如果value是等于<p>北京欢迎您~</p>,那么输出将是<p>北京...</p>

查看源码:from django.template import defaultfilters

自定义过滤器

  1. 首先在某个app中,创建一个python包,叫做templatetags,注意,这个包的名字必须为templatetags,不然就找不到。
  2. 在这个templatetags包下面,创建一个python文件用来存储过滤器。
  3. 在新建的python文件中,定义过滤器(也就是函数),这个函数的第一个参数永远是被过滤的那个值,并且如果在使用过滤器的时候传递参数,那么还可以定义另外一个参数。但是过滤器最多只能有2个参数。
  4. 在写完过滤器(函数)后,要使用register=django.template.Library() register.filter(过滤器名子,函数名子)进行注册。
  5. 还要把这个过滤器所在的这个app添加到settings.INSTALLED_APS中,不然Django也找不到这个过滤器。
  6. 在模板中使用load标签加载过滤器所在的python包。
  7. 可以使用过滤器了。
  8. django.template.Library.filter还可以当作装饰器来使用。如果filter函数没有传递任何参数,那么将会使用这个函数的名字来作为过滤器的名字。当然如果你不想使用函数的名字来作为过滤器的名字,也可以传递一个name参数。示例代码如下:
    @register.filter('my_greet') def greet(value,word):  return value + word
    
@register.filter
def time_since(value):  """  time距离现在的时间间隔  1.如果时间间隔小于1分钟以内,那么就显示“刚刚”  2.如果是大于1分钟小于1小时,那么就显示“xx分钟前”  3.如果是大于1小时小于24小时,那么就显示“xx小时前”  4.如果是大于24小时小于30天以内,那么就显示“xx天前”  5.否则就是显示具体的时间  2017/10/20 16:15  """  if not isinstance(value,datetime):  return value  now = datetime.now()  # timedelay.total_seconds  timestamp = (now - value).total_seconds()  if timestamp < 60:  return '刚刚'  elif timestamp >= 60 and timestamp < 60*60:  minutes = int(timestamp/60)  return '%s分钟前' % minutes  elif timestamp >= 60*60 and timestamp < 60*60*24:  hours = int(timestamp/60/60)  return '%s小时前' % hours  elif timestamp >= 60*60*24 and timestamp < 60*60*24*30:  days = int(timestamp/60/60/24)  return '%s天前' % days  else:  return value.strftime("%Y/%m/%d %H:%M")

include

  1. 有些模版代码是重复的。因此可以单独抽取出来,以后哪里需要用到,就直接使用include进来就可以了。
  2. 如果想要在include子模版的时候,传递一些参数,那么可以使用with xxx=xxx的形式。示例代码如下:
    {
             % include 'header.html' with username='zhiliao' %}
    

模版继承

在前端页面开发中。有些代码是需要重复使用的。这种情况可以使用include标签来实现。也可以使用另外一个比较强大的方式来实现,那就是模版继承。模版继承类似于Python中的类,在父类中可以先定义好一些变量和方法,然后在子类中实现。模版继承也可以在父模版中先定义好一些子模版需要用到的代码,然后子模版直接继承就可以了。并且因为子模版肯定有自己的不同代码,因此可以在父模版中定义一个block接口,然后子模版再去实现。以下是父模版的代码:

{% load static %}
<!DOCTYPE html>
<html lang="en"> <head> <link rel="stylesheet" href="{% static 'style.css' %}" /> <title>{% block title %}我的站点{% endblock %}</title> </head>  <body> <div id="sidebar"> {% block sidebar %} <ul> <li><a href="/">首页</a></li> <li><a href="/blog/">博客</a></li> </ul> {% endblock %} </div> <div id="content"> {% block content %}{% endblock %} </div> </body> </html>

这个模版,我们取名叫做base.html,定义好一个简单的html骨架,然后定义好两个block接口,让子模版来根据具体需求来实现。子模板然后通过extends标签来实现,示例代码如下:

{% extends "base.html" %}

{% block title %}博客列表{% endblock %}

{% block content %} {% for entry in blog_entries %} <h2>{
             { entry.title }}</h2> <p>{
                { entry.body }}</p> {% endfor %} {% endblock %}

需要注意的是:extends标签必须放在模版的第开始的位置 子模板中的代码必须放在block中,否则将不会被渲染。 如果在某个block中需要使用父模版的内容,那么可以使用{ {block.super}}来继承。比如上例,{%block title%},如果想要使用父模版的title,那么可以在子模版的title block中使用{ { block.super }}来实现。

在定义block的时候,除了在block开始的地方定义这个block的名字,还可以在block结束的时候定义名字。比如{% block title %}{% endblock title %}。这在大型模版中显得尤其有用,能让你快速的看到block包含在哪里。

加载静态文件

在一个网页中,不仅仅只有一个html骨架,还需要css样式文件,js执行文件以及一些图片等。因此在DTL中加载静态文件是一个必须要解决的问题。在DTL中,使用static标签来加载静态文件。要使用static标签,首先需要{% load static %}。加载静态文件的步骤如下:

  1. 首先确保django.contrib.staticfiles已经添加到settings.INSTALLED_APPS中,创建时已经默认添加好了。

  2. 确保在settings.py中设置了STATIC_URLSTATIC_URL=\static\

  3. 在已经安装了的app下创建一个文件夹叫做static,然后再在这个static文件夹下创建一个当前app的名字的文件夹,再把静态文件放到这个文件夹下。例如你的app叫做book,有一个静态文件叫做zhiliao.jpg,那么路径为book/static/book/zhiliao.jpg。(为什么在app下创建一个static文件夹,还需要在这个static下创建一个同app名字的文件夹呢?原因是如果直接把静态文件放在static文件夹下,那么在模版加载静态文件的时候就是使用zhiliao.jpg,如果在多个app之间有同名的静态文件,这时候可能就会产生混淆。而在static文件夹下加了一个同名app文件夹,在模版中加载的时候就是使用<img src="{% static 'app/zhiliao.jpg' %}">,这样就可以避免产生混淆。)

  4. 如果有一些静态文件是不和任何app挂钩的。那么可以在settings.py中添加STATICFILES_DIRS,以后DTL就会在这个列表的路径中查找静态文件。那么查找的有顺序就变为,先在自己的app里找,找不到就会这个目录下去找。比如可以设置为:

STATICFILES_DIRS = [
os.path.join(BASE_DIR,"static") ]
  1. 在模版中使用load标签加载static标签。比如要加载在项目的static文件夹下的style.css的文件。那么示例代码如下:
{% load static %}
<link rel="stylesheet" href="{% static 'style.css' %}">
  1. 如果不想每次在模版中加载静态文件都使用load加载static标签,那么可以在settings.py中的TEMPLATES/OPTIONS添加'builtins':['django.templatetags.static'],这样以后在模版中就可以直接使用static标签,变成一个内置的标签,而不用手动的load了。

  2. 如果没有在settings.INSTALLED_APPS中添加django.contrib.staticfiles。那么我们就需要手动的将请求静态文件的url与静态文件的路径进行映射了。示例代码如下:

from django.conf import settings from django.conf.urls.static import static  urlpatterns = [ # 其他的url映射 ] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)<
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值