Django官方文档笔记
文章开始把我喜欢的这句话送个大家:这个世界上还有什么比自己写的代码运行在一亿人的电脑上更酷的事情吗,如果有那就是让这个数字再扩大十倍
1.函数 include() 允许引用其它URLconfs。每当Django 遇到:func:~django.urls.include 时,它会截断与此项匹配的URL 的部分,并将剩余的字符串发送到URLconf 以供进一步处理。
我们设计 include() 的理念是使其可以即插即用。因为投票应用有它自己的URLconf( polls/urls.py ),他们能够被放在"/polls/" ,"/fun_polls/" ,"/content/polls/",或者其他任何路径下,这个应用都能够正常工作。
何时使用 include()
当包括其它URL 模式时你应该总是使用 include() , admin.site.urls 是唯一例外。
我们想在myapp中定义一个主页,然后通过"http://localhost:8000/myapp/homepage"来访问,首先我们在myproject/myapp//view.py中定义一个叫homePage的函数(名字随意,不一定叫这名字):
然后在myproject/myproject/urls.py的urlpatterns列表中添加一个url配置:
然后运行项目,就可以用浏览器通过http://localhost:8000/myapp/homepage来访问。
但假如一个project中有多个app,用以上的方式来管理url可能会造成比较混乱的局面,为了解决这个问题,我们可以用include的方法来配置url,
首先我们在自己的app中建立一个urls.py,即myproject/myapp/目录下建立urls.py,然后在其中输入如下内容:
然后在项目的urls中包含刚刚app中添加的url配置,我们要做的是在myproject/myproject/urls.py输入如下内容:
2.编辑 mysite/settings.py 文件前,先设置 TIME_ZONE 为你自己时区。
此外,关注一下文件头部的 INSTALLED_APPS 设置项。这里包括了会在你项目中启用的所有Django 应用。应用能在多个项目中使用,你也可以打包并且发布应用,让别人使用它们。
通常, INSTALLED_APPS 默认包括了以下Django 的自带应用:
- django.contrib.admin -- 管理员站点,你很快就会使用它。
- django.contrib.auth -- 认证授权系统。
- django.contrib.contenttypes -- 内容类型框架。
- django.contrib.sessions -- 会话框架。
- django.contrib.messages -- 消息框架。
- django.contrib.staticfiles -- 管理静态文件的框架。
这些应用被默认启用是为了给常规项目提供方便。
python manage.py migrate
这个 migrate 命令检查 INSTALLED_APPS 设置,为其中的每个应用创建需要的数据表,至于具体会创建什么,这取决于你的 mysite/settings.py 设置文件和每个应用的数据库迁移文件migrate 命令只会为在 INSTALLED_APPS 里声明了的应用进行数据库迁移。
如果你不需要某个或某些应用,你可以在运行 migrate 前毫无顾虑地从 INSTALLED_APPS 里注释或者删除掉它们。
mysite/settings.py
INSTALLED_APPS =[
'polls.apps.PollsConfig',//自己添加的应用要添加到setting文件中所有应用都在.apps中
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
你模型的迁移数据,它被储存在 polls/migrations/0001_initial.py 里。
迁移是非常强大的功能,它能让你在开发过程中持续的改变数据库结构而不需要重新删除和创建表- 它专注于使数据库平滑升级而不会丢失数据。我们会在后面的教程中更加深入的学习这部分内容,现在,你只需要记住,改变模型需要这三步:
- 编辑 models.py 文件,改变模型。
- 运行 python manage.py makemigrations 为模型的改变生成迁移文件。
- 运行 python manage.py migrate 来应用数据库迁移。
3.创建一个管理员账号
$ python manage.py createsuperuser
启动开发服务器
$ python manage.py runserver
进入管理站点页面¶
现在,试着使用你在上一步中创建的超级用户来登录。然后你将会看到Django 管理页面的索引页:
向管理页面中加入投票(某某)应用¶
但是我们的投票应用在哪呢?它没在索引页面里显示。
只需要做一件事:我们得告诉管理页面,问题 Question 对象需要被管理。打开 polls/admin.py 文件,把它编辑成下面这样:
from django.contrib import admin
from .models import Question
admin.site.register(Question)
4.polls/urls.py
fromdjango.urlsimportpath
from.importviews
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'),
]
5.模板
模板命名空间
虽然我们现在可以将模板文件直接放在 polls/templates 文件夹中(而不是再建立一个 polls 子文件夹),但是这样做不太好。Django 将会选择第一个匹配的模板文件,如果你有一个模板文件正好和另一个应用中的某个模板文件重名,Django 没有办法 区分 它们。我们需要帮助Django 选择正确的模板,最简单的方法就是把他们放入各自的 命名空间 中,也就是把这些模板放入一个和 自身 应用重名的子文件夹里。
「载入模板,填充上下文,再返回由它生成的 HttpResponse 对象」是一个非常常用的操作流程。于是Django 提供了一个快捷函数,我们用它来重写 index() 视图:
polls/views.py
fromdjango.shortcutsimportrender
from.modelsimportQuestion
defindex(request):
latest_question_list =Question.objects.order_by('-pub_date')[:5]
context ={'latest_question_list': latest_question_list}
returnrender(request, 'polls/index.html', context)
抛出404 错误¶
现在,我们来处理投票详情视图——它会显示指定投票的问题标题。下面是这个视图的代码:
polls/views.py
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})
一个快捷函数: get_object_or_404()¶
尝试用 get() 函数获取一个对象,如果不存在就抛出 Http404 错误也是一个普遍的流程。Django 也提供了一个快捷函数,下面是修改后的详情 detail() 视图代码:
polls/views.py
fromdjango.shortcutsimportget_object_or_404, render
from.modelsimportQuestion
defdetail(request, question_id):
question =get_object_or_404(Question, pk=question_id)
returnrender(request, 'polls/detail.html', {'question': question})
去除模板中的硬编码URL
<li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
使用 {% url %} 标签代替硬编码
这个标签的工作方式是在 polls.urls 模块的URL 定义中寻具有指定名字的条目。你可以回忆一下,具有名字'detail' 的URL 是在如下语句中定义的:
# the 'name' value as called by the {% url %} template tag
path('<int:question_id>/', views.detail, name='detail'),
如果你想改变投票详情视图的URL,比如想改成 polls/specifics/12/ ,你不用在模板里修改任何东西(包括其它模板),只要在 polls/urls.py 里稍微修改一下就行:
# added the word 'specifics'
path('specifics/<int:question_id>/', views.detail, name='detail'),
为URL 名称添加命名空间
polls/urls.py
fromdjango.urlsimportpath
from.importviews
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><ahref="{%url'polls:detail'question.id%}">{{question.question_text}}</a></li>
6.表单
- 由于我们创建一个POST 表单(它具有修改数据的作用),所以我们需要小心跨站点请求伪造。Django 已经拥有一个用来防御它的非常容易使用的系统。简而言之,所有针对内部URL 的POST 表单都应该使用 {% csrf_token %} 模板标签。
- 每个单选按钮的 name 是 "choice" 。这意味着,当有人选择一个单选按钮并提交表单提交时,它将发送一个POST 数据 choice=# ,其中# 为选择的Choice 的ID。这是HTML 表单的基本概念。
表单的 action 为 {% url 'polls:vote' question.id %} ,并设置 method="post" 。使用 method="post"无论何时,当你需要创建一个改变服务器端数据的表单时,请使用 ``method="post" 。
return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))
在增加Choice 的得票数之后,代码返回一个 HttpResponseRedirect 而不是常用的 HttpResponse 、 HttpResponseRedirect 只接收一个参数:用户将要被重定向的URL(请继续看下去,我们将会解释如何构造这个例子中的URL)。
在这个例子中,我们在 HttpResponseRedirect 的构造函数中使用 reverse() 函数。这个函数避免了我们在视图函数中硬编码URL。它需要我们给出我们想要跳转的视图的名字和该视图所对应的URL 模式中需要给该视图提供的参数。在本例中,使用在 教程第3 部分 中设定的URLconf, reverse() 调用将返回一个这样的字符串:
'/polls/3/results/'
使用通用视图
根据URL 中的参数从数据库中获取数据、载入模板文件然后返回渲染后的模板
改良URLconf
polls/urls.py
fromdjango.urlsimportpath
from.importviews
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'),
]
注意,第二个和第三个匹配准则中,路径字符串中匹配模式的名称已经由 <question_id> 改为 <pk>。
改良视图
from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.urls import reverse
from django.views import generic
from .models import Choice, Question
class IndexView(generic.ListView):
template_name = 'polls/index.html'
context_object_name = 'latest_question_list'
def get_queryset(self):
"""Return the last five published questions."""
return Question.objects.order_by('-pub_date')[:5]
使用基于类的视图¶
从本质上讲,基于类的视图允许您使用不同的类实例方法响应不同的HTTP请求方法,而不是在单个视图函数中使用条件分支代码。
那么在GET视图函数中处理HTTP的代码看起来像这样:
fromdjango.httpimportHttpResponse
defmy_view(request):
ifrequest.method =='GET':
# <view logic>
returnHttpResponse('result')
在基于类的视图中,这将变为:
fromdjango.httpimportHttpResponse
fromdjango.viewsimportView
classMyView(View):
defget(self, request):
# <view logic>
returnHttpResponse('result')
因为Django的URL解析器期望将请求和关联的参数发送到可调用的函数而不是类,所以基于类的视图具有 as_view()类方法,该类方法返回当请求到达匹配关联模式的URL时可以调用的函数。该函数创建类的实例并调用其dispatch()方法。dispatch查看请求以确定它是否为GET,POST等等,并将请求中继到匹配方法(如果已定义),或者HttpResponseNotAllowed如果不是则引发 :
# urls.py
from django.urls import path
from myapp.views import MyView
urlpatterns = [
path('about/', MyView.as_view()),
]
值得注意的是,您的方法返回的内容与从基于函数的视图返回的内容相同,即某种形式的 HttpResponse。这意味着http快捷方式或 TemplateResponse对象在基于类的视图中有效。
虽然最小的基于类的视图不需要任何类属性来执行其工作,但类属性在许多基于类的设计中很有用,并且有两种方法来配置或设置类属性。
总结:
1.reverse() :在这个例子中,我们在 HttpResponseRedirect 的构造函数中使用 reverse() 函数。这个函数避免了我们在视图函数中硬编码URL。
2.render() (:「载入模板,填充上下文,再返回由它生成的 HttpResponse 对象」是一个非常常用的操作流程。
3.as_view():基于类的视图返回
4.generic :通用视图
Django 的源文件在哪里?
如果你不知道Django 源码在你系统的哪个位置,运行以下命令:
$ python -c "import django; print(django.__path__)"
所有的Django 默认后台模板均可被复写。若要复写模板,像你修改 base_site.html 一样修改其它文件——先将其从默认目录中拷贝到你的自定义目录,再做修改。
models
1.字段选项
null如果True,Django将NULL在数据库中存储空值。默认是False。
blank如果True,该字段允许为空。默认是False。
请注意,这不同于null。 null纯粹与数据库相关,而 blank与验证相关。如果字段有 blank=True,则表单验证将允许输入空值。如果字段有blank=False,则需要该字段
多对一关系¶
要定义多对一关系,请使用django.db.models.ForeignKey。您可以像使用任何其他Field类型一样使用它:将其包含为模型的类属性
class Car(models.Model):
manufacturer = models.ForeignKey(Manufacturer, on_delete=models.CASCADE) //manufacturer为car的外键,一个car一个manufacturer,一个manufacturer多个car
多对多关系
class Topping(models.Model):
pass
class Pizza(models.Model):
toppings = models.ManyToManyField(Topping)
一般情况,普通的多对多已经够用,无需自己创建第三张关系表。但是某些情况可能更复杂一点,比如如果你想保存额外字段信息,例如:某个人加入某个分组的时间呢?想保存进组的原因呢?-----中间表。与普通的多对多不一样,使用自定义中间表的多对多不能使用add(), create(),remove(),和set()方法来创建、删除关系为什么?因为上面的方法无法提供加入时间、邀请原因等中间模型需要的字段内容。唯一的办法只能是通过创建中间模型的实例来创建这种类型的多对多关联。但是,clear()方法是有效的,它能清空所有的多对多关系。
book = person.book_set.all()//person book 一对多
django 默认每个主表的对象都有一个是外键的属性,可以通过它来查询到所有属于主表的子表的信息。
这个属性的名称默认是以子表的名称小写加上_set()来表示,默认返回的是一个querydict对象,你可以继续的根据情况来查询等操作。
在实际项目中,我们使用最多的还是related_name
如果你觉得上面的定义比较麻烦的话,你也可以在定义主表的外键的时候,给这个外键定义好一个名称。要用related_name比如在Book表中: //book表中定义ForeignKey为主表名
person = models.ForeignKey(Person, related_name='person_books')
那么实现上面的需求,可以使用person.book_set.all()也可以使用person.person_books.all()
在使用中间模型定义从模型到自身的多对多关系时,必须使用 symmetrical=False
模型方法和属性
Python“魔术方法”,返回任何对象的字符串表示形式
这告诉Django如何计算对象的URL。Django在其管理界面中使用它,并且只要它需要找出对象的URL。具有唯一标识它的URL的任何对象都应定义此方法。
模型最重要的属性是 Manager。默认名称为 objects。管理员只能通过模型类访问,而不能通过模型实例访问。
Django中有三种可能的继承方式。
- 通常,您只想使用父类来保存您不希望为每个子模型键入的信息。这个类不会被孤立使用,所以抽象基类就是你所追求的。它不生成数据库表或具有管理器,并且无法直接实例化或保存。
- 如果你是现有模型的子类(可能是完全来自另一个应用程序的东西),并希望每个模型都有自己的数据库表,那么 多表继承是最佳选择。
- 最后,如果您只想修改模型的Python级行为,而不以任何方式更改模型字段,则可以使用 代理模型
1. 创建和保存对象,请使用该 create()方法
b = Blog(name='Beatles Blog', tagline='All the latest Beatles news.')
b.save()
2.更新ManyToManyField工作的方式略有不同
entry.authors.add(john, paul, george, ringo)//add方法可一次性添加多个
3.filter(**kwargs)返回QuerySet包含与给定查找参数匹配的新对象。
exclude(**kwargs)返回QuerySet包含与给定查找参数不匹配的新对象
Entry.objects.filter( headline__startswith='What').exclude(
pub_date__gte=datetime.date.today()).filter(
pub_date__gte=datetime.date(2005, 1, 30) )
manager类
4.filter()QuerySet即使只有一个对象与查询匹配,它总会给你一个 - 在这种情况下,它将 QuerySet包含一个元素。如果您知道只有一个对象与您的查询匹配,则可以使用直接返回对象的 get()方法 Manager
基本查找关键字参数采用表单field__lookuptype=value。(这是一个双重下划线)
Entry.objects.filter(pub_date__lte='2006-01-01')
将(粗略地)翻译成以下SQL:
SELECT * FROM blog_entry WHERE pub_date <= '2006-01-01';
但是有一个例外,如果ForeignKey你可以指定后缀的字段名称_id。在这种情况下,value参数应包含外部模型主键的原始值。例如:
>>> Entry.objects.filter(blog_id=4)
果您的关键字参数不包含双下划线- 则假定查找类型为 exact。
例如,以下两个语句是等效的:
>>> Blog.objects.get(id__exact=14) # Explicit form
>>> Blog.objects.get(id=14)
iexact不区分大小写的匹配项
还有一个不区分大小写的版本icontains
跨越关系的查找:双下划线
Blog.objects.filter(entry__headline__contains='Lennon')
跨越多值关系
Blog.objects.filter(entry__headline__contains='Lennon', entry__pub_date__year=2008)
Blog.objects.filter(entry__headline__contains='Lennon').filter(entry__pub_date__year=2008)
过滤器可以引用模型上的字段
from django.db.models import F
请注意,这delete()是唯一 QuerySet未在Manager自身上公开的方法 。这是一种安全机制,可以防止您意外请求Entry.objects.delete()和删除所有条目。如果您确实要删除所有对象,则必须显式请求完整的查询集:
Entry.objects.all().delete()
使用自定义反向管理器¶
默认情况下,RelatedManager用于反向关系的是 该模型的默认管理器的子类。如果要为给定查询指定其他管理器,可以使用以下语法:
e = Entry.objects.get(id=3)
e.authors.all() # Returns all Author objects for this Entry.
e.authors.count()
e.authors.filter(name__contains='John')
a = Author.objects.get(id=5)
a.entry_set.all()# Returns all Entry objects for this Author.//而“反向”模型使用原始模型的小写模型名称,加上'_set'(就像反向一对多关系一样)
视图
1.使用register_converter()以下命令在URLconf中注册自定义转换器类 :
from django.urls import path, register_converter
from . import converters, views
register_converter(converters.FourDigitYearConverter, 'yyyy')
//class FourDigitYearConverter
urlpatterns = [
path('articles/2003/', views.special_case_2003),
path('articles/<yyyy:year>/', views.year_archive),
]
2.如果路径和转换器语法不足以定义URL模式,则还可以使用正则表达式。使用 re_path()而不是path()。
3.urlpatterns=[
path('blog/<int:year>/', views.year_archive, {'foo': 'bar'}),
]
在这个例子中,对于请求/blog/2005/,Django将调用 。views.year_archive(request,
year=2005,foo='bar')
联合框架
fromdjango.contrib.syndication.viewsimportFeed
4.Django提供了不同的层级的url逆向处理工具:
1.在模板templates中,使用url标记,如:{% url %}
2.在Python代码中,使用django.core.urlresolvers.reverse()方法
3.在更高一层级的处理url中,用get_absolute_url()方法
需求点击博客的继续阅读加载全文
5.自定义错误视图
只需在URLconf中指定处理程序,如下所示(在其他地方设置它们将无效
该page_not_found()视图由重写 handler404:
handler404 = 'mysite.views.my_custom_page_not_found_view'
装饰器django.views.decorators.http可用于根据请求方法限制对视图的访问。django.http.HttpResponseNotAllowed如果不满足条件,这些装饰器将返回a
例如,考虑应用程序跟踪音乐家所属的音乐组的情况。一个人与他们所属的团体之间存在多对多的关系,因此您可以使用a ManyToManyField来表示这种关系。但是,您可能希望收集的成员资格有很多详细信息,例如此人加入该组的日期。
对于这些情况,Django允许您指定将用于管理多对多关系的模型。然后,您可以在中间模型上添加额外的字段。中间模型与ManyToManyField使用 through参数指向将充当中介的模型相关联 。对于我们的音乐家示例,代码看起来像这样:
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=128)
def __str__(self):
return self.name
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
def __str__(self):
return self.name
class Membership(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
简单文件上传
请注意只有在请求是通过 POST 提交且提交的 <form> 表单有 enctype="multipart/form-data" 属性的时候,request.FILES 才会包含文件数据,否则的话, request.FILES 是空的。
forms.py
fromdjangoimportforms
classUploadFileForm(forms.Form):
title =forms.CharField(max_length=50)
file =forms.FileField()
views.py
fromdjango.httpimportHttpResponseRedirect
fromdjango.shortcutsimportrender
from.formsimportUploadFileForm
# Imaginary function to handle an uploaded file.
fromsomewhereimporthandle_uploaded_file
defupload_file(request):
ifrequest.method =='POST':
form =UploadFileForm(request.POST, request.FILES)#//注意我们必须向表单的构造器中传递request.FILES。这是文件数据绑定到表单的方法。
ifform.is_valid():#有效的
handle_uploaded_file(request.FILES['file'])#读取处理文件函数
returnHttpResponseRedirect('/success/url/')
else:
form =UploadFileForm()
returnrender(request,'upload.html', {'form': form})
FILES是个字典,它包含每个FileField的键(或者 ImageField,FileField的子类)。这样的话就可以用request.FILES['file']来存放表单中的这些数据了。
当用户上传一个文件的时候,Django会把文件数据传递给上传处理器– 一个小型的类,会在文件数据上传时处理它。上传处理器在FILE_UPLOAD_HANDLERS
中定义,默认为:
("
django.core.files.uploadhandler.MemoryFileUploadHandler",
"
django.core.files.uploadhandler.TemporaryFileUploadHandler",)
MemoryFileUploadHandler
和TemporaryFileUploadHandler
一起提供了Django的默认文件上传行为,将小文件读取到内存中,大文件放置在磁盘中。
redirect()
django 中的中间件(middleware),在django中,中间件其实就是一个类,在请求到来和结束后,django会根据自己的规则在合适的时机执行中间件中相应的方法。
中间件中一共有四个方法:
process_request process_view process_exception process_response
在django中叫中间件,在其他web框架中,有的叫管道,httphandle
我们可以自己写一个类,但是必须继承MiddlewareMixin
所以需要导入:from django.utils.deprecation import MiddlewareMixin
加油吧,程序员!