赞
踩
Django最初被设计用于具有快速开发需求的新闻类站点,目的是实现简单快捷的网站开发。
conda create -n django_env python=3.10
conda activate django_env
python -m pip install Django
python
>>> import django
>>> print(django.get_version())
5.0.1
创建一个基本的投票应用程序,由两部分组成:一个让人们查看和投票的公共站点,一个让你能添加、修改和删除投票的管理站点。
# 在当前目录下创建一个mysite目录
django-admin startproject mysite
# 默认8000端口,会自动重新加载的服务器runserver
python manage.py runserver
# 更换端口
python manage.py runserver 8080
在 Django 中,每一个应用都是一个 Python 包,并且遵循着相同的约定。Django 自带一个工具,可以帮你生成应用的基础目录结构,这样你就能专心写代码,而不是创建目录了。
应用是一个专门做某件事的网络应用程序——比如博客系统,或者公共记录的数据库,或者小型的投票程序。项目则是一个网站使用的配置和应用的集合。项目可以包含很多个应用。应用可以被很多个项目使用。
python manage.py startapp polls
(1)打开polls/views.py,添加以下代码。
from django.shortcuts import render
from django.http import HttpResponse
def index(request):
return HttpResponse("Hello, world. You're at the polls index.")
(2)在polls目录中创建一个URL配置,创建urls.py
,添加以下代码。
from django.urls import path
from . import views
urlpatterns = [
path("", views.index, name="index"),
]
(3)在根URLconf文件中指定创建的polls.urls
模块,在mysite/urls.py
文件中添加以下代码。
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
# include允许引用其他URLConfs
path("polls/", include("polls.urls")),
path('admin/', admin.site.urls),
]
(4)函数path有四个参数,两个必传参数route和view,两个可选参数kwargs和name。
(1)打开mysite/setting.py
,该配置包含了Django项目设置的Python模块。
SQLite
作为默认数据库。DATABASES = {
'default': {
# ENGINE的可选值:'django.db.backends.sqlite3','django.db.backends.postgresql',
# 'django.db.backends.mysql',或 'django.db.backends.oracle'
'ENGINE': 'django.db.backends.sqlite3',
# NAME是数据库名称,如果使用SQLite,就是文件的完整的绝对路径
# 如果不适用SQLite,需要添加USER、PASSWORD、HOST等
'NAME': BASE_DIR / 'db.sqlite3',
}
}
(2)设置TIME_ZONE为自己的时区。
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
(3)设置应用,默认开启的应用需要至少一个数据表,使用前需要创建一些表
# 这个 migrate 命令查看 INSTALLED_APPS 配置,并根据 mysite/settings.py 文件中的数据库配置和随应用提供的数据库迁移文件,创建任何必要的数据库表。你会看到它应用的每一个迁移都有一个消息。
python manage.py migrate
INSTALLED_APPS = [ # 默认包含了以下自带应用 # 管理员站点 'django.contrib.admin', # 认证授权系统 'django.contrib.auth', # 内容类型框架 'django.contrib.contenttypes', # 会话框架 'django.contrib.sessions', # 消息框架 'django.contrib.messages', # 管理静态文件的框架 'django.contrib.staticfiles', # 添加应用配置 'polls.apps.PollsConfig', ]
(1)一个模型就是单个定义你的数据的信息源。模型中包含了不可缺少的数据区域和你存储数据的行为。
(2)创建两个模型
问题Question:包括问题描述和发布时间;
选项Choice:包括选项描述和当前得票数。
打开polls/models.py
文件,添加以下内容。
import datetime from django.db import models from django.utils import timezone # 每个模型都是django.db.models.Model类的子类 class Question(models.Model): # 模型的变量表示一个数据库字段,每个字段都是Field类的实例 # question_text也是字段名 question_text = models.CharField(max_length=200) pub_date = models.DateTimeField("date published") def __str__(self): return self.question_text def was_published_recently(self): return self.pub_date >= timezone.now() - datetime.timedelta(days=1) class Choice(models.Model): question = models.ForeignKey(Question, on_delete=models.CASCADE) choice_text = models.CharField(max_length=200) votes = models.IntegerField(default=0) def __str__(self): return self.choice_text
(3)激活模型
首先把polls应用安装到我们的项目里。在INSTALLED_APPS中添加配置。因为PollConfig类写在文件polls/apps.py中,所以它的路径是’polls.apps.PollsConfig’。
# 通过运行 makemigrations 命令,Django 会检测你对模型文件的修改,并且把修改的部分储存为一次迁移。
# migrate是自动执行数据库迁移并同步管理你的数据库结构的命令。
python manage.py makemigrations polls
# 查看迁移命令会执行哪些SQL语句
# 主键id会被自动创建,也可以自定义;数据库表名由应用名polls和模型名如question连接而来;
# 默认Django会在外键字段名后追加字符串"_id"
python manage.py sqlmigrate polls 0001
# 检查项目中的问题
python manage.py check
# 再次运行migrate在数据库里创建新定义的模型的数据表
python manage.py migrate
(1)进入交互式Python命令行
# 我们使用这个命令而不是简单的使用“python”是因为 manage.py 会设置 DJANGO_SETTINGS_MODULE 环境变量,这个变量会让 Django 根据 mysite/settings.py 文件来设置 Python 包的导入路径。
python manage.py shell
# 进入shell后就可以探索数据库API >>> from polls.models import Choice, Question >>> Question.objects.all() >>> from django.utils import timezone # 添加记录 >>> q = Question(question_text="What's new?", pub_date=timezone.now()) >>> q.save() >>> q.id >>> q.question_text >>> q.pub_date # 修改字段值 >>> q.question_text = "What's up?" >>> q.save() # 关键词查找 >>> Question.objects.filter(id=1) >>> Question.objects.filter(question_text__startswith="What") # 获取今年发布的问题 >>> from django.utils import timezone >>> current_year = timezone.now().year >>> Question.objects.get(pub_date__year=current_year) # 请求不存在的记录会抛出一个异常 >>> Question.objects.get(id=2) # 查找主键值 >>> Question.objects.get(pk=1) >>> q = Question.objects.get(pk=1) >>> q.was_published_recently() >>> q.choice_set.all() # 创建三个选项 >>> q.choice_set.create(choice_text="Not much", votes=0) >>> q.choice_set.create(choice_text="The sky", votes=0) >>> c = q.choice_set.create(choice_text="Just hacking again", votes=0) >>> c.question >>> q.choice_set.count() # 删除选项 >>> c = q.choice_set.filter(choice_text__startswith="Just hacking") >>> c.delete()
(1)创建一个管理员账号
# 创建一个能登录管理页面的用户,添加用户admin/admin
python manage.py createsuperuser
(2)启动开发服务器
Django的管理界面默认就是启用的,启动开发服务器,访问/admin/目录。
(3)向管理界面中加入投票应用
# 打开polls/admin.py
from django.contrib import admin
from .models import Question
admin.site.register(Question)
Django中的视图是一类具有相同功能和模板的网页的集合。网页和其他内容都是从视图派生而来。每个视图表现为一个Python函数,会根据用户请求的URL来选择使用哪个视图。
(1)投票应用中需要的视图
(2)URLconf将URL模式映射到视图
(3)编写更多的视图
# 向polls/views.py中添加更多视图 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文件 urlpatterns = [ path("", views.index, name="index"), # 使用尖括号获得网址部分后发送给视图函数作为一个关键字参数 # question_id部分定义了要使用的名字,用来识别相匹配的模式 # int部分是一种转换形式,用来确定应该匹配网址路径的什么模式 # 冒号用来分隔转换形式和模式名 path("<int:question_id>/", views.detail, name="detail"), path("<int:question_id>/results/", views.results, name="results"), path("<int:question_id>/vote/", views.vote, name="vote"), ]
(4)重构index方法
每个视图必须要要做的只有两个事情:返回一个包含被请求页面内容的HttpResponse对象或者抛出一个异常。
from django.shortcuts import render from .models import Question # Create your views here. from django.http import HttpResponse # 展示数据库里以发布日期排序的最近5个投票问题 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) 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)
(5)使用Django的模板系统
在polls目录里新建一个templates目录,TEMPLATES配置项描述了如何载入和渲染模板。默认的设置文件设置了DjangoTemplates后端,并将APP_DIRS设置为True。这一选项将会让
DjangoTemplates
在每个 INSTALLED_APPS 文件夹中寻找 “templates” 子目录。在你刚刚创建的templates
目录里,再创建一个目录polls
,然后在其中新建一个文件index.html
。换句话说,你的模板文件的路径应该是polls/templates/polls/index.html
。因为app_directories
模板加载器是通过上述描述的方法运行的,所以 Django 可以引用到polls/index.html
这一模板了。
# polls/settings.py 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', ], }, }, ]
<!-- polls/templates/polls/index.html -->
{% if latest_question_list %}
<ul>
{% for question in latest_question_list %}
<!-- 硬编码连接 -->
<!-- <li><a href="/polls/{{ question.id }}/">{{ question.question_text }}</a></li> -->
<!-- 在polls.urls模块的URL定义中寻具有指定名字的条目 -->
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No polls are available.</p>
{% endif %}
# 更新index视图
from django.template import loader
# 载入模板文件并传递一个上下文
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))
(6)快捷函数render
render函数载入模板,填充上下文,再返回由它生成的HttpResponse对象。
# 更新index视图,我们不在需要导入loader和HttpResponse
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)
(7)抛出404错误
# 更新detail视图
from django.http import Http404
from django.shortcuts import render
from .models import Question
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})
<!-- polls/templates/polls/detail.html -->
<!-- 模板系统使用点符号访问变量的属性 -->
<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
<li>{{ choice.choice_text }}</li>
{% endfor %}
</ul>
(8)快捷函数get_object_or_404
from django.shortcuts import render, get_object_or_404
# 更新detail视图
def detail(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, "polls/detail.html", {"question":question})
(9)为URL名称添加命名空间
# 在根URLconf中添加命名空间,修改polls/urls.py
from django.urls import path
from . import views
app_name = "polls"
urlpatterns = [
path("", views.index, name="index"),
path("<int:question_id>/", views.detail, name="detail"),
path("<int:question_id>/results/", views.results, name="results"),
path("<int:question_id>/vote/", views.vote, name="vote"),
]
<!-- polls/templates/polls/index.html -->
<li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
(1)编写一个简单的表单
<!-- 更新polls/detail.html模板 --> <form action="{% url 'polls:vote' question.id %}" method="post"> <!-- 防止跨站请求伪造 --> {% csrf_token %} <fieldset> <legend><h1>{{ question.question_text }}</h1></legend> {% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %} {% for choice in question.choice_set.all %} <!-- 在每个选项前加上一个单选按钮,value属性对应选项的ID --> <!-- 当有人选择一个单选按钮并提交表单,会发送一个POST数据choice=ID --> <!-- forloop.counter指示for标签已经循环多少次 --> <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}"> <label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br> {% endfor %} </fieldset> <input type="submit" value="投票"> </form>
(2)更新vote和result视图
# polls/views.py from django.http import HttpResponse, HttpResponseRedirect from django.shortcuts import render, get_object_or_404 from django.urls import reverse from .models import Question, Choice def vote(request, question_id): question = get_object_or_404(Question, pk=question_id) try: # request.POST是一个类字典对象,通过关键字的名字获取提交的字符串数据 selected_choice = question.choice_set.get(pk=request.POST["choice"]) except (KeyError, Choice.DoesNotExist): return render(request, "polls/detail.html", { "question":question, "error_message":"You didn't select a choice." }) else: selected_choice.votes += 1 selected_choice.save() # 增加选项的投票后重定向到结果页 # reverse函数避免在视图函数中硬编码URL,需要传递的是要跳转的视图名字和参数 return HttpResponseRedirect(reverse("polls:results", args=(question.id,))) def results(request, question_id): question = get_object_or_404(Question, pk=question_id) return render(request, "polls/results.html", {"question":question})
(3)创建一个结果页面
<!-- polls/results.html -->
<h1>{{ question.question_text }}</h1>
<ul>
{% for choice in question.choice_set.all %}
<li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li>
{% endfor %}
</ul>
<a href="{% url 'polls:detail' question.id %}">Vote again?</a>
(4)使用通用视图精简代码
(5)改良URLconf
# polls/urls.py
from django.urls import path
from . import views
app_name = "polls"
urlpatterns = [
path("", views.IndexView.as_view(), name="index"),
path("<int:pk>/", views.DetailView.as_view(), name="detail"),
path("<int:pk>/results/", views.ResultsView.as_view(), name="results"),
path("<int:question_id>/vote/", views.vote, name="vote"),
]
(6)改良视图
# polls/views.py from django.http import HttpResponseRedirect from django.shortcuts import render, get_object_or_404 from django.urls import reverse from django.views import generic from .models import Question, Choice class IndexView(generic.ListView): template_name = "polls/index.html" # 替代默认提供的对象 context_object_name = "latest_question_list" def get_queryset(self): return Question.objects.order_by("-pub_date")[:5] class DetailView(generic.DetailView): # 每个通用模型都需要知道它要操作的模型 # 通过model属性提供这个信息或者定义get_queryset()方法来实现 model = Question # 默认情况下,DetailView会使用<app name>/<model name>_detail.html的模板 # template_name属性是用来告诉Django使用一个指定的模板名字,而不是自动生成的默认名字 template_name = "polls/detail.html" class ResultsView(generic.DetailView): model = Question template_name = "polls/results.html" def vote(request, question_id): question = get_object_or_404(Question, pk=question_id) try: selected_choice = question.choice_set.get(pk=request.POST["choice"]) except (KeyError, Choice.DoesNotExist): return render(request, "polls/detail.html", { "question":question, "error_message":"You didn't select a choice." }) else: selected_choice.votes += 1 selected_choice.save() return HttpResponseRedirect(reverse("polls:results", args=(question.id,)))
测试代码是用来检查你的代码是否能够正常运行的程序。测试在不同的层次中都存在。自动化测试是由某个系统帮你自动完成的。当你创建好了一系列测试,每次修改应用代码后,就可以自动检查出修改后的代码是否还像你曾经预期的那样正常工作。你不需要花费大量时间来进行手动测试。
(1)为什么你需要写测试
(2)基础测试策略
一些开发者遵循“测试驱动”的开发原则,他们在写代码之前先写测试。
(3)开始写一个测试
我们的
polls
应用现在就有一个小 bug 需要被修复:我们的要求是如果 Question 是在一天之内发布的,Question.was_published_recently()
方法将会返回True
,然而现在这个方法在Question
的pub_date
字段比当前时间还晚时也会返回 True。
# 打开shell,查看这个问题
python manage.py shell
>>> import datetime
>>> from django.utils import timezone
>>> from polls.models import Question
>>> future_question = Question(pub_date=timezone.now() + datetime.timedelta(days=30))
>>> future_question.was_published_recently()
True
# 测试需要写在polls/tests.py中,测试系统会自动寻找以test开头的测试函数并执行
import datetime
import datetime
from django.test import TestCase
from django.utils import timezone
from .models import Question
class QuestionModelTests(TestCase):
def test_was_published_recently_with_future_question(self):
time = timezone.now() + datetime.timedelta(days=30)
future_question = Question(pub_date=time)
self.assertIs(future_question.was_published_recently(), False)
# 在终端运行测试,会自动寻找polls应用中的测试代码,找到TestCase的子类创建一个特殊的数据库供测试使用,寻找类中的test开头的方法执行
python manage.py test polls
# 修复这个问题,更新models.py中方法后再次运行测试问题解决
def was_published_recently(self):
now = timezone.now()
return now - datetime.timedelta(days=1) <= self.pub_date <= now
(4)测试视图
Django提供了一个供测试使用的Client来模拟用户和视图层代码的交互。
# setup_test_environment()安装了一个模板渲染器,使我们能够检查响应上的一些额外属性 >>> from django.test.utils import setup_test_environment >>> setup_test_environment() # 导入测试客户端类 >>> from django.test import Client >>> client = Client() # 获取'/'的响应 >>> response = client.get("/") >>> response.status_code 404 >>> from django.urls import reverse >>> response = client.get(reverse("polls:index")) >>> response.status_code 200 >>> response.content >>> response.context['latest_question_list']
from django.utils import timezone
# 更新ListView视图类
class IndexView(generic.ListView):
template_name = "polls/index.html"
context_object_name = "latest_question_list"
def get_queryset(self):
return Question.objects.filter(pub_date__lte=timezone.now())
.order_by("-pub_date")[:5]
# 更新polls/tests.py import datetime from django.test import TestCase from django.utils import timezone from .models import Question from django.urls import reverse # 封装了创建投票的流程,减少了重复代码 def create_question(question_text, days): time = timezone.now() + datetime.timedelta(days=days) return Question.objects.create(question_text=question_text, pub_date=time) class QuestionIndexViewTests(TestCase): def test_no_questions(self): response = self.client.get(reverse("polls:index")) self.assertEqual(response.status_code, 200) self.assertContains(response, "No polls are available.") self.assertQuerySetEqual(response.context["latest_question_list"], []) def test_past_question(self): question = create_question(question_text="Past question.", days=-30) response = self.client.get(reverse("polls:index")) self.assertQuerySetEqual( response.context["latest_question_list"], [question], ) class QuestionModelTests(TestCase): def test_was_published_recently_with_future_question(self): time = timezone.now() + datetime.timedelta(days=30) future_question = Question(pub_date=time) self.assertIs(future_question.was_published_recently(), False)
# 更新DetailView视图,排除还未发布的问题
class DetailView(generic.DetailView):
model = Question
template_name = "polls/detail.html"
def get_queryset(self):
return Question.objects.filter(pub_date__lte=timezone.now())
(1)自定义应用的界面和风格
在polls目录下新建static目录,Django将在该目录下查找静态文件。Django 的
STATICFILES_FINDERS
设置包含了一系列的查找器,它们知道去哪里找到static文件。AppDirectoriesFinder
是默认查找器中的一个,它会在每个INSTALLED_APPS
中指定的应用的子文件中寻找名称为static
的特定文件夹,就像我们在polls
中刚创建的那个一样。管理后台采用相同的目录结构管理它的静态文件。
/* 在polls目录下创建static目录,在创建polls目录,然后添加style.css样式表
polls/static/polls/style.css */
li a {
color: green;
}
<!-- 在polls/templates/polls/index.html中添加样式表 -->
<!-- static模板标签生成静态文件的绝对路径 -->
{% load static %}
<link rel="stylesheet" href="{% static 'polls/style.css' %}">
(2)添加背景图
在
polls/static/polls/
目录中创建images
子目录。 在此目录中,添加您想用作背景的任何图像文件。
(1)自定义后台表单
通过
admin.site.register(Question)
注册Question
模型,Django 能够构建一个默认的表单用于展示。通常来说,你期望能自定义表单的外观和工作方式。你可以在注册模型时将这些设置告诉 Django。
# polls/admin.py
from django.contrib import admin
from .models import Question
class QuestionAdmin(admin.ModelAdmin):
fields = ["pub_date", "question_text"]
# 创建一个模型后台类,接着将其作为第二个参数传递给函数
admin.site.register(Question, QuestionAdmin)
# 将表单分为几个字段集
from django.contrib import admin
from .models import Question
class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
# fieldsets元组第一个元素是字段集的标题
(None, {"fields": ["question_text"]}),
("Date information", {"fields": ["pub_date"]}),
]
admin.site.register(Question, QuestionAdmin)
(2)添加关联的对象
# polls/admin.py from django.contrib import admin from .models import Question, Choice # 使用admin.TabularInline可以使关联对象以一种表格的方式展示 class ChoiceInline(admin.StackedInline): model = Choice extra = 3 class QuestionAdmin(admin.ModelAdmin): fieldsets = [ (None, {"fields": ["question_text"]}), ("Date information", {"fields": ["pub_date"]}), ] inlines = [ChoiceInline] admin.site.register(Question, QuestionAdmin)
(3)自定义后台更改列表
默认情况下,Django 显示每个对象的
str()
返回的值。但有时如果我们能够显示单个字段,它会更有帮助。为此,使用list_display
后台选项,它是一个包含要显示的字段名的元组,
# polls/admin.py
class QuestionAdmin(admin.ModelAdmin):
class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
(None, {"fields": ["question_text"]}),
("Date information", {"fields": ["pub_date"]}),
]
inlines = [ChoiceInline]
list_display = ["question_text", "pub_date", "was_published_recently"]
# 优化过滤器,添加了一个过滤器侧边栏
list_filter = ["pub_date"]
# 列表顶部添加搜索框
search_fields = ["question_text"]
# polls/models.py import datetime from django.db import models from django.utils import timezone from django.contrib import admin class Question(models.Model): question_text = models.CharField(max_length=200) pub_date = models.DateTimeField("date published") def __str__(self): return self.question_text # 通过display装饰器给方法添加排序字段 @admin.display( boolean=True, ordering="pub_date", description="Published recently?", ) def was_published_recently(self): now = timezone.now() return now - datetime.timedelta(days=1) <= self.pub_date <= now
(4)自定义后台界面和风格
在工程目录(包含manage.py的那个文件夹)内创建一个templates目录。
# mysite/settings.py中添加DIRS选项 TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", "DIRS": [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", ], }, }, ]
在templates目录中创建一个admin目录,将默认的Django管理界面模板目录中的模板文件复制到该目录中(admin/base_site.html)。默认的 Django 管理界面模板目录位于 Django 源代码中django/contrib/admin/templates。
# 获取Django源码的位置
python -c "import django;print(django.__path__)"
<!-- 修改base_site.html内容 -->
{% extends "admin/base.html" %}
{% block title %}{% if subtitle %}{{ subtitle }} | {% endif %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %}
{% block branding %}
<div id="site-name"><a href="{% url 'admin:index' %}">Polls Administration</a></div>
{% if user.is_anonymous %}
{% include "admin/color_theme_toggle.html" %}
{% endif %}
{% endblock %}
{% block nav-global %}{% endblock %}
(5)自定义你应用的模板
DIRS默认是空的,Django 是怎么找到默认的后台模板的?因为
APP_DIRS
被置为True
,Django 会自动在每个应用包内递归查找templates/
子目录
(6)自定义后台主页
默认情况下,它展示了所有配置在
INSTALLED_APPS
中,已通过后台应用注册,按拼音排序的应用。你可能想对这个页面的布局做重大的修改。毕竟,索引页是后台的重要页面,它应该便于使用。需要自定义的模板是admin/index.html
。
以Django Debug Toolbar为例。
(1)安装
python -m pip install django-debug-toolbar
与 Django 集成的第三方包需要一些安装后的设置,以将它们与你的项目整合在一起。通常,你需要将包的 Django 应用程序添加到你的
INSTALLED_APPS
设置中。有些包需要其他更改,比如添加到你的 URL 配置(urls.py
)中。
(2)安装其他第三方包
可以使用Django资源 Django Packages来查找更多的第三方包。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。