Python-Django-入门

一、Django介绍

1 、什么是框架

只要你知道一点构建动态网站是怎么回事的话,那么就一定能体会到不断重复地发明某些标准特性是多么痛苦的一

件事情。你得创建数据库结构,把数据导人导出数据库,处理URL,验证用户输人,提供编辑工具,还得关心安全性和

可用性。

终于,你意识到每次都重新实现这些特性实在是太浪费生命了。所以,你决定要重新开发一套自己的库来提供这

些功能。或者说,从你最新的“创造"中把这些库提取出来。之后,如果要开始一个新项目的话,你第一件要做的事情就

是安装你的库。这能大大节约你的工作时间。

但是,事情可没那么简单。如果客户需要的特性不在你的库里怎么办,没关系,加进来就好了。而每个客户都需

要不同的东西,结果就变成你在每个服务器上安装的库都有不同的版本。这绝对是没有办法维护的。

有了教训以后,你回过头来把基础库和最好的add-on从各个项目里拿出来重新组合在一起。对绝大多数项目来说

你不再需要直接调整库代码,只需要改动一下配置文件就可以了,虽然你的代码库越来越大、越来越复杂,但是它也变

得非常强大。这个代码库就是所谓的Web框架。

Django是一个高级PythonWeb框架,劳伦斯出版集团为了开发以新闻内容为主的网站,而开发出来了这个框架,

Django遵守BSD版权,初次发布于 2005 年 7 月, 并于 2008 年 9 月发布了第一个正式版本 1. 0 。

2 、Django特点

1 、开发速度快,Django旨在帮助开发人员尽可能快地从概念到应用程序。

2 、功能齐全,Django包含了许多可用于处理常见Web开发任务的额外功能,用户身份验证,内容管理,站点地图,

RSS源以及许多其他任务。

3 、安全性高,Django非常重视安全性,并帮助开发人员避免许多常见的安全错误,例如SQL注入、跨站点脚本、跨

站点请求伪造。它的用户身份验证系统提供了一种安全的方法来管理用户账户和密码。

4 、Django采用了MVC的软件设计模式,即模型M,视图V和控制器C,并且取了个名字叫MVT。

3 、MVC模型的介绍

MVC模式 (Model-View-Controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型

(Model)、视图(View)和控制器(Controller)。

MVC模式最早由TrygveReenskaug在 1978 年提出[ 1 ],是施乐帕罗奥多研究中心(XeroxPARC)在 20 世纪 80 年代为程

序语言Smalltalk发明的一种软件设计模式,是为了将传统的输入(input)、处理(processing)、输出

(output)任务运用到图形化用户交互模型中而设计的。随着标准输入输入设备的出现,开发人员只需要将精力集中

在业务逻辑的分析与实现上。后来JAVAEE采用MVC的设计模式,这种分工开发的方式受到了广大开发者的认

可,后来包括java,php,python等语言都有MVC设计模式的框架。

MVC框架的核心思想是解耦,让不同的代码块之间降低耦合,增强代码的可扩展性和可移植性。

MVC模式把用户界面交互分拆到不同的三种角色中,使应用程序被分成三个核心部件: Model(模型) 、

View(视图) 、 Control(控制器)

Model: 主要封装对数据库层的访问,内嵌ORM框架,实现面向对象的编程来操作数据库。

View: 用于封装结果,内嵌了模板引擎,实现动态展示数据

Controller: 用于接收用户请求,处理业务逻辑,与Model和View交互,返回结果

在MVC模型中,如果不需要查询数据库,那么Controller将不会与Model交互,直接与View交互,返回html页面。

4 、MVT模型介绍

M(Model) ,与MVC中的M功能相同,负责数据处理,内嵌了ORM框架

V(View) ,与MVC中的C功能相同,接收请求,业务处理,返回响应

T(Template) ,与MVC中的V功能相同,负责封装构造要返回的html,内嵌了模板引擎

二、虚拟环境搭建

在开发中安装模块的方法:

pipinstall模块名称

之前我们安装模块都是直接在物理环境下安装,这种安装方法,后面一次安装的会覆盖掉前面一次安装的。那如果

一台机器上面开发多个项目使用到不同版本的模块呢?怎么样做才能不受版本影响!那么需要用到虚拟环境,每个

虚拟环境互相隔离,在一个虚拟环境中安装卸载模块其他不受影响!

1 .python虚拟环境安装

Windows下创建虚拟环境

选择一个用来存放虚拟环境的文件,如E:/python 3

cdE:python 3 #进入该文件

virtualenvenvname #创建一个名字为envname的虚拟环境

dir #查看当前目录可以知道一个envname的文件已经被创建

virtualenv-ppython 2 envname #如果安装了多个python版本,如py 2 和py 3 ,需要指定使用哪个创建虚拟环境

注意:如果不识别virtualenv命令,可能是python安装路径没添加到系统环境变量或没安装virtualenv或没有

重新打开一个cmd窗口;

启动虚拟环境

#进入虚拟环境文件
cdenvname

#进入相关的启动文件夹

cdScripts

activate #启动虚拟环境

deactivate#退出虚拟环境

2 .虚拟环境中安装指定版本号的模块

1 .在虚拟环境中安装模块,直接使用pip安装就可以。

2 .查看虚拟环境下安装了那些包

pipinstallvirtualenv
pipinstallvirtualenvwrapper-win #Windows使用该命令
pipinstalldjango== 1. 8. 2
pipfreezelist

3 .项目开发完成,需要上线时,将开发环境使用的包,导出安装到生产环境下。

4 .将开发环境导出的包的文件requirements.txt,安装到生产环境

三、创建项目

1 、创建一个博客项目

django的项目结构是由多个应用组成,每一个应用实现不同的功能。

安装好django之后,django提供了一个管理工具django-admin.py,可以使用django-admin.py来创建一个项目。

下面我们来创建一个博客项目,项目名称叫blog。

环境说明:

django 版本 1. 8. 2 这个版本比较稳定,资料比较多,所以本课程使用 1. 8. 2 版本

python 3. 5. 2

unbuntu 16. 04

1 、在家目录创建一个文件夹保存项目

2 、进入刚才创建的虚拟环境,创建名称为blog博客项目

workonpy 3
django-adminstartprojectblog

执行完命令后在myblog目录下生成一个名问blog项目文件夹。

执行这条命令之后自动创建了一个名为blog项目,并且django帮我们生成了 5 个文件。 简单介绍下文件:

manage.py:一个命令行工具,可以使你用多种方式对Django项目进行交互blog/

mkdirmyblog
cdmyblog
pipinstall-rrequirements.txt
pipfreezelist>requirements.txt

init.py:一个空文件,告诉Python该目录是一个Python包。

blog/setting.py:项目的配置文件

bolg/urls.py:URL分发器(路由配置文件)

blog/wsgi.py:项目与WSGI兼容的Web服务器入口

3 、运行项目

看到下面这行提示说明服务已经运行起来

在浏览器中访问:http: 127. 0. 0. 1 : 8000 看到下面这个界面说明项目已经正确创建

pythonmanage.pyrunserver

默认情况下,runserver命令在内部IP的 8000 端口启动开发服务器。如果你需改变服务器的端口,把要使用的端口

作为一个命令行参数传递给它。例如,这个命令在 8080 端口启动服务器:

如果你需改变服务器的IP地址,把IP地址和端口号放到一起。 因此若要监听所有的外网IP,请使用:

2 、应用创建

前面提到django项目中一个应用实现一个功能,那刚才创建好了项目,现在我们来创建一个应用。 1 、创建一个

名称为personal_blog的应用

创建好应用后的整个项目的目录结构:

pythonmanage.pyrunserver 0. 0. 0. 0 : 8080
django-adminstartapppersonal_blog
或者
pythonmanage.pystartapppersonal_blog
pythonmanage.pyrunserver 8080

创建好应用之后的文件介绍:

db.sqlite 3 文档型的轻量级数据库,django默认使用sqlite数据库

personal_blog 应用目录名

admin.py web后台管理,用于注册模型类

migrations 保存迁移时生成的文件

models.py 编写模型类,就是MVT模型中的M

tests.py 用于开发测试类

views.py 编写视图函数,MVT模型中的V

3 、安装应用

Django应用是可以“热插拔”的,即可以在多个项目中使用同一个应用,也可以分发这些应用,因为它们不需要

与某个特定的Django安装绑定。

编辑blog/settings.py文件,并修改INSTALLED_APPS设置以包含应用的名称’personal_blog’。如下

代码:

前面的这些应用是django自带的应用,如果我们需要新加应用,只需要往后面加。

INSTALLED_APPS=(
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'personal_blog',#我们自己写的应用
)

项目与应用的关系:

应用是一个Web应用程序,它完成具体的事项 —— 比如一个博客系统,一个简单的投票应用。

项目是一个特定网站中相关配置和应用的集合,一个项目可以包含多个应用,一个应用可以运用到多个项目中去。

四、Admin站点管理

1 、站点介绍

在shell下面去编辑博客非常麻烦,前面提到过django自带强大的功能,其中就有一个内容管理。 下面我们来使用

django自带的Admin站点管理去编辑我们的blog内容。

Django是在新闻编辑室这样的环境中被开发出来的,这样的环境中“内容发布者”站点和“公共”站点有着非常明

显的界限,网站管理者使用管理界面来添加新闻故事、新闻事件、体育比赛分数等。这些内容会被展示在公共

站点上。Django为网站管理者创建统一的管理界面用以编辑这些内容。

Django会根据模型类文件完全自动地生成管理界面。

管理界面不是让访问网站的人使用的,它服务于网站管理者,用于网站的管理员。

2 、创建管理员账号

启动开服服务器:

在浏览器中输入http:// 127. 0. 0. 1 : 8000 /admin进入后台管理,但是需要管理员账号密码。默认是没有的,需要开

发者创建。

创建后台管理员账号,执行这创建管理员账号命令

执行上面命令后输入按提示输入

pythonmanage.pycreatesuperuser
pythonmanage.pyrunserver
Username(leaveblanktouse'python'):admin #用户名
Emailaddress: 123 @ 163 .com #邮箱
Password:*****
你需要设置的密码
Password(again):****
# 密码,注意:在终端上输入密码是看不见的,这里用*号代表密码。实际上是输入
#重复输入密码
Superusercreatedsuccessfully. #提示successfully创建成功

用刚才创建的账号密码 登录

3 、管理界面本地化

首次登录之后是英文界面,后台管理是给管理员使用的,英文界面阅读起来就比较困难了,这里可以将后台管理本地

化。本地化是将显示的语言、时间等使用本地的习惯,这里的本地化就是进行中国化,中国大陆地区使用简体中文,

时区使用亚洲/上海时区,注意这里不使用北京时区表示。

管理界面本地化修改setting.py文件,找到下面两行配置修改

LANGUAGE_CODE语言’zh_hans’表示中文TIME_ZONE时区’Asia/Shanghai’亚洲/上海

修改好配置之后重启服务:刷新后台管理界面就使用中文显示了

LANGUAGE_CODE='zh-hans'#'en-us'
TIME_ZONE='Asia/Shanghai'#'UTC'

但我们的应用在哪儿? 它没有显示在管理站点的首页面上。

4 、注册模型类

如果想要在后台中能编辑的模型类,我们只需要在应用目录下的admin.py中注册模型类:下

面这段代码加入到personal_blog/admin.py中,向admin中注册博客的模型类。

重新启动服务刷新后台管理界面,后台管理界面就可以看到所有的模型类了:

点击类名称“Posts”可以进入列表页,默认只有一列,显示的是模型类中 str 方法返回的值

fromdjango.contribimportadmin
frompersonal_blog.modelsimport*
#Registeryourmodelshere.
admin.site.register(Post)
admin.site.register(Category)
admin.site.register(Tag)
admin.site.register(Comment)

给模型类都添加上str方法

添加str方法后,Post列表页显示str返回的title值

classCategory(models.Model):
#分类名
category_name=models.CharField(max_length= 20 )
def str (self):
returnself.category_name
classTag(models.Model):
#标签名
tag_name=models.CharField(max_length= 20 )
def str (self):return
self.tag_name
classPost(models.Model):
.....#省略代码
defstr (self):return
self.title
classComment(models.Model):
.....#省略代码
defstr(self):return
self.name

进入post列表页可进行操作。

在列表页中点击“增加”可以进入增加页,Django会根据模型类的不同,生成不同的表单控件,按提示填写表单内容后

点击"保存",完成数据创建,创建成功后返回列表页

关系字段添加方法

在列表页勾选想要删除的复选框,可以删除多项

点击执行之后会提示,删除内容,询问是否删除,包括关系数据都会一起被删除。点击确定数据将会被删除,返

回则不做删除操作。

五、自定义管理表单

1 、列表页字段展示

只需在admin.py中使用admin.site.register(模型类)注册模型类,Django就能构造一个默认的表单。但是,默认管理

表单不够美观,展示的数据量不够,我们需要要自定义管理界面中表单的外观和功能。

在列表页只列出了str方法的返回值,对象的其它属性并没有列出来,查看非常不方便

Django提供了自定义管理页面的功能,比如列表页要显示那些字段

打开personal_blog/admin.py文件,自定义类,继承自admin.ModelAdmin类属性

list_display表示要显示哪些属性

自定义Post模型类的管理表单

fromdjango.contribimportadmin
frompersonal_blog.modelsimport*
#Registeryourmodelshere.
#admin.site.register(Post)#将原来注册注释,或删除掉
admin.site.register(Category)
admin.site.register(Tag)
admin.site.register(Comment)
#第一种方法,采用装饰器的方式注册
@admin.register(Post)
classPostAdmin(admin.ModelAdmin):
list_display=('title','created_time','modified_time','category','author')#content内容会
很长,不放在列表页展示
#第二中注册方式
#classPostAdmin(admin.ModelAdmin):
#
#
list_display=('title','created_time','modified_time','category','author')
#admin.site.register(Post,PostAdmin)

在注册自定义的list_display时,如果有同学将tags添加到list_display中会发现服务器报错了,错误是list_display中的值

不能是ManyToManyField类型

django官方解释:ManyToManyField字段不受支持,因为这将需要为表中的每一行执行单独的SQL语句。如果你想

这样做,给你的模型一个自定义的方法,并将该方法的名称添加到list_display。

如果我们想要在列表页展示出多对多关系的字段那么需要到模型类中添加一个方法:

classPost(models.Model):
title=models.CharField(max_length= 50 )#文章标题
content=models.TextField()#文章内容created_time
=models.DateTimeField()#创建时间modified_time=
models.DateTimeField()#发布时间
category=models.ForeignKey(Category)#分类,使用外键连接一对多关系使用ForeignKey
tags=models.ManyToManyField(Tag,blank=True)#标签,多对多关系使用ManyToManyField
author=models.ForeignKey(User)#作者,一对多关系
# 添加tags_name方法。在list_display中添加这个方法名
deftags_name(self):
return",".join([str(t)fortinself.tags.all()]) #这条语句就是将文章的标签取出拼接成字
符串返回
def str (self):
returnself.title

写好后将tags_name方法名加到list_display中,这样就不会报错,文章的所有标签页能显示出来。

2 、编辑页面排版修改

细心的同学应该注意到了,在增加修改页面的排版问题,django默认是按照模型类编写的循序从上到下展示字段的。

但是我们编写模型类字段很多时候并不会去关心字段的顺序。所以在后台编辑的时候不能将相近的字段在一起编辑,

给后台编辑带来不便。django在注册模型类的时候提供了fieldsets属性来控制编辑页面的排版。

修改admin.py文件,PostAdmin类:

fields 属性控制编辑页面展示内容

增加修改页只展示fields属性包含的内容。如果有些字段是默认不需要修改的可以是用fields控制。

@admin.register(Post)
classPostAdmin(admin.ModelAdmin):
list_display=('title','created_time','modified_time','category','author','tags_name')
fields=('title','created_time')#fields属性控制编辑页面展示那些字段

显然只用fields并不能提供给我们一个直观的排序方式。要创造一个直观的排序方式就需要fieldsets配合fields使用。

修改admin.py文件中的PostAdmin类:

fieldsets中每个元组的第一个元素是字段集的标题,第二个元素是一个字典fields属性。设置fieldsets属性后,后

台编辑页面字段分类显示!这样对网站编辑比较友好。

@admin.register(Post)
classPostAdmin(admin.ModelAdmin):
list_display=('title','created_time','modified_time','category','author','tags_name')
fieldsets=(
('标题/正文',{'fields':['title','content']}),
('创建/修改时间',{'fields':['created_time','modified_time']}),
('分类/标签',{'fields':['category','tags']}),
('作者',{'fields':['author']})
)

隐藏字段集,在字段很多的情况下,编辑页会很长,如果将部分字段集隐藏起来,需要修改的时候再显示,这样编

辑起来就方便很多修改admin.py文件的PostAdmin类:字段集中添加’classes’:[‘collapse’]

字段集中添加了’classes’: [‘collapse’]属性的字段集默认将被隐藏起来,需要点显示才能显示出来编辑。

@admin.register(Post)
classPostAdmin(admin.ModelAdmin):
list_display=('title','created_time','modified_time','category','author','tags_name')
fieldsets=(
('标题/正文',{'fields':['title','content']}),
('创建/修改时间',{'fields':['created_time','modified_time'],'classes': ['collapse']}),
('分类/标签',{'fields':['category','tags'],'classes': ['collapse']}),
('作者',{'fields':['author']})
)

3 、添加关联对象

Category跟Post是一对多的关系,编辑Post每个与其它对象拥有ForeignKey关系的对象都有一个这种链接。当你点击

“+”,你将看到一个带有“添加category”表单的弹出窗口。如果你在这个窗口中添加了一个category并点

击“Save”,Django会将保存这个category到数据库中,然后动态地将这个对象添加为你正编辑的category的选择项。

django认为这是一个很麻烦的事情,高效的编辑方式应该在创建category对象的时候顺便一起编辑Post。

inlines 指定关联的模型类 extra指定提供几个空白空间,不能被删除。

这告诉Django:Post对象在Category的管理界面中编辑。默认提供足够 3 个Post的空间。

#admin.site.register(Category)删除默认注册的Category,或者注释掉
classPostInline(admin.StackedInline):
model=Post
extra= 3
@admin.register(Category)
classCategoryAdmin(admin.ModelAdmin):
list_display=('category_name',)
inlines=[ChoiceInline] #声明内嵌的模型类

这里有一个问题,关联表放进来后占用大量的屏幕空间,为了解决这个问题,Django提供了一种以表格的形式显示

内嵌的相关联对象的方法,只需改变一下PostInline的声明:

使用 TabularInline(不是StackedInline),这些相关联的对象显示成紧凑的、基于表格的形式:

声明为 TabularInline 后这里内嵌的Post就以表格的形式展示

classChoiceInline(admin.TabularInline):#这里继承admin中的TabularInline类,以表格的形式内嵌关联
表对象
model=Postextra
= 2
@admin.register(Category)
classCategoryAdmin(admin.ModelAdmin):
list_display=('category_name',)
inlines=[ChoiceInline]

4 、列表页表头修改

观察下表头,列名使用的是模型类中的字段名的大写,并且将下划线转成了空格。

如果对列名不满意可以在模型类中定义一个方法代替原来字段,方法返回原来字段的值。将TITLE修改成“标题”。

修改models.py文件Post类:

然后在到admin.py文件中修改PostAdmin类中的list_dispaly元素’title’修改成刚才在models中创建的方法名

5 、添加搜索功能

classPost(models.Model):
title=models.CharField(max_length= 50 )#文章标题
content=models.TextField()#文章内容created_time
=models.DateTimeField()#创建时间modified_time=
models.DateTimeField()#发布时间
category=models.ForeignKey(Category)#分类,使用外键连接一对多关系使用ForeignKey
tags=models.ManyToManyField(Tag,blank=True)#标签,多对多关系使用ManyToManyField
author=models.ForeignKey(User)#作者,一对多关系
deftags_name(self):
return",".join([str(t)fortinself.tags.all()])
deftitle_name(self):
returnself.title
title_name.short_description='标题'
defstr (self):return
self.title
@admin.register(Post)
classPostAdmin(admin.ModelAdmin):
list_display=('title_name','created_time','modified_time','category','author',
'tags_name')
...#省略其他代码

在admin.py中注册模型类中添加search_fields属性,可以是列表,也可以是元祖。里面的元素是支持搜索的字段名称。

增加标题,分类搜索:在admin.py中PostAdmin类中增加search_fields属性,将需要搜索的字段添加到列表中。

添加好search_fileds属性后,刷新列表页,会出现搜索框。这样就支持 title,category 值的搜索。

注意:如果搜索字段里有外键。要注明外键的那个字段,双下划线。否则就会报下面错误。

@admin.register(Post)
classPostAdmin(admin.ModelAdmin):
list_display=('title_name','created_time','modified_time','category','author',
'tags_name')
fieldsets=[
('标题/正文',{'fields':['title','content']}),
('创建/修改时间',{'fields':['created_time','modified_time'],'classes': ['collapse']}),
('分类/标签',{'fields':['category','tags'],'classes': ['collapse']}),
('作者',{'fields':['author']})
]
search_fields=['title','categorycategory_name']# 添加搜索字段

6 、过滤器

再次编辑你的admin.py文件来改进列表页面:使用list_filter来添加过滤器。将下面这行添加进PostAdmin:

这行代码添加一个“Filter”侧边栏,管理员可以通过title,category字段对列表内容进行显示过滤:

7 、修改表名

在后台管理页面中表名默认使用模型类名称的复数形式。通常情况下,我们都会将表名修改成比较直观的名称。

@admin.register(Post)
classPostAdmin(admin.ModelAdmin):
list_display=('title_name','created_time','modified_time','category','author',
'tags_name')
fieldsets=[
('标题/正文',{'fields':['title','content']}),
('创建/修改时间',{'fields':['created_time','modified_time'],'classes': ['collapse']}),
('分类/标签',{'fields':['category','tags'],'classes': ['collapse']}),
('作者',{'fields':['author']})
]
search_fields=['title','category']#添加搜索字段
list_filter=['title','category'] #过滤器

修改表名使用模型类的一个内置类Meta类。Django模型类的Meta是一个内部类,它用于定义一些Django模型类的行

为特性。

Meta选项:

db_table

ordering

verbose_name

verbose_name_plural

db_table是指定自定义数据库表明的。Django有一套默认的按照一定规则生成数据模型对应的数据库表明。
Options.db_table
定义该model在数据库中的表名称
db_table='Students'
如果你想使用自定义的表名,可以通过以下该属性
table_name='my_owner_table'
这个字段是告诉Django模型对象返回的记录结果集是按照哪个字段排序的。
这是一个字符串的元组或列表,没有一个字符串都是一个字段和用一个可选的表明降序的'-'构成。
当字段名前面没有'-'时,将默认使用升序排列。使用'?'将会随机排列
ordering=['created_time']#按创建升序排列
ordering=['-created_time']#按创建降序排列,-表示降序
ordering=['?created_time']#随机排序,?表示随机
ordering=['-created_time','author']#以created_time降序,在以author升序排列
给模型类起一个更可读的名字一般定义为中文,名字为复数形式,django自动在后面加一个s
verbose_name="文章"
指定模型类的名字,这个指定什么就是什么,不会再后面加个s,如果是起中文名,一般使用这个
verbose_name_plural="文章"

修改modles.py文件模型类,每个模型类创建一个内置Meta类修改模型类名称

returnself.tag_name
classMeta:
verbose_name_plural='标签'
classPost(models.Model):
title=models.CharField(max_length= 50 )#文章标题
content=models.TextField()#文章内容created_time
=models.DateTimeField()#创建时间modified_time=
models.DateTimeField()#发布时间
category=models.ForeignKey(Category)#分类,使用外键连接一对多关系使用ForeignKey
tags=models.ManyToManyField(Tag,blank=True)#标签,多对多关系使用ManyToManyField
author=models.ForeignKey(User)# 作者,一对多关系
classMeta:
verbose_name_plural='文章'
ordering=['-created_time']#以创建时间倒序显示结果。
deftags_name(self):
return",".join([str(t)fortinself.tags.all()])
deftitle_name(self):
returnself.title
title_name.short_description='标题'
def str (self):
returnself.title
def str (self): # unicode onPython 2
classCategory(models.Model):
#分类名
category_name=models.CharField(max_length= 20 )
def str (self):
returnself.category_name
classMeta:
verbose_name_plural='分类'
classTag(models.Model):
#标签名
tag_name=models.CharField(max_length= 20 )
classComment(models.Model):
name=models.CharField(max_length= 20 )#评论用户
content=models.TextField() #评论内容
time=models.DateTimeField()#发布评论时间
post=models.ForeignKey(Post)#评论文章,一对多关系
defstr(self):return
self.name
classMeta:
verbose_name_plural='评论'

8 、分页显示

django后台管理页面默认一页显示 100 条数据,在注册模型类时可以指定一页显示几条数据

修改admin.py文件PostAdmin类:添加list_per_page属性,属性值为一个数字,指定一页显示几条数据

9 、修改应用的名称

Dajngo在Admin后台默认显示的应用的名称为创建app时的名称。

我们如何修改这个app的名称达到定制的要求呢,其实Django已经在文档里进行了说明。

从Django 1. 7 以后不再使用app_label,修改app相关需要使用AppConfig。我们只需要在应用的init.py里面进行修

改:

classPostAdmin(admin.ModelAdmin):
list_display=('title_name','created_time','modified_time','category','author',
'tags_name')
fieldsets=[
('标题/正文',{'fields':['title','content']}),
('创建/修改时间',{'fields':['created_time','modified_time'],'classes': ['collapse']}),
('分类/标签',{'fields':['category','tags'],'classes': ['collapse']}),
('作者',{'fields':['author']})
]
search_fields=['title','categorycategory_name']# 添加搜索字段
list_filter=['title','category'] #
list_per_page= 10 #指定一页显示几条数据
#coding=utf- 8
fromdjango.appsimportAppConfig
importos
default_app_config='personal_blog.BlogConfig'
VERBOSE_APP_NAME='博客' #应用名称
defget_current_app_name(_file):
return os.path.split(os.path.dirname(_file))[- 1 ]
classBlogConfig(AppConfig):
name=get_current_app_name(file)
verbose_name=VERBOSE_APP_NAME

六、视图和URL

后台管理页面已经做的差不多了,那下面应该就是做 公共 站点,也就是给别人看的网页部分。

对于django的设计框架MVT,用户在URL中请求的是视图,视图接收请求后进行处理,并将处理的结果返回给

请求者

1 、原理

视图(view)是Django应用中的一“类”网页,它通常使用一个特定的函数提供服务,并且具有一个特定的模板。例如,

在博客应用中,可能有以下视图:

博客首页 ——显示最新发表的博客。

博客“详细”页面——单篇博客的固定链接页

面。评论——对给定的博客发表评论

在Django中,网页的页面和其他内容都是由视图来传递的(视图对WEB请求进行回应)。每个视图都是由一个简单

的Python函数(或者是基于类的视图的方法)表示的。Django通过检查请求的URL(准确地说,是URL里域名之后的那

部分)来选择使用哪个视图。

比如访问知乎:https://zhuanlan.zhihu.com/p/ 32292103 你会发现域名之后会带有类似/p/ 32292103 django就是利用

url域名之后的这段路径去匹配视图。

Django使用叫做‘URLconf’的配置来为URL匹配视图。 一个URLconf负责使用正则表达式将URL模式匹配到视图。

2 、定义视图

视图就是一个Python函数(或者是基于类的视图的方法),被定义在views.py中视图

的第一个参数是HttpRequest类型的对象request,包含了所有请求的信息视图必须

返回HttpResponse对象,包含返回给请求者的响应信息

让我们来编写第一个视图。 打开应用目录下的views.py文件并将以下Python代码写入:

personal_blog/views.py

这是Django中最简单的视图。 为了能够调用这个视图,我们需要将这个视图映射到URL上 —— 利用一个

URLconf。

fromdjango.shortcutsimportrender
fromdjango.httpimportHttpResponse
#Createyourviewshere.
defindex(request): #视图函数默认接收一个 request作为参数,包含了所有请求的信息。
returnHttpResponse('helloworld')

3 、URL配置

项目目录下的settings.py中通过ROOT_URLCONF指定url配置,创建项目的时候会默认指定。

默认配置

urlpatterns列表,存储url()对象,这个名称是固定的 urlpatterns中的每个正则表达式在第一次访问它们时被编译

url()对象,被定义在django.conf.urls包中

语法: 1 、包含,一般在自定义应用中创建一个urls.py来定义url

2 、定义,指定正则和视图的对应关系

正则说明:

定义一个视图:

配置url

url(正则,include('应用.urls'))
url(正则,'视图名称')
1 、正则部分推荐使用r,表示字符串不转义,这样在正则表达式中使用\只写一个就可以
2 、不能在开始加反斜杠,推荐在结束加反斜杠
错误使用:正则开头加/
r'/index'
r'/index/'
defdetail(request):
returnHttpResponse('ok')
ROOT_URLCONF='blog.urls'
fromdjango.conf.urlsimportinclude,url
fromdjango.contribimportadmin
urlpatterns=[
url(r'^admin/', include(admin.site.urls)),
fromdjango.conf.urlsimporturl
frompersonal_blogimportviews
urlpatterns=
[url(r'^index/$',views.index),
url(r'^\d+/',views.detail)
]

URLconf配置规则:

一条URLconf包括url规则、视图两部分

url规则使用正则表达式定义

视图就是在views.py中定义的视图

查找视图的过程:在浏览器地址栏中输入url,请求到网站后,获取url信息,然后与编写好的URLconf从上往下逐条

匹配,如果匹配成功则调用对应的视图,退出匹配。如果所有的URLconf都没有匹配成功,则返回 404 错误,

配置url有两种方式,第一种是在项目目录的URLconf配置文件中配置,如下:

blog/urls.py中配置:

fromdjango.conf.urlsimportinclude,url
fromdjango.contribimportadmin
frompersonal_blog.viewsimportindex #将视图导入
urlpatterns=[
url(r'^admin/',include(admin.site.urls)), # 创建项目时,django自动创建的额访问管理后台的url
url(r'^index/',index) #配置访问index视图函数
]

不推荐使用这种方法,如果一个项目有多个应用,全部url都配置到项目URLconf中,会很混乱,不好维护。

启动服务器,在浏览器中输入http://http: 127. 0. 0. 1 : 8000 /index/,可以访问到index这个视图了。浏览器接收到helloworld

这个返回值。

第二种方法在应用目录中创建一个URLconf,创建一个名为urls.py的文件,创建好后项目文件如下图:

创建好文件之后,需要让项目的URLconf链接到应用的URLconf中。修改项目urls.py:

fromdjango.conf.urlsimportinclude,url
fromdjango.contribimportadmin
urlpatterns=[
url(r'^admin/', include(admin.site.urls)),
url(r'^blog',include('personal_blog.urls')),#符合正则将会进入personal_blog的urls.py中继续匹
配。
]

配置好关联之后,回到应用中的URLconf配置中。

personal_blog/urls.py

配置好后在浏览器输入:http:// 127. 0. 0. 1 : 8000 /blog/index/ ,同样可以访问到视图函数,以后都使用第二种方法。

4 、匹配规则介绍

上面有提到,参与匹配的url只是域名之后。比如:http:// 127. 0. 0. 1 : 8000 /blog/index/?a= 1 &b= 5 这个url 只会有

blog/index/ 参与匹配,域名以及参数都不参与匹配。

匹配从项目URLconf中开始匹配,项目中的URLconf是那个文件,可以在setting.py的设置文件看到这条配置。

URLconf根配置是blog/urls.py这个文件。

blog/urls.py文件:

fromdjango.conf.urlsimporturl
frompersonal_blogimportviews
urlpatterns=
[url(r'^index/$',views.index)
]
ROOT_URLCONF='blog.urls'
fromdjango.conf.urlsimportinclude,url
fromdjango.contribimportadmin
frompersonal_blog.viewsimportindex
urlpatterns=[
url(r'^admin/', include(admin.site.urls)),
url(r'^blog/',include('personal_blog.urls')), # 符合正则将会进入personal_blog的urls.py中继续匹
配。
]

blog/index/ 从上到下开始匹配,被 r’^blog/’ 这条正则匹配中 ,这条正则是对应包含personal_blog应用中的

urls.py的,那么将继续到personal_blog/urls.py中继续匹配 在前面匹配过的内容将不再参与匹配,那么只剩下

index/会继续匹配。

personal_blog/urls.py

继续匹配,index/匹配中r’^index/$'规则,这条URLconf对应视图,那么将会执行这个视图。到这里整个匹配

过程结束。如果全部正则都没有匹配上,就会报 404 错误请求资源不存在。

5 、url中参数提取

django中,可以将url提取值作为参数传给视图。视图函数可以接收

位置参数:

定义一个/year/month/day/格式的url,需要将year,month,day提取出来传给视图函数由于日

期都是数字格式那么这些编写正则:

视图函数接收参数: 正则第一个分组参数将传给视图的第二个形参,第二个传给视图第三个形参,以此类推。

浏览器访问 http:// 127. 0. 0. 1 : 8000 /blog/ 2014 / 2 / 12 / ,效果如下

fromdjango.conf.urlsimporturl
frompersonal_blogimportviews
urlpatterns=
[url(r'^index/$',views.index)
]
获取值需要在正则表达式中使用小括号,也就是正则的分组。
分为两种方式
1 、位置参数
2 、关键字参数
注意:两种参数的方式不要混合使用,在一个正则表达式中只能使用一种参数方式
url(r'^(\d+)/(\d+)/(\d+)/',views.date)
defdate(request,year,month,day):
return HttpResponse('{}-{}-{}'.format(year,month,day))

关键参数:

在正则表达式部分为组命名 修改url中的正则表达式。 其中?P部分表示为这个参数定义的名称。

视图函数中的形参,只能用正则中分组的名称。不管关键字参数位置如何传,最终结果是一样的。

6 、URL起别名

一般网页中都有很多链接,其实这些链接就是一个url地址。比如在网页里面使用首页.像这样的

链接有很多。假如有一天,突然需要改变登录的链接,想将/index变成/blog/index这样的话,就需要将url里面的正

则改变成^blog/index/ , 同 时 再 将 < a > 标 签 里 面 的 h r e f 变 成 b l o g / i n d e x / ,同时再将标签里面的href变成^blog/index/ <a>hrefblog/index/。像这样的链接太多了,根本就无法修改。

由于没有学到模板,后面会详细介绍模板,这里知道name作用即可:

这个应用中新建一个 templates 文件夹,在templates中新建一个 index.htmlindex.html

url(r'^(?P\d+)/(?P\d+)/(?P\d+)/',views.date)
defdate(request,month,day,year):
return HttpResponse('{}-{}-{}'.format(year,month,day))




Title


blog

blog
blog
blog

blog
blog
blog
blog


创建一个视图,返回index.html

应用中url配置

在浏览器中访问:http:// 127. 0. 0. 1 : 8000 /blog/index/

现在需求改了,原来的a标签连接需要修改成/blog/detail/p/那么修改正则后,a标签是不是得全部修改!这样工作量

就很大了,如果一个网站很多url,那么该的时候有部分没改过来,那不就出问题了。那么我们用name参数来改进下:

url增加一个name参数

fromdjango.shortcutsimportrender
fromdjango.httpimportHttpResponse
#Createyourviewshere.
defindex(request):
returnrender(request,'index.html')
url(r'^detail/',views.detail)
url(r'^detail/',views.detail,name='detail')

修改模板:

修改完后重新访问:http:// 127. 0. 0. 1 : 8000 /blog/index/ 查看网页源代码:





Title



{%raw%} blog
blog
blog #使用name参数{%url'detail'%} 模板语言
blog
blog
blog
blog
{%endraw%}


这种写法,修改url之后,我们看看能不能正常渲染。 修改url:

使用name参数,在不修改前端页面url的情况下,修改了url,django会在前端页面自动渲染name参数对应的

url。其他没有使用name参数的a标签url就没有修改过来。

url(r'^detail/p/',views.detail,name='detail')

name参数还有其他用法这里先不细讲,由于刚入门django知识储备还不够,再深入讲解可能大家听不懂,所以先将

基础知识学完之后会补充name参数其他用法。

7 、视图与模型交互

每个视图函数只负责处理两件事中的一件:返回一个包含所请求页面内容的 HttpResponse对象,或抛出一个诸如

Http 404 异常。 视图可以从数据库中读取记录,或者不读取数据库。下面访问数据库,读取文章标题返回。

修改index视图

访问 http:// 127. 0. 0. 1 : 8000 /blog/index/

七、模板基础

1 、设置模板路径

在上一节中,查询出数据是以字符串形式返回给浏览器的,这显然是不符合网站开发的。要一个好看的界面必然用

到css,html,js,如果将这些内容都写成字符串的形式,显然不现实。

为了解决这一问题,django中使用了模板

将前端页面写在模板由视图调用,再返回给浏览器。

在setting.py配置文件中TEMPLATES设置描述了Django将如何加载并渲染模板。

from.modelsimport* # 导入模型类,.models表示导入当前文件夹下的models
#Createyourviewshere.
defindex(request):
post=Post.objects.all()#查询Post表中的所有数据,返回一个列表
content=','.join([p.titleforpinpost])
returnHttpResponse(content)
TEMPLATES=[
{
'BACKEND':'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR,'templates')],
#模板路径,定义项目目录下的templates
#BASE_DIR:项目路径,在setting中定义
#BASE_DIR=os.path.dirname(os.path.dirname(os.path.abspath( file)))
'APP_DIRS':True,#包含应用目录下的templates目录,设置为True,django也能找到应用目录下的模
板。
'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',
],
},
},
]

目录:

2 、模板命名空间

我们可以直接将我们的模板放在blog/templates,但实际这样做会很麻烦。Django将选择它找到的名字匹配的第一个模

板文件,如果你在不同的应用有相同名字的模板文件,Django将不能区分它们。我们需要将Django指向正确的模板,

最简单的方式是使用命名空间。具体实现方式是,将这些模板文件放在以应用的名字来命名的另一个目录下:

3 、定义模板

django中的模板,是一个html文件,但是模板由自己的一套语言。

在模板中输出变量语法如下,变量可能是从视图中传递过来的,也可能是在模板中定义的

模板系统使用点号查找语法来访问变量的属性。

在模板中编写代码段语法:

比如:在视图中传一个对象参数给模板。如果模板中需要使用对象的属性那么,使用 对象.属性名 方式访问。

编写一个模板:

/blog/templates/personal_blog/title.html

{{变量名}}
{%代码段%}
{{对象.属性名}}

Title


    {%raw%} {%forpinpost_list%}
  • {{p.title}}
  • #模板系统使用点号查找语法来访问变量的属性。 {%endfor%}
{%endraw%}


调用模板分为三步骤:

找到模板定

义上下文渲

染模板

创建一个视图title视图来使用模板:

配置url:

浏览器中访问 http:// 127. 0. 0. 1 : 8000 /blog/title/ 应该能看到一个形如列表的,文章标题。

#导入模块
fromdjango.httpimportHttpResponse
fromdjango.templateimportRequestContext,loader
deftitle(request):
post_list=Post.objects.all()
#加载模板文件
template=loader.get_template('personal_blog/title.html')
#定义上下文
context=RequestContext(request,
{'post_list':post_list,
})
#渲染模板
return HttpResponse(template.render(context))
url(r'^title/',views.title)

4 、render快捷渲染函数

django调用模板一般方式是载入一个模板、填充一个context然后返回一个含有模板渲染结果的HttpResponse对

象,django提供了一个快捷函数让调用模板更简单。

使用快捷函数重写视图:

render()函数将请求对象作为它的第一个参数,模板的名字作为它的第二个参数,第三个参数向模板中传递的上下文

数据。它返回一个HttpResponse对象,含有用给定的context渲染后的模板。

八、博客首页

1 、文章首页

在模板templates/personal_blog目录下新建一个index.html用于做主页展示文章。为了好看点,加了一些css样式。





BLOG





  • 首页
  • 联系
  • 关于
  • 管理
  • {%forpinpost_list%} {{p.created_time}}
    {{p.title}}
    摘要:   {{p.content|slice:' 100 '}} {# |slice过滤器,只取前 100 个字符 #}
    阅读全文
    
    posted@ 2018 - 01 - 0619 : 51 地球守卫者阅读( 32 )评论( 0 )
    {%endfor%}
    
    
    

    视图函数:

    配置url:

    重启服务器:浏览 http:// 127. 0. 0. 1 : 8000 /blog/index/ 效果如下:

    fromdjango.shortcutsimportrender
    
    fromdjango.httpimportHttpResponse
    fromdjango.templateimportRequestContext,loader
    from.modelsimport*
    
    #Createyourviewshere.
    
    defindex(request):
    #查询所有文章
    post_list=Post.objects.all()
    
    return render(request,'personal_blog/index.html',context={"post_list":post_list})
    
    url(r'^index/$',views.index,name='index'),
    

    2 、文章详细页

    点击文章标题,和阅读全文应该链接到文章的详细页。编

    写templates/personal_blog/detail.html详细页模块:

    详细页视图,由于详细页需要知道那篇文章。所有要求请求的时候将文章id传到视图。

    配置详细页url,利用url参数提取的方式获取id。

    由于视图需要接收id参数,所以在url中需要将id传给视图,修改首页的标题跟阅读全文的url链接:

    
    
    
    
    {{post.title}}
    
    
    
      {{post.title}}
  • {{post.content}}
  • 
    
    
    defdetail(request,id):
    
    #查询pk为 id的文章
    post=Post.objects.get(pk=id)
    
    returnrender(request,'personal_blog/detail.html',context={"post":post})
    
    url(r'detail/(\d+)',views.detail,name='detail')
    
    {#使用url的name参数动态生成url#}
    
    {{p.title}}
    
    阅读全文
    

    重启服务器 尝试访问详细页:

    127:.0.0.1:8000
    

    你可能感兴趣的:(django)