Django从入门到放弃之后台admin管理与URL| 模板| 视图(四) 发表评论 367 views CXX1.COM原创博客网 › 白石 › 哲学 › 技艺 › Django › Django从入门到放弃之后台admin管理与URL| 模板| 视图(四) ------------ [TOC] > ## Django从入门到放弃之后台admin管理(四) > ## 一、为 admin 后台管理添加超级管理员 > <font color="red">提示: 我们在上一篇中讲到新建了一个分支,那么在开始本章前请提交 databases 分支</font> ------------ > 建立新的分支 admin > 首先我们输入来创建一个超级管理员 , 这里密码就是 123456 ,记住这个密码 python manage.py createsuperuser Username (leave blank to use '98624'): white Email address: 986247535@qq.com Password: 123456 > 接着它会提示我们密码太简单, 不过没关系, 直接输入 y/N Bypass password validation and create user anyway? y Superuser created successfully. 创建成功 > 启动我们的轻量级服务器, 并且输入网址 http://127.0.0.1:8000/admin/ python manage.py runserver > 看到这个页面后, 表示没有问题输出刚刚的用户和密码 <center>  </center> > 登陆进去后有个缺点就是为什么全是英文?  > 设置 setting.py 文件后就能看到因为啦。 LANGUAGE_CODE = 'zh-Hans' #设置后台语言 默认 en-us > 我们需要在 polls/admin.py 中注册我们的模型并导入相当于一个接口 ```python from django.contrib import admin # Register your models here. from .models import Question admin.site.register(Question) ``` > Django 是一种热部署所以我们不需要重启服务端, 直接就能看到变化  > 这条信息就是我们刚刚在 API 中更新的数据  > ## 二、URL 调度器 >首先我们得明确什么是 URL , 全称统一资源定位符, 那么所谓 URL 调度器就是对这些 URL 网页中的地址进行一个分配和管理 > #### 我们如何学习 URL 调度器? 它的难点在哪? ------------ - 首先明白 HttpRequest 对象 > httpRequest对象是http 协议对游览器做出的一个请求动作, 整个过程我们来分析下,首先用户输入网址点击回车,由搜索引擎找到域名解析 DNS 服务商再然后 DNS 再返回路径给游览器游览器通过 http 协议与与主机建立联系 > 在完成握手后游览器解析地址接着 web 服务器就拿着这个路由去看看这个地址对应这服务器的哪一个文件地址,如果有就返回一个 httpRequest 对象当客户端并且在这个对象中我们能看到很多有用的信息, 当然服务器会根据这个地址地址返回不同的状态码 - 其实理解 URL 在整个 http 所在的地位和它的整个流程以及生命周期 > URL 在网页中占据着大量的地位, 设计一个好的 URL 对整个网站设计会有非常大的帮助, 以及后期在做 SEO 优化的时候。一个好的 URL 它的设计起初就应该是简洁的,方便的。 >并且 URL 遵循从大到小的原则并且在进行传参数的时候我们尽量做到统一标准。 - 理解简单的正则表达式 > 在框架的设计中我们在设计其中 URL conf 的时候一般是用正则表达式去匹配这个字符串然后啊再去做分发,所以我们的重点就放在了如何写出一个良好的正则表达式。 > 正则能帮我们做很多的时候比如做自动机的匹配模式,下面我们就简单的介绍正则,我们从另外一个角度去分析那么我把这个专栏放到其他的文章中请点击这里 <font>[如何彻底搞懂正则思维 ?](http://www.cxx1.com/article/2020/7/20/29.html "如何彻底搞懂正则思维 ?")</font> > #### Django 中的 URL 框架 > 步骤 1. 找 URLconf 1. 寻找 urlpatterns 2. 顺序匹配 3. 匹配成功调用视图(正则匹配) 4. 匹配失败调用错误代码视图 > 流程图 ```flow look=>start: 找到URLconf po1=>operation: 寻找urlpatterns po2=>operation: url集合 顺序查找 con=>condition: 匹配成功? con2=>condition: 还存在 url? e1=>end: 调用前端视图 e2=>end: 错误视图 look->po1 po1->po2 po2->con con(yes)->e1 con(no)->con2 con2(yes,right)->po2 con2(no)->e2 ``` ------------ > #### 现在可以开始我们的正式学习了首先我们需要知道源代码是如何运作的 > 很显然我们要使用 url 必须得导入 path 库 from django.urls import path > 接着我们需要导入视图库这可以用于展示我们的视图 from . import views > 核心代码,那么其实我们可以发现在这个 方法下面最终我们返回的是 URLPattern def _path(route, view, kwargs=None, name=None, Pattern=None): if isinstance(view, (list, tuple)): # For include(...) processing. pattern = Pattern(route, is_endpoint=False) urlconf_module, app_name, namespace = view return URLResolver( pattern, urlconf_module, kwargs, app_name=app_name, namespace=namespace, ) elif callable(view): pattern = Pattern(route, name=name, is_endpoint=True) return URLPattern(pattern, view, kwargs, name) else: raise TypeError('view must be a callable or a list/tuple in the case of include().') > 下面这段代码就是比较核心的类 class URLPattern: def __init__(self, pattern, callback, default_args=None, name=None): self.pattern = pattern self.callback = callback # the view self.default_args = default_args or {} self.name = name > 那么我们现在就合理的分析一下所谓的 URL 调度器整个工作过程, 首先如果包然后使用里面的私有方法 path 传递一堆路径仅进去,接着我们需要填写其实一共是5个参数 _path(route, view, kwargs=None, name=None, Pattern=None): > 接着调用了 URLResolver 来进行解析URL ,具体解析过程自行查看源代码 > #### 那么其实 URLPattern 在其中起了很多作用它的作用是做一个回调视图, 最后所有的核心算法都在 ResolverMatch 这个类所在的文件中,其中它做了哪些工作呢? 1. 正则匹配 2. 拼接字符串 包括模型名称类名称方法名称 > #### 说点题外话, Django 的内核代码冗余并且复杂,这是需要一点耐心去断点调试的 ------------ > #### 直接上手路由规则吧 > 我们直接在 url.py 文件中填写 urlpatterns = [ path('articles/2003/', views.special_case_2003), path('articles/<int:year>/', views.year_archive), path('articles/<int:year>/<int:month>/', views.month_archive), path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail), ] > 依照我们上面讲解的 path 接受5个参数2个参数是必须的分别是路由和视图, 这里会对视图进行解析最终返回一个 URLResolver 后的过程,如果这个视图是可回调的那么就会直接返回 URLPattern 匹配后的结果 > 否则返回一个错误信息 > #### 我们注意到这里要用尖括号来传递值, 并且在 路由的前面我们不必加 / 因为 Django会默认找到模块而不是直接知道跟目录 > ## 三、路由转换器 > 这里官方已经给出规则我们只需要做就行, 还是那句话会正则的谁还去写路径转换, 当然这里给出了我们还是学习一下 > 首先默认的几个规则 str - 匹配除了 '/' 之外的非空字符串。如果表达式内不包含转换器,则会默认匹配字符串。 int - 匹配 0 或任何正整数。返回一个 int 。 slug - 匹配任意由 ASCII 字母或数字以及连字符和下划线组成的短标签。比如,building-your-1st-django-site 。 uuid - 匹配一个格式化的 UUID 。为了防止多个 URL 映射到同一个页面,必须包含破折号并且字符都为小写。比如,075194d3-6885-417e-a8a8-6c931e272f00。返回一个 UUID 实例。 path - 匹配非空字段,包括路径分隔符 '/' 。它允许你匹配完整的 URL 路径而不是像 str 那样匹配 URL 的一部分。 >#### 自定义路径转化器的部分自行查阅这不是本章的重点, 有兴趣查询官网文档 > ## 四、 模板 > 我们定义其 views.py 文件 def index(request): return HttpResponse("Hello, world. You're at the polls index.") def detail(request, question_id): return HttpResponse("You're looking at question %s." % question_id) def results(request, question_id): response = "You're looking at the results of question %s." return HttpResponse(response % question_id) def vote(request, question_id): return HttpResponse("You're voting on question %s." % question_id) > 并且我们要在路由规则中进行规定, 这是在 polls/urls.py from django.urls import path from . import views urlpatterns = [ # ex: /polls/ path('', views.index, name='index'), # ex: /polls/5/ path('<int:question_id>/', views.detail, name='detail'), # ex: /polls/5/results/ path('<int:question_id>/results/', views.results, name='results'), # ex: /polls/5/vote/ path('<int:question_id>/vote/', views.vote, name='vote'), ] > 而在 DjangoWhite/urls.py 中我们注册, 这样才能保证整个路由规则被找到 urlpatterns = [ path('polls/', include('polls.urls')), path('admin/', admin.site.urls), ] > #### 现在我们可以访问这些页面了规则很简单 例如: http://127.0.0.1:8000/polls/2/results/ http://127.0.0.1:8000/polls/2/vote/ > #### 现在我们编写一个模板来应对这个规则 > 首先在 polls/views.py from django.http import HttpResponse from .models import Question #这是一定要导入的 def index(request): latest_question_list = Question.objects.order_by('-pub_date')[:5] output = ', '.join([q.question_text for q in latest_question_list]) return HttpResponse(output) > 现在我们可以借用 [API](http://www.cxx1.com/article/2020/7/19/28.html#%E5%9B%9B%E3%80%81%20API%20%E6%98%AF%E4%BB%80%E4%B9%88%20? "API") 向 Question 添加几个提问来看看是否符合我们的预期, 我们依次写入了5条信息 What's 5?, What's 4?, What's 3?, What's 2?, What's 1? > 如果把 [:6] 改下就是显示全部的问题, 因为数据库中一共才6条 What's 5?, What's 4?, What's 3?, What's 2?, What's 1?, What's up? > 现在我们换一种方法创建一个模板 polls/templates/polls/index.html <!DOCTYPE html> <html> <head> <title></title> </head> <body> {% if latest_question_list %} <ul> {% for question in latest_question_list %} <li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li> {% endfor %} </ul> {% else %} <p>No polls are available.</p> {% endif %} </body> </html> > 我们更新 视图 from django.http import HttpResponse from django.template import loader # 模板是必须导入用于加载视图 from .models import Question def index(request): latest_question_list = Question.objects.order_by('-pub_date')[:5] template = loader.get_template('polls/index.html') context = { 'latest_question_list': latest_question_list, } return HttpResponse(template.render(context, request)) > 和刚刚不同的是我们 调用了 loader 下面的方法 get_template,这个方法的原型如下 def get_template(template_name, using=None): loader.get_template('polls/index.html') > 并且这个名称我们定义在了视图模板中 latest_question_list > 我们回忆下前面的模板逻辑, 只有当 latest_question_list 模板存在的时候才显示问题的 id 与 描述 ,并且是通过 question 对象来进行全部的一个遍历 > 现在我们访问 http://127.0.0.1:8000/polls/ 就能看懂5条记录了 <center>  </center> > #### 值得商榷的是如果您在实践中发现了错误, 比如模板没有找到请不要灰心, 尝试看看是否路径正确 > 我们现在可以点击每一个列表然后看到问题 > #### render() 快捷函数 > 这种操作在非常多的框架中屡见不鲜, 其实就是一个助手函数,非常方便我们要长期使用, 在上面的视图代码中我们使用了 HttpResponse 与 loader 对象这是一个糟糕的,因为我们并不想使用那么多的对象来完成程序 > 现在我们直接使用快捷函数 from django.shortcuts import render > 重写编写 index 方法, 非常愉快的是我们只是使用了 render() 去渲染视图 def index(request): latest_question_list = Question.objects.order_by('-pub_date')[:5] context = {'latest_question_list': latest_question_list} return render(request, 'polls/index.html', context) > 但是现在我们又面临一个问题就是其他依靠 HttpResponse 就不能用了修改 detail() 函数为 render() 方式 def detail(request, question_id): try: question = Question.objects.get(pk=question_id) except Question.DoesNotExist: raise Http404("Question does not exist") return render(request, 'polls/detail.html', {'question': question}) > 注意了我们新加了 detail.html 模板不存在,这里我们编写我们的,路由与 index.html 一致 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {{ question }} </body> </html> > #### 现在我们来处理一些问题就是 id 不存在的情况 http://127.0.0.1:8000/polls/999/ ,这个 url会抛出 404 ,但是我们如果主动捕获这个错误并且给用户一个良好的体验呢? > views.py 中导入 from django.shortcuts import get_object_or_404, render > 现在我们就使用 get_object_or_404() 快捷函数来进行捕获 question = get_object_or_404(Question, pk=question_id) > 现在我们修改 detail.html <h1>{{ question.question_text }}</h1> <ul> {% for choice in question.choice_set.all %} <li>{{ choice.choice_text }}</li> {% endfor %} </ul> > ## 五、硬编码与软编码 > 类似 http://www.cxx1.com/admin/#/admin/blog/article/ 的我们叫硬编码, 因为这及其的不灵活, 如果我们写在 a 标签中 > 现在我们修改 index.html 中的硬编码 <li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li> 修改前 <li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li> 修改后 > #### URL 的命名空间 > 名字空间其实就是为了方便文件管理, 避免造成混乱, Django 的命名空间感觉很低端不过。。。 > 在 urls.py 中添加 app_name = 'polls' > 修改刚刚的 <li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li> > ## 总结 > #### 这篇课程我们完成了后台管理简单探索与前台路由与模板的使用下一章我们针对前台表单来优化 > 如果您喜欢本博客请收藏转发点赞。