Django学习记录二

三、URL与视图

URL分发器

视图:
视图一般都写在app的view.py中。并且视图的第一个参数永远都是request(一个HttpRequest)对象。这个对象存储了请求过来的所有信息,包括拾的参数以及一些头部信息等。在视图中,一般是完成逻辑相关的操作。比如这个请求是添加一篇博客,那么通过request来接收到这些数据,然后存储到数据库中,最后把执行的结果返回给浏览器。视图函数的返回结果必须是HttpRequestBase对象或者子类的对象。示例代码如下:

from django.http import HttpResponse

def book(request):
    return HttpResponse("图书首页")

URL映射:
视图写完后,要与URL进行映射,即用户在浏览器中输入什么url的时候可以请求到这个视力函数。在用户输入了某个url,文玩清台我们的网站的时候,django会从项目的urls.py文件中寻找到对应的视力和。在urls.py文件中有一个urlpatterns变量,以后django就会从这个变量中读取所有的匹配规则,匹配规则需要使用django.urls.pathh函数进行包裹,这个函数会根据传入的参数返回URLPattern或者是URLResolver的对象。示例代码如下:

from django.contrib import admin
from django.urls import path
from book import views

ADMIN_SITE_URLS_ = [
    path('admin/', admin.site.urls),
    path('book/', views.book)
]

URL中传参数

有时候,url包含了一些参数需要动态调整。比如简书某文章的详情页的url,https://www.jianshu.com/p/a64aa003be0c后面的a64aa003be0c就是这篇文件的id,那么简书的文章详情页面的url就可以写成https://www.jianshu.com/p/,其中id就是文件的id。那么如何在django中实现这种需求呢?这个时候我们可以在path函数中,使用尖括号的形式来定义一个参数。比如我现在想要获取一本书籍的详细信息,那么应该在url中指定这个参数。
  1. 采用在url中使用变量的方式

在path的第一个参数中,使用<参数名>的方式可以传递参数。然后在视图函数中也要定一个参数,视图函数中的参数必须和url中的参数名称保持一致,不然就找不到这个参数。另外,url可以传递多个参数

  • 在url.py的代码:
from django.contrib import admin
from django.urls import path
from book import views

ADMIN_SITE_URLS_ = [
	path('', views.index),
    path('admin/', admin.site.urls),
    path('book/', views.book),
    path('book/<book_id>', views.book_detail),
]
  • 在view.py的代码:
from django.http import HttpResponse

# Create your views here.

#...

def book_detail(request, book_id):
    text = "您获取的图书id是:%s"%book_id
    return HttpResponse(text)
  1. 采用查询字符串的方式

在url中,不需要单独的匹配查询字符串的部分。只需要在视图中会用 request.GET.get(‘参数名称’) 的方式来获取。

  • 在url.py的代码:
from django.contrib import admin
from django.urls import path
from book import views

ADMIN_SITE_URLS_ = [
    path('', views.index),
    path('admin/', admin.site.urls),
    path('book/', views.book),
    #path('book/<book_id>/', views.book_detail),
    path('book/author/', views.author_detail)
]
  • 在view.py的代码:
from django.http import HttpResponse

# Create your views here.

#...

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

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

  1. URL命名
  • 为什么需要url命名:
    因为url是经常变化的。如果代码中写死可能会经常改代码。给url取个名字,以后使用url的时候就使用他的名字进行反转就可以了,就不需要写死url了
  • 如何给一个url指定名称:
    在path函数中,传递一个name参数就可以指定
urlpatterns = [
    path("", views.index, name='index'),
    path("login/", views.login, name='login')
]
  • 应用命名空间:
    在多个app之间,有可能产生同名的url。这个时候为了避免反转url的时候产生混淆,可以使用应用命名空间,来做区分。
# 应用命名空间
app_name = 'front'

urlpatterns = [
    path("", views.index, name='index'),
    path("login/", views.login, name='login')
]

以后在做反转的时候就可以使用<应用命名空间:url名称>的方式进行反转

def index(request):
    username = request.GET.get("username")
    #username = request.GET["username"] 不可用
    if username:
        return HttpResponse("前台首页")
    else:
        login_url = reverse('front:login')
        print("="*30)
        print(login_url)
        print("="*30)
        return redirect(login_url)

四、模板

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

DTL与普通的HTML文件的区别

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

  • 渲染模板
    渲染模板有多种方式。这里讲下两种常用的方式
  1. render_to_string: 找到模板,然后将模板编译后渲染成Python的字符串格式。最后通过HttpResponse类包装成一个HttpRequest对象返回回去
from django.template.loader import render_to_string
from django.http import HttpResponse

def index(request):
    html = render_to_string("index.html")
    return HttpResponse(html)
  1. 以上方式跃然已经很方便了。但是django还提供了一个更加简便的方式,直接将模板渲染成字符串和包装成HttpResponse对象一步到位完成
from django.shortcuts import render

def index(request):
    return render(request, "index.html")
  • 模板路径设置
    在项目的setting.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的异常

DTL模板语法

  • 变量:
    模板中可以包含变量,Django在渲染模板的时候,可以传递变量对应的值过去进行替换。变量的命名规范和Python非常类似,只能是阿拉伯数字和英文字符以及下划线的组合,不能出现标点符号等特殊字符。变量需要通过视图函数渲染,视力函数在使用render或者render_to_string的时候可以传递一个context的参数,这个参数是一个字典类型。以后在模板中的变量就从这个字典中读取值的
# index2.html模版代码
<p>{{username}}</p>
# views.py代码
def index(request):
    context = {
        "username": "斯巴达"
    }
    return render(request, "index2.html", context=context)

模板中的变量同样也支持点的形式。在出现了点的情况,比如person.username,模板是按照以下方式进行解析的:

  1. 如果person是一个字典,那么就会查找这个字典的username这个key对应的值
def index(request):
    context = {
        "person":{
            "username":"皮卡丘",
            "keys":"abc"
        }
    }
    return render(request, "index2.html", context=context)
  1. 如果person是一个对象,那么就会查找这个对象的username属性,或者是username这个方法
class Person(object):
    def __init__(self, username):
        self.username = username
        
def index(request):
        p = Person("可达鸭")
    	context = {"person": p}
    return render(request, "index2.html", context=context)
  1. 如果出现的是person.1,会判断person是否是一个列表或者元组或者任意的可以通过下标访问的对象,如果是的言辞就取这个列表的第1个值。如果不是就获取到的是一个空的字符串。
def index(request):
    context = {
        "person":[
            "程咬金","阿珂"
        ]
    }
    return render(request, "index2.html", context=context)

常用的模板标签

  1. if标签

if标签相当于Python中的if语句,有elif和else相对应,但是所有的标签都需要有标签符号( {%%} )进行包裹。if标签中可以使用==、!=、<、<=、>、>=、in、not in、is、is not等判断运算符。

    {% if '鲁班一号' in heros %}
        <p>鲁班一号正在待命</p>
    {% else %}
        <p>鲁班一号正在睡觉</p>
    {% endif %}
  1. for…in…标签

for…in…类似于Python中的for…in…。可以遍历列表、元组、字符串字典等一切可以遍历的对象

        {% for book in books %}
            <li>{{ book }}</li>
        {% endfor %}

如果想要反向遍历,那么在遍历的时候就加上一个reversed

        {% for book in books reversed %}
            <li>{{ book }}</li>
        {% endfor %}

遍历字典的时候,需要使用item、keys和values等方法。在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,以此类推
  • forloop.revcounter0:
  • forloop.first:是否第一次遍历
  • forloop.last:是否最后一次遍历
  • forloop.parentloop:如果有多个循环嵌套,那么这个属性代表的是上一级的for循环
        {% for book in books %}
            <tr>
                <td>{{ forloop.revcounter }}</td>
                <td>{{ forloop.parentloop }}</td>
                <td>{{ forloop.counter }}</td>
                <td>{{ book.price }}</td>
            </tr>
        {% endfor %}
  1. for…in…empty标签

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

  1. url标签

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

	<a href="{% url 'book' %}">读书</a>

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

	# path部分
	path('detail/<book_id>/', views.book_detail, name='detail')
	# url反转,使用位置参数
	<a href="{% url 'detail' 1 %}">最火的图书是</a>
	# url反转,使用关键字参数
	<a href="{% url 'detail' book_id=1 %}">最火的图书是</a>

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

	<a href="{% url 'detail'  %}?next=1">最火的图书是</a>

如果需要传递多个参数,那么通过空格的方式进行分隔

	<a href="{% url 'detail' book_id=1 page=2 %}">最火的图书是</a>

模版常用过滤器

在模版中,有时候需要对一些数据进行处理以后才能使用。一般在Python中我们是通过函数的形式来完成的。在模版中,则是通过过滤器来实现。过滤器使用的时候 “ | ” 来使用。

	{{value | add:"2"}}
  • add

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

	{{value | add:"2"}}

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

def add(value, arg):
	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):
	safe = isinstance(value, SafeData)
	value = value.replace(arg,"")
	if safe and arg != ';':
		return mark_safe(value)
	return value
  • date

将一个日期按照指定的格式,格式化成字符串

{{ data.date | date:"Y-m" }}

还有更多时间格式化的方式。见下表

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

模版继承

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

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<header>
    <ul>
        <li><a href="/">首页</a></li>
        <li><a href="{% url 'company' %}">公司</a></li>
        <li><a href="{% url 'school' %}">校园</a></li>
        <li>{{ username }}</li>
    </ul>
</header>
<div class="content">
    {% block content %}
        我是父模板中content的代码
    {% endblock %}
</div>
<footer>
    这是footer部分
</footer>
</body>
</html>

index.html

{% extends "base.html" %}

{% block content %}
    <p>这是首页的代码</p>
    我是block外面的代码
    <p>{{ block.super }}</p>
{% endblock %}

需要注意的是:extends标签必须放在模版的开始的位置
子模版中的代码必须放在block中,否则不会被渲染
如果在某个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_URL
  3. 在已经安装了的app下创建一个文件叫做static,然后再在这个static文件夹下创建一个当前app的名字的文件夹,再把静态文件放到这个文件夹下。例如你的app叫做book,有一个静态文件叫做zhiliao.jpg,那么路径为book/static/book/zhiliao.jpg。(为什么app下创建一个static文件夹,还需要在这个static下创建一个同app名字的文件夹呢?原因是如果直接把静态文件放在static文件夹下,那么在模版加载静态文件的时候就是使用zhiliao.jpg,如果在多个app之间有同名的静态文件,这时候可以就会产生混淆。而在static文件夹下加了一个同名app文件夹,在模版中加载的时候就是使用app/zhiliao.jpg,这样就可以避免产生混淆。)
  4. 如果有一些静态文件是不和任何app挂钩的。那么可以在settings.py中添加STATICFILES_DIRS,以后DTL就会在这个列表的路径中查找静态文件。比如可以设置为:
STATICFILES_DIRS = [
	os.path.join(BASE_DIR, "static")
]
  1. 在模版中使用load标签加载static标签。比如要加载在项目的static文件夹下的style.css的文件。
<link rel="stylesheet" href="{% static 'index.css' %}">
  1. 如果不想每次在模版中加载静态文件都使用load加载static标签,那么可以在settings.py中的TEMPLATES/OPTIONS添加 ‘builtins’:[‘django.templatetags.static’],这样以后在模版中就可以直接使用static标签,而不用手动的load了
  2. 如果没有在settings.INSTALLED_APPS中添加django.contrib.staticfiles。那么我们就需要手机的将请求静态文件的url与静态文件的路径进行映射了
from


本人的经验分享,希望可以帮助到你们,如何不对的地方,可以评论留言,帮我指正一下,如果帮助了你,请给我点个赞吧

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值