django管理界面
设计背景
为你的员工或客户生成一个用户添加,修改和删除内容的后台是一项缺乏创造性和乏味的工作。因此,django全自动地根据模型创建后台界面。
django产生于一个公众页面和内容发布者页面完全分离的新闻类站点的开发过程中。
站点管理人员使用管理系统来添加新闻、时间和体育时讯等,这些添加的内容被显示在公共页面上。django通过为站点管理人员创建统一的内容编辑界面解决了这个问题。
管理界面不是为了网站的访问者,而是为了管理者准备的。
创建一个管理员账号
首先,我们得创建一个能登录管理页面的用户。请运行下面的命令:
py -3 manage.py createsuperuser
D:\django\mysite>py -3 manage.py createsuperuser
#输入用户名
Username (leave blank to use ‘lenovo‘): admin
#输入邮箱
Email address: [email protected]
#输入密码
Password:
Password (again):
The password is too similar to the username.
This password is too short. It must contain at least 8 characters.
This password is too common.
Bypass password validation and create user anyway? [y/N]: y
启动开发服务器
django的管理页面默认就是启用的。让我们启用开发服务器,看看它到底是什么样的。
如果开发服务器未启动,用以下命令启动它:
python manage.py runserver
浏览器访问http://127.0.0.1:8000/admin/,转到本地域名的”/admin/”目录,你会看到管理员登录界面:
django默认开启翻译功能,所以登录界面可能会使用浏览器的语言,取决于浏览器的设置和django是否拥有你语言的翻译。
进入管理员站点页面
现在,试着使用你在上一步中创建的超级用户来登录。然后你将会看到django管理页面的索引页:
你将会看到几种可编辑的内容:组和用户。它们是由django.contrib.auth提供的,这是django开发的认证框架。
向管理页面中加入投票应用
但是我们的投票应用在哪儿呢?它没在索引页面里显示
只需要做一件事:我们得告诉管理页面,问题Question对象需要被管理。开发polls/admin.py文件,把它编辑成下面这样:
polls/admin.py:
from django.contrib import admin # Register your models here. from .models import Question admin.site.register(Question)
体验便捷的管理功能
现在我们向管理页面注册了问题Question类。django知道它应该被显示在索引页里:
点击“Question”。现在看到是问题“Question”对象的列表“change list”。这个界面会显示所有数据库里的问题Queston对象,你可以选择一个来修改。这里现在有我们在上一部分中创建的”What’s new?”问题。
点击”What’s new?”来编辑这个问题(Question)对象:
注意事项:
1)这个表单时从问题Question模型中自动生成的
2)不同的字段类型(日期时间字段DateTimeField、字符字段CharField)会生成对应的HTML输入控件。每个类型的字段都知道它们该如何在管理页面显示自己。
3)每个日期时间字段DateTimeField都有JavaScript写的快捷按钮。日期有转到今天(Today)的快捷按钮和一个弹出式日历界面。时间有设为现在(Now)的快捷按钮和一个列出常用时间的方便的弹出式列表。
页面底部提供了几个选项
1)保存(Save)-保存修改,然后返回对象列表
2)保存并继续编辑(Save and continue editing)-保存改变,然后重新载入当前对象的修改界面。
3)保存并新增(Save and add another)-保存改变,然后添加一个新的空对象并载入修改界面
4)删除(Delete)-显示一个确认删除页面
如果显示的“发布日期(Date Published)”和你在创建它们的时间不一致,这意味着你可能没有正确的设置时区(TIME_ZONE)。改变设置,然后重新载入页面看看是否显示了正确的值。
通过点击“今天(Today)”和 “现在(Now)”按钮改变“发布日期(Date Published)”。然后点击“保存并继续编辑(Save and add another)”按钮。然后点击右上角的“历史(History)”按钮。你会看到一个列出了所有通过django管理页面对当前对象进行的改变的页面,其中列出了时间戳和进行修改操作的用户名:
视图
django中的视图的概念是【一类具有相同功能和模板的网页的集合】。
比如,在一个博客应用中,你可能会创建如下几个视图:
1)博客首页—展示最近的几项内容。
2)内容“详情”页—详细展示某项内容
3)以年为单位的归档页—展示选中的月份里各天创建的内容。
4)以天为单位的归档页—展示选中天里创建的所有内容
5)评论处理器—用于响应为一项内容添加评论的操作
在我们的投票应用中,我们需要下列几个视图:
1)问题索引页—展示最近的几个投票问题
2)问题详情页—展示某个投票的问题和不带结果的选项类表
3)问题结果页—展示某个投票的结果
4)投票处理器—用于响应用户为某个问题的特定选项投票的操作
在django中,网页和其他内容都是从视图派生而来。
每一个视图表现为一个简单的python函数(或者说方法,如果是在基于类的视图里的话)。
django将会根据用户请求的URL来选择使用哪个视图(更准确的说,是根据URL中域名之后的部分)。
在你上网的过程中,很可能看见过像这样的URL:
“ME2/Sites/dirmod.sap?sid=&type=gen&mod=Core+Pages&gid=A6CD123KJUHJ213”。别担心,django里的URL规则要比这优雅的多!
一个URL模式定义了某种URL的基本格式
—举个例子:/newsarchive/<year>/<month>/
为了将URL和视图关联起来,django使用了’URLconfs’来配置。URLconf将URL模式映射到视图。
如:mysite/urls.py:
urlpatterns = [ path(‘polls/‘, include(‘polls.urls‘)), path(‘admin/‘, admin.site.urls), ]
待练习URL调度器:https://docs.djangoproject.com/zh-hans/2.1/topics/http/urls/
编写更多视图
现在我们向polls/views.py里添加更多视图,这些视图有一些不同,因为他们接收参数:
polls/views.py:
def detail(request, question_id): return HttpResponse("You‘re lokking at question %s." % requestion_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模块里,只要添加几个url()(re_path函数的别名)函数调用就可以:
添加视图函数到polls.urls模块
polls/urls.py:
urlpatterns = [ # ex: /polls/ path(‘‘, views.index, name=‘index‘), # ex: /polls/5/ path(‘<int:question_id>/‘, views.detail, name=‘detail‘), # ex:/pools/5/results/ path(‘<int:question_id>/results/‘, views.results, name=‘results‘), # ex: /polls/5/vote/ path(‘<int:question_id>/vote/‘, views.vote, name=‘vote‘), ]
浏览器访问”/polls/14/”,django会将运行detail()方法并且展示你在URL里提供的问题ID。
访问”/polls/34/vote/”和”/polls/14/vote/”,你将会看到暂时用于占位的结果和投票页
当某人请求你网站的某一页时,如”/polls/14/”, django将会载入mysite.urls模块
因为这在配置项ROOT_URLCONF中设置了:
settings.py:
ROOT_URLCONF = ‘mysite.urls‘ mysite/urls.py: urlpatterns = [ path(‘polls/‘, include(‘polls.urls‘)), path(‘admin/‘, admin.site.urls), ]
polls/urls.py:
urlpatterns = [ # ex: /polls/ path(‘‘, views.index, name=‘index‘), # ex: /polls/5/ path(‘<int:question_id>/‘, views.detail, name=‘detail‘), # ex:/pools/5/results/ path(‘<int:question_id>/results/‘, views.results, name=‘results‘), # ex: /polls/5/vote/ path(‘<int:question_id>/vote/‘, views.vote, name=‘vote‘), ]
然后django寻找名为urlpatterns变量并且按顺序匹配正则表达式。在找到匹配项’polls/’,它切掉了匹配的文本(”polls/”),将剩余文本--”14/”,发送到”polls.urls” URLconf做进一步处理。
URLconf就是指polls.urls
url匹配视图的过程
匹配的顺序是先根据settings.py中ROOT_URLCONF变量(‘mysite.urls‘)指向的urls文件去找urlpatterns变量,在urlpatterns变量中依次匹配path()函数中的route参数(‘polls/‘),匹配到之后,把匹配到的文本(‘polls/‘--路径的一部分)截掉,剩余的文本(‘14/’),去path()函数中指定的URLconf(polls.urls)中去匹配视图函数,这里剩余的文本”14/”匹配到了’<int:question_id>/’,使得django以如下形式调用detail():
detail(request=<HttpRequest object>, question_id=14)
polls/views.py: detail函数的定义:
def detail(request, question_id): return HttpResponse("You‘re lokking at question %s." % question_id)
question_id=14由<int:question_id>匹配生成。使用尖括号“捕获”这部分URL,且以关键字参数的形式发送给视图函数。上述字符串的:question_id>部分定义了将被用于区分匹配模式的变量名,这里的模式就是urlpattern里的一行匹配代码,而int: 则是一个转换器,决定了应该以什么变量类型匹配这部分的URL路径。
为每个URL加上不必要的东西,例如.html,是没有必要的。如果非要加的话,也可以:
path(‘polls/latest.html’, views.index),
但不推荐这样做,太low了
写一个真正有用的视图
每个视图必须要做的只有两件事:
返回一个包含被请求页面内容的HttpResponse对象,或抛出一个异常,比如Http404。
至于你还想干些什么,随便你。
你的视图可以从数据库里读取记录,可以使用一个模板引擎(比如django自带的,或者其他第三方的),可以生成一个PDF文件,可以输出一个XML,创建一个ZIP文件,你可以做任何你想做的事,使用任何你想用的python库。
django只要求返回的是一个HttpResponse,或者抛出一个异常
因为django自带的数据库API很方便,我们在前面学过,所以我们试试在视图里使用它。
在index()函数里插入一些新的内容,让它能展示数据库里以发布日期排序的最近5个投票问题,以空格分割:
from django.shortcuts import render # Create your views here. 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)
其他视图函数不变(detail,results,vote)
为了演示,我们添加6个问题:
查看数据库中的数据
浏览器访问http://127.0.0.1:8000/polls/,触发index视图函数:
这里有个问题:页面的设计写死在视图函数的代码里的。如果你想改变页面的样子,你需要编辑python代吗。所以让我们使用django的模板系统,只要创建一个视图,就可以将页面的设计从代码中分离出来。
使用django的模板系统
首先,在你的polls项目里创建一个templates目录。django将会在这个目录里查找模板文件。
你的项目的TEMPLATES配置项描述了django如何载入和渲染模板。默认的设置文件设置了DjangoTemplates后端,并将APP_DIRS设置成了True。这一选项将会让DjangoTemplates在每个INSTALLED_APPS文件夹中寻找”templates”子目录。
settings.py:
INSTALLED_APPS = [ ‘polls.apps.PollsConfig‘, ‘django.contrib.admin‘, ‘django.contrib.auth‘, ‘django.contrib.contenttypes‘, ‘django.contrib.sessions‘, ‘django.contrib.messages‘, ‘django.contrib.staticfiles‘, ] TEMPLATES = [ { ‘BACKEND‘: ‘django.template.backends.django.DjangoTemplates‘, ‘DIRS‘: [], ‘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‘, ], }, }, ]
在你刚刚创建的templates目录里,再创建一个目录polls,然后在其中新建一个文件index.html。换句话说,你的模板文件的路径应该是polls/templates/polls/index.html。因为django会寻找到对应的app_directories,所以你只需要使用polls/index.html就可以引用到这一模板了。
模板命名空间
虽然我们现在可以将模板文件直接在polls/templates文件中(而不是再建立一个polls子文件夹),但是这样做不太好。django将会选择第一个匹配的模板文件,如果你有一个模板文件正好和另一个应用中的某个模板文件重名,django没有办法区分它们。我们需要帮助django选择正确的模板,最简单的方法就是把它们放入个字的命名空间中,也就是把这些模板放入一个和自身应用重名的子文件夹里。
所以我们在templates文件夹下,新建一个跟应用重名的文件夹”polls”,然后在该子文件夹下新建一个index.html文件:polls/templates/polls/index.hmtl
在index.html模板中输入如下代码
{% 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 %}
然后,让我们更新一下polls/views.py里的index视图来使用模板:
视图函数中使用模板:
polls/view.py:
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))
上下文:
上述代码的作用是,载入polls/index.html模板文件,并且向它传递一个上下文(context)。这个上下文是一个字典,它将模板内的变量映射为python对象。
此处context是一个字典,渲染模板时通过template.render()方法把context和请求对象传入到模板文件中,在模板文件中,对context中的对象进行渲染
再次触发视图函数,渲染模板
浏览器访问”polls/”,将会看到一个无序列表,列出了我们在之前添加的投票问题,链接指向了这个投票的详情页。
点击链接:
快捷函数:render()
“载入模板,填充上下文,再返回由它生成的HttpResponse对象”,是一个非常常用的操作流程。
于是django提供了一个快捷函数,我们用它来重写index()视图:
polls/views.py
from django.shortcuts import render from .models import Question 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)
注意,我们不再需要导入loader和HttpResponse,不过如果你还有其他函数(比如details,results和vote)需要用到它的话,就需要保持HttpResponse的导入
再次启动服务器,访问127.0.0.1:8000/polls/,可以正常访问
render()函数的第一个参数是请求对象request,模板文件名称作为第二个参数,第三个参数是一个可选的,字典形式的对象。render()函数返回的是模板文件根据context参数渲染后得到的HttpResponse对象。
抛出404错误
现在,我们来处理投票详情视图—它会显示指定投票的问题标题。下面是视图的代码:
polls/views.py:
from django.shortcuts import render from .models import Question from django.http import Http404 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})
这里有个新原则,如果指定问题ID所对应的问题不存在,这个视图就会抛出一个Http404异常。
我们稍后讨论你需要在polls/detail.html里输入什么,但是如果你想试试上面这段代码是否正常工作的话,可以暂时把下面这段输进去,这样你就能测试了。
polls/templates/polls/detail.html:
{{ question }}
访问一个不存在的request_id: http://127.0.0.1:8000/polls/10/
快捷函数:get_object_or_404()
尝试用get()函数获取一个对象,如果不存在就抛出Http404错误也是一个普遍的流程。
django也提供了一个快捷函数,下面是修改后的详情detail()视图代码:
polls/views.py:
from django.shortcuts import get_object_or_404, render from .models import Question def detail(request, question_id): question = get_object_or_404(Question, pk=question_id) return render(request, ‘polls/detail.html‘, {‘question‘: question})
get_object_or_404()方法的第一个参数是模型类,第二个参数可以是任意的数字,该数字会传给模型类对应的manager的get()方法,如果用该数字查不到对象,则会报Http404错误
设计哲学:
为什么我们使用辅助函数get_object_or_404()而不是自己捕获ObjectDoesNotExist异常呢?还有,为什么模型API不直接抛出ObjectDoesNotExist而是抛出Http404呢?
因为这样做会增加模型层和视图层的耦合性。指导django设计的最重要的思想之一就是要保证松散耦合。一些受控的耦合将会包含在django.shortcuts模块中。
也有get_list_or_404()函数,工作原理和get_object_or_404()一样,除了get()函数被换成了filter()函数。如果类表为空的话会抛出Http404异常。
原文地址:https://www.cnblogs.com/xiaxiaoxu/p/11665875.html