开发环境搭建
1.虚拟环境+库 安装django
python -m venv myvenv
myvenv Scripts activate.bat
pip install Django
2.start project 项目创建
python -m django startproject djangosite
3.start app 应用程序创建
cd djangosite (外面的djangosite)
python manage.py startapp demo
4注册app
目的是被Diango发现,以便可以扫描到数据模型和模板
image.png
Djanog基本架构
传统MVC
image.png
django改进的MVC---MTV
image.png
Modle:和数据库交互,通过Model可以不用直接操作数据库,提高了代码编写效率
View: 处理用户的请求,和返回数据响应,可以直达用户
Template: django独特的网页渲染方式,将内容配合模板渲染成网页展现给用户,需要配合前端基本知识使用(html css js)如果前后端分离则用不到此模块
Django视图
视图定义:处理http请求的部分,返回http响应
Django如何定义视图
# demo/views.py
#定义视图--用户能看到的内容
def index(request):
return HttpResponse('lalala')
如何访问该视图?
通过路由系统
Django的路由系统
什么是路由 ?
请求的向导,如用户访问 http://host/path/foo/bar 被系统转到foo视图函数,处理后返回结果
路由原理
通过解析传递过来的url,来分配具体执行的视图函数。可以理解为视图的调度器。
image.png
Django的路由定义
# djangosite/urls.py
from login import views
urlpatterns = [
path('admin/', admin.site.urls),
path('index/',views.index),
]
Django路由转发
当系统比较复杂时,一层路由会显得很臃肿,且后期不好维护,所以我们可以把路由层层分解,这个叫做路由的转发。
image.png
蓝色的是总路由,统一处理用户的请求,后面五颜六色的是分路由,分别处理总路由发过来的请求。这个就好比之前的小店老板1个人处理业务就够了,但是现在公司做大了,老板接到活以后要分配给下面的员工来处理。
路由的注意点
末尾/的问题
一般我们在定义路由的时候习惯末尾加/(斜杠)
如果定义了斜杠
那么浏览器访问的时候可以不带(会自动为你补全) 但是请求工具,比如代码request必须带(不会自动补全)
如果末尾没有定义/(斜杠)
那么浏览器访问的时候不带/(不会自动帮你删/) 同样请求工具,比如代码request也不能带/(不会自动补全也不会自动帮你删/)
路由的分发
对比下我们目前的路由文件 urls.py
"""
路由文件
"""
from django.contrib import admin
from django.urls import path
urlpatterns = [
path('admin/', admin.site.urls),
]
from testapp import views
urlpatterns += [
path("index/",views.index), # 为你的项目添加一个可以访问的地址:http://127.0.0.1:8000/index/ 并返回某个视图的内容
path("hello/",views.hello_world),
path("world/",views.world),
path('events/',views.events), # 发布会管理页面
path('events/detail',views.event_detail), # 发布会详情页
]
不同的app路由都统一集中到了一块,如果项目简单还好,项目复杂,url文件就会变得特别臃肿。
所以为了后期好维护,我们可以将路由逐层分解。
我们可以用django的include函数完成这个操作
from django.urls import path,include
path('1级路由/',include(视图模块))
在app目录下新建分路由文件urls.py(这个文件名可以自定义,一般叫这个名字)
demo/urls.py
from django.urls import path,include
from . import views
urlpatterns = [
path('index/',views.index),
]
sgin/urls.py
from django.urls import path,include
from . import views
urlpatterns = [
path('events/',views.events),
path('event_detail/',views.event_detail),
]
修改主路由,开头导入include
from django.contrib import admin
from django.urls import path,include #导入include
#第一步导入路由
from demo import urls as demo_view
from sgin import urls as sgin_view
urlpatterns = [
path('admin/', admin.site.urls),
#路由分发
path('demo/',include(demo_view)),
# 签到系统路由
path('sgin/',include(sgin_view)),
]
路由与视图组合练习
创建应用程序 ---sgin
python -m django startapp sgin # 或者django-admin startapp demo
定义URL
#djangosite/urls,py
from sgin import views
urlpatterns = [
path('admin/', admin.site.urls),
path('events/',views.events) #列出发布会
]
页面视图
#sgin/views.py
from django.http import HttpResponse
def events(request):
return HttpResponse('发布会')
启动python开发服务器
python manage.py runserver 9090 #最后一个表示端口号,随意,只要不和当前系统程序冲突即可
升级视图-增加发布会数量
def events(request):
event_list=['测开发布会',
'自动化发布会',
'性能发布会',
'安全发布会',
'全栈发布会',
'ISTQB',
'TM项目管理',
'PMP考证']
return HttpResponse('|'.join(event_list))
视图再升级-加入html标签
def events(request):
event_list=['测开发布会',
'自动化发布会',
'性能发布会',
'安全发布会',
'全栈发布会',
'ISTQB',
'TM项目管理',
'PMP考证']
#套入标签<li></li>中
res=''.join([f'<li>{event}</li>' for event in event_list])
return HttpResponse(res)
这时候发现在代码里面修改html很麻烦,且不好维护,这个时候我们需要将html的内容外包给模板系统来处理,他负责对外展示的样式。
Django模板--初识
模板的作用
用HMTL文件来保存待显示的内容,然后我们代码直接返回HTML文件即可
我们只需利用Django的模板机制就可以实现
用法--template
首先在应用程序Login的目录下新建一个templates的目录 目录名必须相同
然后新建HTML文件,里面塞入如下内容
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>发布会</title>
</head>
<body>
<h1>测试开发发布会</h1>
</body>
</html>
模板实践---修改发布会视图返回,改为返回html文件
return render(request,'events.html')
刷新页面,展示的内容
image.png
第一个模板技术-变量
作用:
将视图函数的变量返回到模板中,django将其渲染
用法:
视图返回变量:{'模板中用到的变量名':变量}
return render(request,'events.html',{'events':res})
模板使用变量:{{变量名}}
<body>
{{ events }} #标签中加入
</body>
刷新页面
image.png
发现变量自带的标签没有被渲染,对的,默认情况下django返回的变量中若带html标签是不会被渲染的,当然如果你本就不想渲染html标签,或者变量内容没有Html标签那么可以忽略,但是如果想的话,请看下面:
第二个模板技术-for循环控制器
作用:
将列表类型的变量挨个展现出来
用法:
视图返回变量列表:
修改下原视图函数的返回,之前是字符串,现在改为列表并且去掉标签
#套入标签<li></li>中
res=[event for event in event_list]
return render(request,'events.html',{'events':res},)
模板使用for:
<ul>
{% for event in events %}
<li>{{ event }}</li>
{% endfor %}
</ul>
发现没有?语法和 python几乎一样!不要忘记For循环结束要加{% endfor %},因为Html里是不认你的缩进的。。。
刷新页面 正常了
第三个模板技术-if控制器
作用:
条件控制,可以根据条件选择渲染哪些元素
用法:
视图返回变量同上
模板使用变量:
{% if 'ISTQB' in events %}
<h3>8个发布会</h3>
{% endif %}
注意:在标签内使用变量不用再加{{}}了,否则会报错
再换一个条件
{% if events.length == 9 %}
<h3>9个发布会</h3>
{% endif %}
发现没有生效,原因是在模板中.length这种列表自带的属性失效了,需要使用模板自带的过滤器来实现
第四个模板技术-过滤器的用法
作用:
转换变量和标签参数的值
写法:
{{变量|过滤器}}
上面的案例可以改成
{% if events|length == 9 %}
<h3>9个发布会</h3>
{% endif %}
刷新页面发现可以了
内置的模拟器参考:https://docs.djangoproject.com/zh-hans/3.1/ref/templates/builtins/#ref-templates-builtins-tags
Tips:当哪天你发现内置的模拟器也不能满足需求了,你可以自定义过滤器,不过如果你不专注前端开发可能很少用到了,参考:https://docs.djangoproject.com/zh-hans/3.1/howto/custom-template-tags/#writing-custom-template-filters
页面的美化-更新模板加入静态文件
加入静态文件
image.png
将提供的静态文件按照如上目录结构存放。
由于我们要使用django的模板系统来渲染页面,所以引入静态文件需要遵循django的规则
{% load static %}
#开头加上该标签<!DOCTYPE html>
<html lang="cn">
同时修改外部文件的引入格式
原来的引入方式
<link href="assets/css/bootstrap.css " rel="stylesheet" /> #css
<script src="assets/js/jquery-1.10.2.js"></script> #js
修改后
<link href="{% static 'assets/css/bootstrap.css' %} " rel="stylesheet" /> #css
<script src="{% static 'assets/js/jquery-1.10.2.js' %}"></script> #js
填充模板页面
将发布会信息显示到页面上
{% for event in events %}
<li>{{ event }}</li>
{% endfor %}
发现不好看,再选择性的加入一些样式
<ul class="list-group">
{% for event in events %}
<li class="list-group-item text-center">{{ event }}</li>
{% endfor %}
</ul>
Tips: class="list-group" class="list-group-item text-center" 表示使用该css文件时,class对应的样式,bootstrap为我们定义了现成的样式,只需要引入类即可,不用从头写cs
完美呈现
继续页面的开发
展示发布会具体信息:名称,时间,地点 等
从发布会管理页面链接到详情页
增加返回
此时发现一个问题,两个页面的基本样式都差不多---测边栏和页首菜单,只是中间区域不同
如果只有两个页面还好,多个页面就会出现难以维护的情况,因为可能你改动一个样式就要改N个文
件,非常不方便!
所以我们丰富的编程思路该如何解决问题?
对了,定义一个相对不变的公共模板,其他页面继承这个模板就可以了,模板留出接口,继承的页面只
需要改动这个接口就可以。
模板的继承
{% block title%}{% endblock %}
类似这种{% block 标签%}{% endblock %}格式的标签
这个就是模板提供的接口,预留了空间让继承的子页面用于改动的
我们要做的就是继承这个模板页面,改动需要改动的即可
定义基础模板base.html表示根模板的意思
<!-- base.html-->
{% load static %}
<!DOCTYPE html>
<html lang="cn">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta content="haiwen" name="author" />
<!-- Bootstrap Styles-->
<link href="{% static 'assets/css/bootstrap.css' %} " rel="stylesheet" />
<!-- FontAwesome Styles-->
<link href="{% static 'assets/css/font-awesome.css'%}" rel="stylesheet" />
<!-- Custom Styles-->
<link href="{% static 'assets/css/custom-styles.css' %}" rel="stylesheet" />
<title>{% block title%}{% endblock %}</title>
</head>
<body>
<div id="wrapper">
<nav class="navbar navbar-default top-navbar" role="navigation">
<div class="navbar-header">
<a class="navbar-brand"><i class="icon fa fa-plane"></i> 发布会签到系统</a>
<div id="sideNav" >
<i class="fa fa-bars icon"></i>
</div>
</div>
<ul class="nav navbar-top-links navbar-right">
<li class="dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#" aria-expanded="false">
<i class="fa fa-user fa-fw"></i> <i class="fa fa-caret-down"></i>
</a>
<ul class="dropdown-menu dropdown-user">
<li><a href="#"><i class="fa fa-user fa-fw"></i> User Profile</a>
</li>
<li><a href="#"><i class="fa fa-gear fa-fw"></i> Settings</a>
</li>
<li class="divider"></li>
<li><a href="#"><i class="fa fa-sign-out fa-fw"></i> Logout</a>
</li>
</ul>
<!-- /.dropdown-user -->
</li>
</ul>
</nav>
<!--/. NAV TOP -->
<nav class="navbar-default navbar-side" role="navigation">
<div class="sidebar-collapse">
<ul class="nav" id="main-menu">
<li>
<a class="active-menu" href="/sgin/events"><i class="fa fa-dashboard"></i> 发布会</a>
</li>
<li>
<a href="/sgin/guests"><i class="fa fa-desktop"></i> 嘉宾</a>
</li>
</ul>
</div>
</nav>
<!-- /. NAV SIDE -->
<div id="page-wrapper">
<div class="header">
<div class="page-header">
{% block maintitle %}{% endblock %}
</div>
</div>
<div id="page-inner" class="panel-body">
{% block content%}
{% endblock %}
<footer><p>Author:haiwen. <a href="https://ke.qq.com/course/3135766" target="_blank">松勤测试开发课程</a></p>
</footer>
</div>
<!-- /. PAGE INNER -->
</div>
<!-- /. PAGE WRAPPER -->
</div>
<!-- jQuery Js -->
<script src="{% static 'assets/js/jquery-1.10.2.js' %}"></script>
<!-- Bootstrap Js -->
<script src="{% static 'assets/js/bootstrap.min.js' %}"></script>
<!-- Custom Js -->
<script src="{% static 'assets/js/custom-scripts.js' %}"></script>
<script>
$(document).ready(
$('#main-menu>li>a').each(function (){
$(this).attr('class',''); //先取消选中
let current_href = window.location.pathname
if(current_href === $(this).attr('href')){
$(this).attr('class','active-menu');
}
}),
)
</script>
</body>
</html>
子页面events.html改写
{% extends "base.html" %}
{% block title%}发布会管理{% endblock %}
{% block content%}
<ul class="list-group">
{% for event in event_list %}
<li class="list-group-item text-center">
<a href="/events/detail">{{ event }}</a>
</li>
{% endfor %}
</ul>
{% endblock %}
开头的 {% extends "base.html" %} 表示继承base.html 页面
{% block content %}{% endblock %} 这之间的内容就填写子页面特有的个性内容。
刷新页面,依旧美丽,但是我们的Html文件简洁了很多,有木有!
依次类推,我们可以在模板想要改动的地方留出接口,子页面继承的时候可以改动这些接口,这里并不
是所有的接口都要子页面填充,你可以只填充你想填充的地方。
原则就是,模板提供的接口,子页面可以填充,没有提供的接口,自然就填充不了哦
依次类推,直接继承父模板,定义子页面
event_detail.html
{% extends 'base.html' %}
{% block title%}发布会详情页{% endblock %}
{% block content%}
<h1>发布会详情页</h1>
<p><a href="/events/" class="btn btn-info">返回发布会列表</a></p>
{% endblock %}
定义路由 urls.py
"""
路由文件
"""
from django.contrib import admin
from django.urls import path
urlpatterns = [
path('admin/', admin.site.urls),
]
from testapp import views
urlpatterns += [
path("index/",views.index), # 为你的项目添加一个可以访问的地址:http://127.0.0.1:8000/index/ 并返回某个视图的内容
path("hello/",views.hello_world),
path("world/",views.world),
path('events/',views.events), # 发布会管理页面
path('events/detail',views.event_detail), # 发布会详情页
]
定义视图 views.py
from django.shortcuts import render
from django.http import HttpResponse # 管理项目请求和响应的一个包
# Create your views here.
"""
视图管理
"""
# Create your views here.
def events(request):
event_list = [
'自动化发布会',
'测试开发布会',
'性能发布会',
'安全发布会',
'全栈发布会',
'ISTQB',
'TM项目管理',
'PMP考证'
]
# 简单的返回字符串
# return HttpResponse([f'<li>{event}</li>' for event in event_list])
# 返回一个模板内容
return render(request,'events.html',{'event_list':event_list})
#发布会详情页
def event_detail(request):
return render(request,'event_detail.html')
def index(request):
# return HttpResponse("你好")
return render(request,"index.html")
def hello_world(request):
return HttpResponse("hello_world是根据字符串作为返回值的")
def world(request):
# return HttpResponse("你好")
return render(request,"world.html")
访问 发布会详情页(http://127.0.0.1:9090/events/detail)
附录--知识点官方文档
路由:https://docs.djangoproject.com/zh-hans/3.1/topics/http/urls/
视图:https://docs.djangoproject.com/zh-hans/3.1/topics/http/views/
模板:https://docs.djangoproject.com/zh-hans/3.1/topics/templates/
内置模板标签和过滤器:https://docs.djangoproject.com/zh-hans/3.1/ref/templates/builtins/#ref-templates-builtins-tags
django通用术语:https://docs.djangoproject.com/zh-hans/3.1/glossary/
网友评论