1 路由传参
在主urls中传递参数,注意格式
from django.contrib import admin
from django.urls import path
from django.conf.urls import url, include
urlpatterns = [
path('admin/', admin.site.urls),
path('one/', include('one.urls')),
path('two/', include('two.urls'), {'time': True}),
path('three/', include('three.urls'))
]
此处我们给名为two的app传入一个name的字典,然后我们到名为two的app下定义函数
from django.shortcuts import render,redirect,reverse
from django.http import HttpResponse
from django.template.loader import get_template
import time
# Create your views here.
def test(request,**kwargs):
return redirect(reverse('test1'))# 根据named动态获取路由
message = 'hello world!'
if kwargs.get('time'):
message += '<br/>' + time.asctime(time.localtime(time.time()))
return HttpResponse(message)
def test1(request,**kwargs):
message = 'hello world! test1'
if kwargs.get('time'):
message += '<br/>' + time.asctime(time.localtime(time.time()))
return HttpResponse(message)
这里我们使用**kwargs接收传过来的参数,然后在函数中使用kwargs.get()方法接收,然后在里面传入键,就会得到值。这样就完成了路由方式的传参。
2重定向
from django.urls import path
from . import views
urlpatterns = [
path(r'test/', views.test),
path(r'test1/', views.test1,name='test1'),
path(r'index/<username>/<password>',views.index)
]
我们直接在路由中给重定向的函数中传入第三个参数,即给他定义一个名字
from django.shortcuts import render,redirect,reverse
from django.http import HttpResponse
from django.template.loader import get_template
import time
# Create your views here.
def test(request,**kwargs):
return redirect(reverse('test1'))# 根据named动态获取路由
message = 'hello world!'
if kwargs.get('time'):
message += '<br/>' + time.asctime(time.localtime(time.time()))
return HttpResponse(message)
def test1(request,**kwargs):
message = 'hello world! test1'
if kwargs.get('time'):
message += '<br/>' + time.asctime(time.localtime(time.time()))
return HttpResponse(message)
这里我们又引入一个方法 reverse,然后直接需要在重定向的函数中,直接ruturn redirect(reverse(‘test1’)).该方法会根据路由中的name动态的获取重定向的路由。
3前后端不分离开发
前后端不分离开发,即把前端代码和前后端交互,以及数据库交互放在一起,那么我们就需要注册一个templates文件,来存放前端html文件夹。首先在settings里面找到
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
我们将template路径放在’DIRS’中,注意格式!
然后在项目文件夹下新建一个templates文件夹,然后创建与app数量相同且与app名称相同的文件夹(主要是为了方便管理)。
然后在同名文件夹中新建模板文件(html文件):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>test</title>
</head>
<body>
<div>欢迎登陆:<span style="color: red">{{ username }}</span></div>
</body>
</html>
然后在views文件中:
def template_1(request,**kwargs):
username = 'zjj'
#render是一个函数,第一个参数传入请求对象request,第二个传入模板地址,第三个参数是传递给模板的一个字典,通过key取值(该参数可省略,即无参数传递时)
return render(request, 'two/template_1.html', {'username': username})
这里我们使用的是render,而不是Httpresponse,这里的第二个参数用来引入模板html,然后第三个参数用来给模板文件传参,注意:这里使用的键值对格式的字典。
效果:
当然,这里不仅可以传字符串,还可以传很多值:
def fun():
return 'function'
class Student:
def __init__(self,name):
self.name = name
def study(self):
return 'good'
def template_var(request,**kwargs):
stu = Student('yige')
context = {'str_var': 'string',
'fun_var': fun,
'student_study_var':stu.study,
'student_var':stu,
'list_var': [1,2,3],
'dict_var':{'a':1,'b':2},
'int_var':1,
'tuple_var':('a','b'),
}
return render(request, 'two/template_var.html', context)
然后在模板文件中:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模板变量</title>
</head>
<body>
<ul>
<li>这个整数变量:{{ int_var }}</li>
<li>字符串变量:{{ str_var }}</li>
<li>函数变量:{{ fun_var }},这里会通过key得到value函数体</li>
<li>方法变量:{{ student_study_var }}</li>
<li>实例对象变量:{{ student_var }}</li>
<li>字典变量:{{ dict_var }}</li>
<li>元组变量:{{ tuple_var }}</li>
<li>列表变量:{{ list_var }}</li>
</ul>
<ul>
<li>访问对象属性:{{ student_var.name }}</li>
<li>访问对象方法:{{ student_var.study }}</li>
</ul>
<ul>
<li>访问列表元素:{{ list_var.1 }}</li>
<li>访问元组元素:{{ tuple_var.1 }}</li>
<li>访问字典元素:{{ dict_var.a }}</li>
</ul>
</body>
</html>
这里需要注意的是最后三排
<li>访问列表元素:{{ list_var.1 }}</li>
<li>访问元组元素:{{ tuple_var.1 }}</li>
<li>访问字典元素:{{ dict_var.a }}</li>
这里在定位元素的时候,并不是使用的[],而是使用的. 这里需要注意
效果:
静态文件的操作:
我们在完成模板html文件的创建后,还需要创建静态文件,比如css,js,图片等,首先当前项目目录下创建,如图
然后加入到settings目录中,不然我们找不到它
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static')
]
直接添加在最下方,这样我们才可以找到它,
模板文件引入方式:
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>静态文件</title>
<link rel="stylesheet" href="{% static 'css/static_file.css' %}">
</head>
<body>
<img src="{% static 'image/page1.png' %}" alt="">
<script src="{% static 'js/static_file.js' %}"></script>
</body>
</html>
首先在顶端使用{% load static%},表示引入静态文件,名字基于你的命名,然后下面才可以使用{% static ‘’%}来进行文件的引入。
效果:
4登陆操作
这里我们直接传值尝试,就不用数据库交互了
路由信息:
from django.urls import path
from . import views
urlpatterns = [
path(r'test/', views.test),
path(r'test1/', views.test1,name='test1'),
path(r'template_1', views.template_1),
path(r'template_var',views.template_var),
path(r'index/<username>/<password>',views.index)
]
这里最后一排,定义路由的方法需要注意,
视图信息:
def index(request, username, password, **kwargs):
username_db = 'zjj'
password_db = '123'
message = '请先登录'
context = {
'username': message,
'password': message
}
if username == username_db and password == password_db:
context['username'] = username
context['password'] = password
return render(request, 'two/index.html', context)
我们直接给路由传递用户,和密码,再看模板
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<dl>
<dt>用户信息</dt>
<li>用户名:{{ username }}</li>
<li>密码:{{ password }}</li>
</dl>
</body>
</html>
这里我们直接传递一个context,如果传递太多值,建议使用这种方法,不会看起来很臃肿。
效果:
5过滤器
过滤器就是模板文件对函数中传递过来的值进行过滤。具体值都可以查
from django.http import HttpResponse, HttpResponseNotFound
from django.shortcuts import redirect, render
from datetime import datetime
# Create your views here.
def filter_var(request):
context = {'str_var': 'THIS is Python',
'now': datetime.now,
'name': '<span style= color:"red">yige</span>',
}
return render(request, 'three/filter_var.html', context)
模板:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>过滤器</title>
</head>
<body>
<div>
<li>未过滤 {{ str_var }}</li>
<li>转小写{{ str_var|lower }}</li>
<li>获取第一个值{{ str_var|first }}</li>
<li>最后一个值{{ str_var|last }}</li>
<li>链式调用:模拟较规范的英文句子{{ str_var|lower|capfirst}}</li>
<li>去除指定字符(过滤器使用参数):{{ str_var|cut:' '}}</li>
<li>没处理的时间: {{ now }}</li>
<li>处理一下,date是日期,time是时间: {{ now|date }}</li>
<li>time过滤器: {{ now|time }}</li>
<li>xx年xx月xx日 xx:xx:xx24小时制 {{ now|date:'Y年m月d日 H:i:s' }}</li>
<li>xx:xx:xx12小时制{{ now|time:'H:i:s'}}</li>
<li>{{ name }}</li>
</div>
</body>
</html>
这里是使用方法
效果:
当然我们可以自己动议过滤器,比如这里的cut:
def cut(str,re):
return ''.join(str.split(re))
这里我们传入一个字符串,然后使用split方法切割字符串,然后用.join方法拼接起来返回出去,那么我们这个方法就需要传入用什么标志来切割,我们这里传入的是空格,那么出来的字符串就不会有空格。
6模板的标签
6.1if语句
首先定义一个函数:
from django.http import HttpResponse, HttpResponseNotFound
from django.shortcuts import redirect, render
class User:
def __init__(self, name, age, sex='男'):
self.name = name
self.age = age
self.sex = sex
def template_label(request):
user = User('周健', 26, 5)
context = {
'user': user
}
return render(request, 'three/template_label.html', context)
这里我们将值传入模板后,来进行模板标签条件语句的操作:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div class="if-box">
<h3>if模板标签</h3>
<p>当前用户信息:</p>
<ul>
<li>
姓名:{{ user.name }}
{% if user.name == '周健' %}
good boy
{% endif %}
</li>
<li>
年龄:{{ user.age }}
{% if user.age > 10 and user.age < 30 %}
年轻小伙
{% endif %}
</li>
<li>
性别:
{% if user.sex == 0 %}
男
{% elif user.sex == 1 %}
女
{% else %}
未知
{% endif %}
</li>
</ul>
</div>
</body>
</html>
使用格式:{% if%} {%endif%}
在这个中间可以插入elif,else等,和平常语句差不多,但是要加上{% %},语法才通顺。
6.2for语句与多层for语句
for语句可以对传入模板的参数进行遍历,然后forloop里面保存着循环的一些信息,可以直接.调用属性,forloop有很多属性,如first(第一个),last(最后一个),counter(从1开始的序号),recouter(倒过来的序号),counter0(从0开始的序号),recounter0(倒过来的从0开始序号)。
视图函数:
from django.http import HttpResponse, HttpResponseNotFound
from django.shortcuts import redirect, render
# Create your views here.
def template_label(request):
context = {
'course': ['python', 'linux', 'mysql', 'redis'],
'course_info': ('难点', '周边'),
'html_text': '<div>有html标签的噢<div>'
}
return render(request, 'four/template_label.html', context)
这里传入了几个值,然后再模板文件中,进行for操作,注意:for语句是双标签,不过可以直接for + tap键,快捷键
<div class="box">
{{ course }}
</div>
<div>forloop里面保存着循环的一些信息,可以直接.调用属性</div>
<ul>
{% for i in course %}
<li>{{ forloop.revcounter }}.{{ i }}</li>
{% endfor %}
</ul>
<ul>
{% for i in course %}
<li>{% if forloop.revcounter0 > 2 %}
<li> {{ i }}</li>
{% endif %}
</li>
{% endfor %}
</ul>
这里进行了遍历,然后在参数前面加上序号,这里是反向从1开始的序号,然后下面是对序号做判断,如果大于2才能显示.
效果:
多层for循环的使用:
<ul class="more-for-box">
<h3>多层for循环</h3>
<ul>
{% for i in course %}
<li>
{{ i }}
{% for j in course_info %}
{% if forloop.parentloop.first %}
<li style="color: rebeccapurple">
{{ j }}<input type="text">
</li>
{% else %}
<li>
{{ j }}<input type="text">
</li>
{% endif %}
{% endfor %}
</li>
{% endfor %}
</ul>
</ul>
这里嵌套了两层for语句,其实就和python的多层for循环一样,需要注意的就是注意格式{%%},和{{}}的区别,一个是函数使用,一个是接收参数用。
效果:
6.3url标签
可以实现跳转的标签,是需要在路由文件中添加名字
路由文件:
from django.contrib import admin
from django.urls import path
from . import views
urlpatterns = [
path(r'template_label', views.template_label, name='template_label'),
path(r'url_var/<var>', views.url_var, name='url_var'),
path(r'index/<value>', views.index)
]
这里给两个函数另外命了名。然后
<ul>
<h3>url模板标签</h3>
<p>{% url 'template_label' %}</p>
<p>
应用:
<a href="{% url 'template_label' %}">跳转</a>
<a href="{% url 'url_var' '2' %}">携带参数跳转</a>
</p>
</ul>
另外这里,还有一个携带参数跳转
def url_var(request, var):
return render(request, 'four/url_var.html', {'var': var})
这里我们的函数有一个传入参数,然后上面的模板文件中,只需要在后面名字参数后面,添加一个字符串参数,就能把这个参数传递给目标函数,然后跳转的页面就是携带参数的页面。
6.4with标签
with标签可以将变量赋予给新的变量。
<div>
<h3>with标签</h3>
{% with course.0 as firstc %}
<p>{{ firstc }}</p>
{% endwith %}
</div>
这个用的地方不是很多。
6.5 autoscape模板标签
可以实现页面的自动转义的取消和开启,之前不是说到django是自己带有自动转义,该标签可以取消自动转义。这里的html_text是有标签符号的字符串。
<div class="autoscape-box">
<h3>outoscape模板标签</h3>
<ul>
<li>
原数据:{{html_text}}
</li>
<li>
过滤器取消转义: {{ html_text|safe }}
</li>
<li>
autoscape取消自动转义:
{% autoescape off %}
{{ html_text }}
{% endautoescape %}
</li>
</ul>
</div>
效果:
这里不加任何处理,就会直接显示
7模板的继承
这样可以省去很多工作量,字类模板可以将父类模板的css,js,等等都可以继承过来,不用自己再写。方法:
{% extends 'four/indexbase.html' %}
比如这里父类模板名字为indexbase.html,然后删除所有子类模板的初始代码,只需要一行代码,就可以将父类所有的东西继承过来。但是没有页面是完全一样的,所以有时候我们需要修改一些东西,所以需要使用block标签。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>父类</title>
{% block css %}
{% endblock %}
</head>
<body>
{% block header %}
牛,
{% endblock %}
good
{% block center %}
yxyy
{% endblock %}
</body>
</html>
这里我们在父类中定义了许多个block标签,每一个标签里面的参数都不同,这是为了在继承的时候能区分开,注意这里的上下顺序会延续到子类中,就是说不管子类中写的上下顺序是如何的,最后呈现出来的效果只与父类中的上下顺序一致。然后我们就可以在子类中定义了。
{% extends 'four/indexbase.html' %}
{% block css %}
直接写就行!
{% endblock %}
{% block center %}
xxxxxxx
{% endblock %}
{% block header %}
{{ block.super }}
<div>yes</div>
{% endblock %}
这里我们需要注意的是,如果我们不定义block,即子类中没有block,直接在子类中加入代码,django是不会渲染的,所以对于哪些是重复的,哪些需要修改要做提早的规划。
然后如果我们添加了block标签,但是我们除了自己修改东西外,我们还想保留父类原来的东西,就需要使用{{ block.super}},如上图代码中所示,这样就可以即保留父类信息,又可以添加信息。
8自定义过滤器
首先自定义过滤器的路径设置,第一步在项目文件夹下新建一个名为common的python包(注意:是python包,python package)(名字可任取),然后在common里面再建一个python包,名字必须是templatetags,注意:名字必须是这个。然后在里面建一个python文件(不是包)。效果如图:
建立完成后,在settings里面注册它,
进入新建的sex_change文件,自定义过滤器其实就是新建一个函数,但是这个函数要被html文件接收并且能使用,就需要一些手段。首先导入django里面的template,再得到注册对象。
from django import template
register = template.Library() #得到注册对象
@register.filter
def change(value, args):
return '未知' if value >= len(args) or value < 0 else args[value]
这里先不管别的,单看这个函数,有两个传入值,一个value,一个args。
然后一个三目运算符,判断如果value的值大于等于args的长度或者小于0,就返回’未知’,否则就返回args中value项。然后使用register.filter进行注册,使用装饰器形式。然后怎么用呢?首先在html文件里面导入我们自定义过滤器所在的文件名
{% load sex_change %}
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<ul>
<li>姓名:{{ user.name }}</li>
<li>年龄:{{ user.age }}</li>
<li>性别:{{ user.sex | change:sex_li }}</li>
这里在第一排使用{% load 文件夹名%},注意这里不是过滤器的名字,是所在的文件名。
然后在使用的时候还是和过滤器一样。
def custom_filter(request):
user = User('zj', 18, 1)
context = {
'user': user,
'sex_li': ['男', '女'],
'label_index': 1,
'label_list': ['python', 'c', 'c++'],
'format_string': '1',
'course': ['a', 'b', 'c', 'd', 'e']
}
return render(request, 'five/custom_filter.html', context)
那么我们给change过滤器传入了2个参数,第一个参数是user.sex,然后第二个参数是sex_li.那么把这两个参数传入函数中,会返回sex_li中的1项,即女。
9自定义标签
自定义标签和自定义过滤器形式一样,所以我们直接在sex_change文件里直接进行注册。
@register.simple_tag
def current_time_str():
return 1
这里需要注意的是,修饰器是@register.simple_tag,而不是@register.filter,当然函数的定义方式是不变的。
<li>当前时间:{% current_time_str %}</li>
当然,自定义标签也可以传入参数,但是传入的参数只能是在views函数中传入html文件的context,那么我们如何接收来自views函数的参数?
@register.simple_tag(takes_context=True)
def current_time_context(context):
return context['format_string']
这里传入修饰器的参数,takes_context=True.
这样就可以获取context中的参数,当然需要获取context,这里主要是注意格式,即使用键值对形式,用键取值。
另外,比如我们每一次html文件中,每一次遍历参数,都需要使用for标签进行遍历,然后endfor标签结束。那么我们能不能将它封装起来,然后每一次使用,只需要传入参数即可。
首先我们单独定义一个html文件来封装for标签方法。
然后在sex_change文件中(就是之前我们定义的那个),新建一个自定义标签。
@register.inclusion_tag('five/for_item.html', takes_context=True)
def for_item(context, key):
li = context.get(key)
return {'key': li}
这里在修饰器的第一个参数中传入封装for标签的html地址。那么我们的这个标签如何使用呢?
<ul>
{% for_item 'course' %}
</ul>
这里我们只传入一个course列表,然后调用for_item标签,标签通过context.get(key),获取course的值,key就是传入的course,然后return{‘key’ : li},这里会将这个字典返回到第一个参数的地址,也就是html文件中,然后html文件中的key就是该字典中的键,那么就会获取li,然后开始遍历后,输出。