框架(framework),指为解决一个开放性的问题而设计的具有一 定约束性的支撑结构,使用框架可以帮助你快速开发特定的系统。
常见的python web框架
`Full-Stack Framework`(全栈框架)
Django、web2py、TurboGears、Pylons、......
`Non Full-Stack Framework`(非全栈框架)
tornado、Flask、Bottle、webpy、pyramid.....
python 3.5.2
Django==1.11.5
PyMySQL==0.7.11
pytz==2017.2
方法一:使用pip工具
更新pip的版本
python -m pip install --upgrade pip
首先要确保安装了pip工具
pip install Django
方法二:使用git
$ git clone git://github.com/django/django.git
$ pip install -e django/
方法三:下载Django的py包,然后使用python命令安装
检测是否安装成功
In [1]: import django
In [2]: django.VERSION
Out[2]: (1, 11, 4, u'final', 0)
django默认提供了Sqlite数据库
安装python和mysql的连接模块。
pip install PyMySQL 连接数据库
>django-admin.py help
Type 'django-admin.py help
查看指定命令的帮助文档
>django-admin.py help startproject
usage: django-admin.py startproject [-h] [--version] [-v {0,1,2,3}]
[--settings SETTINGS]
[--pythonpath PYTHONPATH] [--traceback]
[--no-color] [--template TEMPLATE]
[--extension EXTENSIONS] [--name FILES]
name [directory]
Creates a Django project directory structure for the given project name in th
current directory or optionally in the given directory.
positional arguments:
name Name of the application or project.
directory Optional destination directory
optional arguments:
-h, --help show this help message and exit
[root@miner-k ~]# mkdir /app
[root@miner-k ~]# cd /app/
[root@miner-k app]# django-admin startproject mysite
[root@miner-k app]# tree .
.
└── mysite #Django项目的名称,刚才创建的项目名称
├── manage.py #命令行实用程序,与Django进行交互。
└── mysite
├── __init__.py
├── settings.py #配置文件
├── urls.py #url的设置
└── wsgi.py #动态网关接口文件
Django-admin.py是Django的一个用于管理任务的命令工具,manage.py是对Django-admin.py的简单包装,每一个Django project里面都会包含一个manage.py
[root@miner-k mysite]# python manage.py help
Type 'manage.py help ' for help on a specific subcommand.
Available subcommands:
[auth]
changepassword
createsuperuser
[contenttypes]
remove_stale_contenttypes
[django]
check
compilemessages
createcachetable
dbshell
diffsettings
创建一个名为hello的app
[root@miner-k mysite]# python manage.py startapp hello
一般不同的APP负责不同的功能,一个app负责一个功能。
[root@miner-k mysite]# tree hello/
blog/
├── admin.py #管理后台的配置
├── apps.py #app的配置
├── __init__.py
├── migrations #数据库的管理
│ └── __init__.py
├── models.py #模型代码的配置
├── tests.py #单元测试
└── views.py #业务代码
生成同步数据库的脚本
D:\pythonwork\django\mysite>python manage.py makemigrations
No changes detected
同步数据
D:\pythonwork\django\mysite>python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying sessions.0001_initial... OK
创建超级用户以及密码(密码不能太短)
D:\pythonwork\django\mysite>python35 manage.py createsuperuser
Username (leave blank to use 'administrator'): admin
Email address:
Password:
Password (again):
Superuser created successfully.
修改超级用户的密码
D:\pythonwork\django\mysite>python35 manage.py changepassword admin
Changing password for user 'admin'
Password:
启动服务
D:\pythonwork\django\mysite>python35 manage.py runserver
Performing system checks...
System check identified no issues (0 silenced).
October 10, 2017 - 20:52:07
Django version 1.11.5, using settings 'mysite.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
登录后台
登录后台的URL:http://127.0.0.1:8000/admin/
启动的时候指定监听的端口
D:\pythonwork\django\mysite>python35 manage.py runserver 8080
Performing system checks...
System check identified no issues (0 silenced).
September 12, 2017 - 22:13:32
Django version 1.11.5, using settings 'mysite.settings'
Starting development server at http://127.0.0.1:8080/
Quit the server with CTRL-BREAK.
默认情况下
static 目录:存放css、js、图片等静态文件
templates 目录:存放模板
在app中配置
修改hello的app目录下的views.py定义一个业务请求处理的函数
from django.shortcuts import render
# Create your views here.
def hello(request):
return render(request,'table.html ')
定义一个模板并引用静态文件
在app的目录下创建两个目录static
和templates
将static目录下存放CSS、js格式的文件
在template目录下存放table.html文件
在项目mysite目录中配置
在settings.py里面的INSTALLED_APPS
中加入hello
,将新建的app增加到项目中。
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'hello',
]
在urls.py里面定义url地址
from django.conf.urls import url
from django.contrib import admin
from hello import views #从指定的app中导入views
'''url(URL路径正则表达式,app中views的函数,别名)'''
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^hello/', views.hello,name='hello'),
]
启动服务
访问测试
访问网站:http://127.0.0.1:8000/hello/
修改seting.py文件
'''在DIRS中指定模板的目录'''
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': ['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',
],
},
},
]
'''指定静态文件的目录'''
STATICFILES_DIRS = (os.path.join(BASE_DIR, 'static'),)
上面的URL的配置是在工程的urls.py中设置访问的URL,现在为了方便管理不同的URL,需要在不同的app下设置URL
工程中的urls.py配置
''' 包含app中URL的配置文件
1.导入incloude():
from django.conf.urls import url, include
2. 增加URL的参数:
url(r'^blog/', include('blog.urls'))
r'^blog/' :访问的后缀
include('blog.urls'):指定包含的URL的存放位置。blog目录下的urls
'''
from django.conf.urls import url,include
from django.contrib import admin
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^', include('hello.urls')),
]
app中的urls.py的配置
from django.conf.urls import url
from hello import views
urlpatterns = [
url(r'^hello/$', views.hello),
]
注意:访问URL时,URL是项目中URL中配置加app中的URL。如果在工程中的URl中设置url(r'^abc/', include('hello.urls')),
在app中设置url(r'^hello/$', views.hello),
访问时输入的URl为http://127.0.0.1:8000/abc/hello/
在钻研更多代码之前,让我们先花点时间考虑下 Django 数据驱动 Web 应用的总体设计。
Django 的设计鼓励松耦合及对应用程序中不同部分的严格分割。 遵循这个理念的话,要想修改应用的某部分而不影响其它部分就比较容易了。 在视图函数中,我们已经讨论了通过模板系统把业务逻辑和表现逻辑分隔开的重要性。 在数据库层中,我们对数据访问逻辑也应用了同样的理念。
把数据存取逻辑、业务逻辑和表现逻辑组合在一起的概念有时被称为软件架构的 Model-View-Controller (MVC)模式。 在这个模式中, Model 代表数据存取层,View 代表的是系统中选择显示什么和怎么显示的部分,Controller 指的是系统中根据用户输入并视需要访问模型,以决定使用哪个视图的那部分。
Django 紧紧地遵循这种 MVC 模式,可以称得上是一种 MVC 框架。 以下是 Django 中 M、V 和 C 各自的含义:
由于 C 由框架自行处理,而 Django 里更关注的是模型(Model)、模板(Template)和视图(Views),Django 也被称为 MTV 框架 。在MTV 开发模式中:
如果你熟悉其它的 MVC Web开发框架,比方说 Ruby on Rails,你可能会认为 Django 视图是控制器,而 Django 模板是视图。 很不幸,这是对 MVC 不同诠释所引起的错误认识。 在 Django 对 MVC 的诠释中,视图用来描述要展现给用户的数据;不是数据 如何展现 ,而且展现 哪些 数据。 相比之下,Ruby on Rails 及一些同类框架提倡控制器负责决定向用户展现哪些数据,而视图则仅决定 如何 展现数据,而不是展现 哪些 数据。
MTV的响应模式如下所示:
Django 决定要使用的根URLconf 模块。通常,这个值就是ROOT_URLCONF 的设置,但是如果进来的HttpRequest 对象具有一个urlconf 属性(通过中间件request processing 设置),则使用这个值来替换ROOT_URLCONF 设置。
url.py:URL分发器(路由配置文件)
URL配置(URLconf)就像配置Django所支持的网站目录,他的本质是URL模式以及要为该URL模式调用的视图函数之间的映射表。
urlpatterns = [
url(正则表达式,view函数,参数,别名,前缀),
]
#url的函数定义
url(regex, view, kwargs=None, name=None):
下面是一个简单的 URLconf:
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^articles/2003/$', views.special_case_2003),
url(r'^articles/([0-9]{4})/$', views.year_archive),
url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive),
url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail),
]
注:
一些请求的例子:
上面的示例使用简单的、没有命名的正则表达式组(通过圆括号)来捕获URL 中的值并以位置 参数传递给视图。在更高级的用法中,可以使用命名的正则表达式组来捕获URL 中的值并以关键字 参数传递给视图。
在Python 正则表达式中,命名正则表达式组的语法是(?P
,其中name
是组的名称,pattern
是要匹配的模式。
下面是以上URLconf 使用命名组的重写:
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^articles/2003/$', views.special_case_2003),
url(r'^articles/(?P[0-9]{4})/$' , views.year_archive),
url(r'^articles/(?P[0-9]{4})/(?P[0-9]{2})/$' , views.month_archive),
url(r'^articles/(?P[0-9]{4})/(?P[0-9]{2})/(?P[0-9]{2})/$' , views.article_detail),
]
这个实现与前面的示例完全相同,只有一个细微的差别:捕获的值作为关键字参数而不是位置参数传递给视图函数。例如:
在实际应用中,这意味你的URLconf 会更加明晰且不容易产生参数顺序问题的错误 —— 你可以在你的视图函数定义中重新安排参数的顺序。当然,这些好处是以简洁为代价;conf
命名组和传递参数的区别:
该方法传递的参数是变量,可以根据客户端等的不同而变化,但是使用ru()中传递的参数是固定值。
urls.py
from django.conf.urls import url
from hello import views
'''向views中的hello函数中传递参数a'''
urlpatterns = [
url(r'^hello/$', views.hello,{'a':123}),
]
views.py
from django.shortcuts import render
from django.contrib.auth.models import User
# Create your views here.
'''函数hello接收参数a,否则会报错'''
def hello(request,a):
user_list = User.objects.all()
print(a)
return render(request,"table.html ",{'user_list':user_list})
通常一个URL分解器对应一个URL匹配模块,它可以包含多个URL模式,也可以包含多个其他的URL分解器。通常这种包含关系结构设计,实现了Django对URL的层级解析。
工程中的urls.py配置
''' 包含app中URL的配置文件
1.导入incloude():
from django.conf.urls import url, include
2. 增加URL的参数:
url(r'^blog/', include('blog.urls'))
r'^blog/' :访问的后缀
include('blog.urls'):指定包含的URL的存放位置。blog目录下的urls模块
'''
from django.conf.urls import url,include
from django.contrib import admin
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^', include('hello.urls')),
]
app中的urls.py的配置
from django.conf.urls import url
from hello import views
urlpatterns = [
url(r'^hello/$', views.hello),
]
注意:访问URL时,URL是项目中URL中配置加app中的URL。如果在工程中的URl中设置url(r'^abc/', include('hello.urls')),
在app中设置url(r'^hello/$', views.hello),
访问时输入的URl为http://127.0.0.1:8000/abc/hello/
urls.py中,需要配置访问时的URL
设置urls.py的主目录
'''在工程目录中的seting.py中设置,设置工程mysite下的urls为主URL的配置文件'''
ROOT_URLCONF = 'mysite.urls'
配置方法:
'''配置URL的正则表达式以及对应的URL对应的操作(函数)'''
from django.conf.urls import url
urlpatterns = [
url('正则表达式', '操作函数','参数','别名','前缀'),
]
为方便管理URL设置层目录include函数
''' 包含app中URL的配置文件
1.导入incloude():
from django.conf.urls import url, include
2. 增加URL的参数:
url(r'^blog/', include('blog.urls'))
r'^blog/' :访问的后缀
include('blog.urls'):指定包含的URL的存放位置。blog目录下的urls模块
'''
from django.conf.urls import url,include
from django.contrib import admin
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^', include('hello.urls')),
]
Django 使用Request 对象和Response 对象在系统间传递状态。
当请求一个页面时,Django会建立一个包含请求元数据的 HttpRequest 对象。 当Django 加载对应的视图时,HttpRequest 对象将作为视图函数的第一个参数。每个视图会返回一个HttpResponse 对象。
from django.shortcuts import render
from django.contrib.auth.models import User
from django.http import HttpRequest,HttpResponse
def hello(request,a):
user_list = User.objects.all()
print(a)
return render(request,"table.html ",{'user_list':user_list})
在函数最开始的第一个参数,request是HttpRequest的实例。
HttpRequest.scheme
一个字符串,表示请求的方案(通常是http 或https)
HttpRequest.body
一个字节字符串,表示原始HTTP 请求的正文。它对于处理非HTML 形式的数据非常有用:二进制图像、XML等。 如果要处理常规的表单数据,应该使用HttpRequest.POST。
HttpRequest.path
一个字符串,表示请求的页面的完整路径,不包含域名。例如:”/music/bands/the_beatles/”
HttpRequest.method
一个字符串,表示请求使用的HTTP 方法。必须使用大写
if request.method == 'GET':
do_something()
elif request.method == 'POST':
do_something_else()
HttpRequest.GET
一个类似于字典的对象,包含HTTP GET 的所有参数
HttpRequest.POST
一个包含所有给定的HTTP POST参数的类字典对象,提供了包含表单数据的请求。详情请参考下面的QueryDict 文档。如果需要访问请求中的原始或非表单数据,可以使用HttpRequest.body 属性。
POST 请求可以带有空的POST 字典 —— 如果通过HTTP POST 方法请求一个表单但是没有包含表单数据的话。因此,不应该使用if request.POST 来检查使用的是否是POST 方法;应该使用if request.method == “POST”(参见上文)。|
注意:POST 不包含上传的文件信息
HttpRequest.COOKIES
一个标准的Python 字典,包含所有的cookie。键和值都为字符串
HttpRequest.FILES
一个类似于字典的对象,包含所有的上传文件。FILES 中的每个键为 中的name。
注意,FILES 只有在请求的方法为POST 且提交的 带有enctype=”multipart/form-data” 的情况下才会包含数据。否则,FILES 将为一个空的类似于字典的对象
HttpRequest.META
一个标准的Python 字典,包含所有的HTTP 头部。具体的头部信息取决于客户端和服务器,下面是一些示例:
CONTENT_LENGTH —— 请求的正文的长度(是一个字符串)。
CONTENT_TYPE —— 请求的正文的MIME 类型。
HTTP_ACCEPT —— 响应可接收的Content-Type。
HTTP_ACCEPT_ENCODING —— 响应可接收的编码。
HTTP_ACCEPT_LANGUAGE —— 响应可接收的语言。
HTTP_HOST —— 客服端发送的HTTP Host 头部。
HTTP_REFERER —— Referring 页面。
HTTP_USER_AGENT —— 客户端的user-agent 字符串。
QUERY_STRING —— 单个字符串形式的查询字符串(未解析过的形式)。
REMOTE_ADDR —— 客户端的IP 地址。
REMOTE_HOST —— 客户端的主机名。
REMOTE_USER —— 服务器认证后的用户。
REQUEST_METHOD —— 一个字符串,例如”GET” 或”POST”。
SERVER_NAME —— 服务器的主机名。
SERVER_PORT —— 服务器的端口(是一个字符串)。
从上面可以看到,除CONTENT_LENGTH 和CONTENT_TYPE 之外,请求中的任何HTTP 头部转换为META 的键时,都会将所有字母大写并将连接符替换为下划线最后加上HTTP_ 前缀。所以,一个叫做X-Bender 的头部将转换成META 中的HTTP_X_BENDER 键。
HttpRequest.user
一个AUTH_USER_MODEL 类型的对象,表示当前登录的用户。如果用户当前没有登录,user 将设置为django.contrib.auth.models.AnonymousUser 的一个实例。你可以通过is_authenticated() 区分它们,像这样:
if request.user.is_authenticated():
# Do something for logged-in users.
else:
# Do something for anonymous users.
user 只有当Django 启用AuthenticationMiddleware 中间件时才可用。更多信息,参见Django 中的用户认证。
HttpRequest.session
一个既可读又可写的类似于字典的对象,表示当前的会话。只有当Django 启用会话的支持时才可用
每一个view请求处理方法必须有一个HttpResponse对象的
典型的应用是传递一个字符串作为页面的内容到HttpResponse 构造函数:
>>> from django.http import HttpResponse
>>> response = HttpResponse("Here's the text of the Web page.")
>>> response = HttpResponse("Text only, please.", content_type="text/plain")
如果你想增量增加内容,你可以将response 看做一个类文件对象
>>> response = HttpResponse()
>>> response.write("Here's the text of the Web page.
")
>>> response.write("Here's another paragraph.
")
格式:
render(request, template_name[, context][, context_instance][, content_type][, status][, current_app][, dirs][, using])[source]
结合一个给定的模板和一个给定的上下文字典,并返回一个渲染后的 HttpResponse 对象
必选参数:
request:该request用于生成response
template_name:要使用的模板的完整名称或者模板名称的一个序列。
可选参数:
content_type:生成的文档要使用的MIME 类型。默认为DEFAULT_CONTENT_TYPE 设置的值
status:响应的状态码。默认为200
下面的示例渲染模板myapp/index.html,MIME 类型为application/xhtml+xml:
from django.shortcuts import render
def my_view(request):
# View code here...
return render(request, 'myapp/index.html', {"foo": "bar"},
content_type="application/xhtml+xml")
这个示例等同于:
from django.http import HttpResponse
from django.template import RequestContext, loader
def my_view(request):
# View code here...
t = loader.get_template('myapp/index.html')
c = RequestContext(request, {'foo': 'bar'})
return HttpResponse(t.render(c),
content_type="application/xhtml+xml")
格式:
render_to_response(template_name[, context][, context_instance][, content_type][, status][, dirs][, using])[source]
根据一个给定的上下文字典渲染一个给定的目标,并返回渲染后的HttpResponse
必选参数:
template_name:要使用的模板的完整名称或者模板名称的一个序列。如果给出的是一个序列,将使用存在的第一个模板。
可选参数:
content_type:生成的文档要使用的MIME 类型。默认为DEFAULT_CONTENT_TYPE 设置的值
status:响应的状态码。默认为200
实例:
下面的示例渲染模板myapp/index.html,MIIME 类型为application/xhtml+xml:
from django.shortcuts import render_to_response
def my_view(request):
# View code here...
return render_to_response('myapp/index.html', {"foo": "bar"},
content_type="application/xhtml+xml")
这个示例等同于:
from django.http import HttpResponse
from django.template import Context, loader
def my_view(request):
# View code here...
t = loader.get_template('myapp/index.html')
c = Context({'foo': 'bar'})
return HttpResponse(t.render(c),
content_type="application/xhtml+xml")
redirect(to, [permanent=False, ]*args, **kwargs)[source]
为传递进来的参数返回HttpResponseRedirect 给正确的URL 。
参数可以是:
默认返回一个临时的重定向;传递permanent=True 可以返回一个永久的重定向
示例:
通过传递一个对象;将调用get_absolute_url() 方法来获取重定向的URL:
from django.shortcuts import redirect
def my_view(request):
...
object = MyModel.objects.get(...)
return redirect(object)
通过传递一个视图的名称,可以带有位置参数和关键字参数;将使用reverse() 方法反向解析URL:
def my_view(request):
...
return redirect('some-view-name', foo='bar')
传递要重定向的一个硬编码的URL:
def my_view(request):
...
return redirect('/some/url/')
也可以是一个完整的URL:
def my_view(request):
...
return redirect('http://example.com/')
默认情况下,redirect() 返回一个临时重定向。以上所有的形式都接收一个permanent 参数;如果设置为True,将返回一个永久的重定向:
def my_view(request):
...
object = MyModel.objects.get(...)
return redirect(object, permanent=True)
Django包含了一系列的HttpResponse衍生类(子类),用来处理不同类型的HTTP 响应(response)。与 HttpResponse相同, 这些衍生类(子类)存在于django.http之中。
class HttpResponseRedirect
构造函数的第一个参数是必要的 — 用来重定向的地址。这些能够是完全特定的URL地址(比如,’http://www.yahoo.com/search/‘),或者是一个不包含域名的绝对路径地址(例如, ‘/search/’)。关于构造函数的其他参数,可以参见 HttpResponse。注意!这个响应会返回一个302的HTTP状态码。
url
这个只读属性,代表响应将会重定向的URL地址(相当于Location response hader)。
class HttpResponsePermanentRedirect
与HttpResponseRedirect一样,但是它会返回一个永久的重定向(HTTP状态码301)而不是一个“found”重定向(状态码302)。
class HttpResponseNotModified
构造函数不会有任何的参数,并且不应该向这个响应(response)中加入内容(content)。使用此选项可指定自用户上次请求(状态代码304)以来尚未修改页面。
class HttpResponseBadRequest
与HttpResponse的行为类似,但是使用了一个400的状态码。
class HttpResponseNotFound
与HttpResponse的行为类似,但是使用的404状态码。
class HttpResponseForbidden
与HttpResponse类似,但使用403状态代码。
在项目的目录下setings.py中
#setings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
mysql:
引擎的名称:django.db.backends.mysql
在工程目录中init.py中写入:
import pymysql
pymysql.install_as_MySQLdb()
连接设置将被用在这些命令上:
换句话说,如果你设置数据库的名称在OPTIONS, 这将优先于NAME, 这将覆盖任何在MySQL option file中的东西.
下面是使用一个MySQL选择文件一个示例配置:
# settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'OPTIONS': {
'read_default_file': '/path/to/my.cnf',
},
}
}
# my.cnf
[client]
database = NAME
user = USER
password = PASSWORD
default-character-set = utf8
其他几个MySQLdb连接选项可能是有用的,例如ssl, init_command, and sql_mode. 查阅 MySQLdb documentation了解更多细节。
> python manage.py migrate
ORM是什么?:(在django中,根据代码中的类自动生成数据库的表也叫–code first)
ORM:Object Relational Mapping(对象关系映射)
类名对应——》数据库中的表名
类属性对应———》数据库里的字段
类实例对应———》数据库表里的一行数据
obj.id obj.name…..类实例对象的属性
# views.py
from django.shortcuts import render
from django.contrib.auth.models import User
from django.http import HttpRequest,HttpResponse
# Create your views here.
def hello(request,a):
user_list = User.objects.all()
print(user_list.query)
return render(request,"table.html ",{'user_list':user_list})
# 在project的setings.py
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}
'''准备环境'''
D:\pythonwork\django\mysite>python manage.py shell
>>> from hello.models import *
create和save方法
objects:model默认管理器,create是管理器的方法,save是model对象的方法。
插入主外键关系的时候,可以用对象的方式,也可以直接关联ID的方式
插入多对多关系的时候要分步操作。
插入一个作者:
'''创建一个作者'''
>>> Author.objects.create(name='tom')
(0.000) SELECT @@SQL_AUTO_IS_NULL; args=None
(0.052) INSERT INTO `hello_author` (`name`) VALUES ('tom'); args=['tom']
>>>
插入一个作者的详细记录:
>>> AuthorDetail.objects.create(sex=0,email='[email protected]',address='北京市海淀区梧桐路25号',birthday='19920202',author_id=1)
插入一个出版社的记录
>>> pub = Publisher()
>>> pub.name = "中国电子出版社"
>>> pub.address = "北京市"
>>> pub.city = "北京市"
>>> pub.state_province = '北京市'
>>> pub.country = '中国'
>>> pub.website = 'http://www.miner-k.com'
>>> pub.save()
(0.052) INSERT INTO `hello_publisher` (`name`, `address`, `city`, `state_provinc
e`, `country`, `website`) VALUES ('中国电子出版社', '北京市', '北京市', '北京市'
, '中国', 'http://www.miner-k.com'); args=['中国电子出版社', '北京市', '北京市',
'北京市', '中国', 'http://www.miner-k.com']
插入一本书的记录
>>> Book.objects.create(title='python入门到精通',publisher=pub,publisher_date='2012-12-12')
(0.067) INSERT INTO `hello_book` (`title`, `publisher_id`, `publisher_date`) VALUES ('python入门到精通', 1, '2012-12-12'); args=['python入门到精通', 1, '2012-12-12']
插入书、作者、出版商关系的记录
>>> book = Book.objects.get(id=1)
(0.002) SELECT VERSION(); args=None
(0.002) SELECT `hello_book`.`id`, `hello_book`.`title`, `hello_book`.`publisher_id`, `hello_book`.`publisher_date` FROM `hello_book` WHERE `hello_book`.`id` = 1; args=(1,)
>>> author = Author.objects.get(id=1)
(0.002) SELECT `hello_author`.`id`, `hello_author`.`name` FROM `hello_author` WHERE `hello_author`.`id` = 1; args=(1,)
>>> book.authors.add(author)
(0.004) SELECT `hello_book_authors`.`author_id` FROM `hello_book_authors` WHERE
(`hello_book_authors`.`book_id` = 1 AND `hello_book_authors`.`author_id` IN (1)); args=(1, 1)
(0.066) INSERT INTO `hello_book_authors` (`book_id`, `author_id`) VALUES (1, 1); args=(1, 1)
>>>
update和save方法
updete是QuerySet对象的方法
>>> author = Author.objects.get(id=1)
(0.002) SELECT `hello_author`.`id`, `hello_author`.`name` FROM `hello_author` WHERE `hello_author`.`id` = 1; args=(1,)
>>> author.name = 'jim'
>>> author.save()
(0.586) UPDATE `hello_author` SET `name` = 'jim' WHERE `hello_author`.`id` = 1;args=('jim', 1)
所谓的惰性查询:publisher.objects.all()只是返回一个QuarySet(查询结果集对象),并不会马上执行sql,而是当调用QuerySet的时候才会执行。
>>> Author.objects.all()
(0.002) SELECT `hello_author`.`id`, `hello_author`.`name` FROM `hello_author` LIMIT 21; args=()
]>
>>> Book.objects.all()
(0.002) SELECT `hello_book`.`id`, `hello_book`.`title`, `hello_book`.`publisher_id`, `hello_book`.`publisher_date` FROM `hello_book` LIMIT 21; args=()
]>
delete方法
删除id为1的书籍
'''删除指定id的书籍'''
>>> Book.objects.filter(id=1).delete()
(0.003) SELECT `hello_book`.`id`, `hello_book`.`title`, `hello_book`.`publisher_
id`, `hello_book`.`publisher_date` FROM `hello_book` WHERE `hello_book`.`id` = 1; args=(1,)
(0.069) DELETE FROM `hello_book_authors` WHERE `hello_book_authors`.`book_id` IN (1); args=(1,)
(0.001) DELETE FROM `hello_book` WHERE `hello_book`.`id` IN (1); args=(1,)
(2, {'hello.Book': 1, 'hello.Book_authors': 1})
执行查询的相关链接
QuerySet特点:
1.可迭代的
2.可切片的
# python manage.py shell
'''将查询的结果存储到一个变量中,通过查看变量的类型发现返回值是QuerySet类。 '''
>>> from hello.models import *
>>> pub_list = Publisher.objects.all()
>>> type(pub_list)
<class 'django.db.models.query.QuerySet'>
>>> for pub in pub_list:
... print(pub.name)
...
中国电子出版社
filter() 始终给你一个查询集,即使只有一个对象满足查询条件 —— 这种情况下,查询集将只包含一个元素。
如果你知道只有一个对象满足你的查询,你可以使用管理器的get() 方法,它直接返回该对象:
获取一个表中所有对象的最简单的方式是全部获取。可以使用管理器的all() 方法:
>>> pub_list = Publisher.objects.all()
all()方法返回包含数据库中所有对象的一个查询集。
all()方法 返回了一个包含数据库表中所有记录查询集 。但在通常情况下,你往往想要获取的是完整数据集的一个子集。
要创建这样一个子集,你需要在原始的的查询集上增加一些过滤条件。两个最普遍的途径是:
filter(**kwargs)
返回一个新的查询集 ,它包含满足查询参数的对象。
exclude(**kwargs)
返回一个新的查询集 ,它包含不满足查询参数的对象。
查询参数(上面函数定义中的**kwargs)需要满足特定的格式,下面字段查询一节中会提到。
举个例子,要获取年份为2006的所有文章的查询集,可以使用filter()方法:
>>> Author_list = Author.objects.filter(id=1)
first()
返回结果集的第一个对象, 当没有找到时返回None.如果 QuerySet 没有设置排序,则将会自动按主键进行排序
例:
>>> Author.objects.all()
>>> Author.objects.all().first()
last()
工作方式类似first(),只是返回的是查询集中最后一个对象。
values(*fields)
返回一个ValuesQuerySet —— QuerySet 的一个子类,迭代时返回字典而不是模型实例对象。而是一个可迭代的字典序列。
values_list
它与values()非常相似,只不过后者返回的结果是字典序列,而values_list()返回的是元组序列。
>>> Book.objects.filter(id=1).values('title','publisher_date')
'title': '岩石力学', 'publisher_date': datetime.date(2017, 11, 7)}]>
>>> Book.objects.filter(id=1).values_list('title','publisher_date')
'岩石力学', datetime.date(2017, 11, 7))]>
查询id为1的书籍,并只显示数据名称和出版日期
>>> Book.objects.filter(id=1).values('title','publisher_date')
'title': '岩石力学', 'publisher_date': datetime.date(2017, 11, 7)}]>
>>> Book.objects.filter(id=1).values_list('title','publisher_date')
'岩石力学', datetime.date(2017, 11, 7))]>
查询所有的出版社信息,并按照id降序排列,并尝试使用reverse方法进行反向排序。
>>> Publisher.objects.all().order_by('id').values('name')
'name': '中国电子出版社'}, {'name': '中国工业出版社'}, {'name': '山
西教育出版社'}]>
>>> Publisher.objects.all().order_by('-id').values('name')
'name': '山西教育出版社'}, {'name': '中国工业出版社'}, {'name': '中
国电子出版社'}]>
>>> Publisher.objects.all().order_by('id').values('name').reverse()
'name': '山西教育出版社'}, {'name': '中国工业出版社'}, {'name': '中
国电子出版社'}]>
显示所有的出版社的地址,不能重复
>>> Publisher.objects.all().values('city')
'city': '北京市'}, {'city': '天津市'}, {'city': '太原市'}, {'city':
'太原市'}, {'city': '北京市'}, {'city': '北京市'}]>
>>> Publisher.objects.all().values('city').distinct()
'city': '北京市'}, {'city': '天津市'}, {'city': '太原市'}]>
查询北京市的出版社
>>> Publisher.objects.filter(city='北京市').values('name')
(0.002) SELECT `hello_publisher`.`name` FROM `hello_publisher` WHERE `hello_publ
isher`.`city` = '北京市' LIMIT 21; args=('北京市',)
<QuerySet [{'name': '中国电子出版社'}, {'name': '清华大学出版社'}, {'name': '北
大教育出版社'}]>
查询北京市除外的出版社
>>> Publisher.objects.exclude(city='北京市').values('name')
'name': '中国工业出版社'}, {'name': '山西教育出版社'}, {'name': '山
西大学出版社'}]>
查询男作者的数量
>>> AuthorDetail.objects.filter(sex='男').count()
(0.638) SELECT COUNT(*) AS `__count` FROM hello_authordetail` WHERE `hello_auth ordetail`.`sex` = '男'; args=('男',)
3
多表查询的技巧:
__ : 两个下划线可以生成连接查询,查询关联的字段信息
_set:提供了对象访问相关联表数据的方法,但是这种方式只能是相关类访问定义了关系的类(主键类访问外键类)
Publisher 类是Book类的主键类,
'''此处获取Publisher对象只能通过get方法获取,不能使用filter()'''
>>> pub_list = Publisher.objects.get(name='中国工业出版社')
>>> pub_list.book_set.all()
]>
>>> pub_list.book_set.all().values('title')
'title': '流体力学'}]>
查询客户的完整信息
'''AuthorDetail中的属性author是与表Author关联,如果直接打印author属性,打印的是author_id.如果需要打印Author的属性name,需要打印变量author__name'''
>>> from hello.models import *
>>> AuthorDetail.objects.values('sex','email','address','birthday','author')
'address': '北京市海淀区梧桐路25号', 'birthday': '19920202', 'author': 1, 'sex': '男', 'email': '[email protected]'}, {'address': '上海市外滩32号', 'bir
thday': '19921201', 'author': 2, 'sex': '男', 'email': '[email protected]'}, {'address': '广州市广陵大道21号', 'birthday': '19981232', 'author': 3, 'sex': '女', 'email': '[email protected]'}, {'address': '深圳市为民道11号', 'birthday': '19990303', 'author': 4, 'sex': '男', 'email': '[email protected]'}]>
>>> AuthorDetail.objects.values('sex','email','address','birthday','author__name')
'address': '北京市海淀区梧桐路25号', 'birthday': '19920202', 'author__name': 'jim', 'sex': '男', 'email': '[email protected]'}, {'address': '上海市外滩32号', 'birthday': '19921201', 'author__name': 'jim', 'sex': '男', 'email': '[email protected]'}, {'address': '广州市广陵大道21号', 'birthday': '19981232', 'author__name': 'lucy', 'sex': '女', 'email': '[email protected]'}, {'address': '深圳市为民道11号', 'birthday': '19990303', 'author__name': 'jick', 'sex': '男', 'email': '[email protected]'}]>
查询一本数书的作者姓名、出版社的名字
>>> Book.objects.filter(title='岩石力学').values('title','authors','publisher')
'publisher': 1, 'authors': 1, 'title': '岩石力学'}]>
>>> Book.objects.filter(title='岩石力学').values('title','authors__name','publisher__name')
'publisher__name': '中国电子出版社', 'title': '岩石力学', 'authors__name': 'jim'}]>
查询一个作者写的所有的书籍
>>> Book.objects.filter(authors__name='jim').values('title')
'title': '岩石力学'}]>
聚合查询
aggrate通过QuerySet进行计算,返回一个聚合值的字典,aggregate()每一个参数都指定一个包含在字典中的返回值。
查询某一个出版社出版书的数量
利用QuerySet的API
>>> from hello.models import *
>>> Publisher.objects.filter(name='中国工业出版社').count()
1
利用聚合查询aggregate
'''导入涉及到的模块'''
>>> from django.db.models import *
>>> Publisher.objects.filter(name='中国工业出版社').aggregate(Count('name'))
{'name__count': 1}
查询某一个作者出版书籍的总价
>>> Book.objects.filter(authors__name='jim').aggregate(Sum('price'))
{'price__sum': Decimal('10.00')}
分组查询annotate
可以为QuerySet中的每一个对象添加注解,可以通过计算机查询的结果中的每一个对象所关联的对象集合,从而得出总计价(也可是平均值或总和等)
查询所有的作者对应的所有出书的价格
>>> Book.objects.values('authors__name').annotate(Sum('price'))
<QuerySet [{'authors__name': 'jim', 'price__sum': Decimal('10.00')}, {'authors__
name': 'lucy', 'price__sum': Decimal('10.00')}, {'authors__name': 'jick', 'price
__sum': Decimal('10.00')}]>
查询所有出版社最便宜书籍的价格
>>> Book.objects.values('publisher__name').annotate(Min('price'))
<QuerySet [{'price__min': Decimal('10.00'), 'publisher__name': '中国电子出版社'}
, {'price__min': Decimal('10.00'), 'publisher__name': '中国工业出版社'}, {'price
__min': Decimal('10.00'), 'publisher__name': '山西教育出版社'}]>
一对一:
作者模型:一个作者有姓名(一对一)
作者详情模型:作者的详情中有,性别、email地址、和出生日期、作者详情模型和作者模型之间是一对一的关系
一对多:
出版商模型:出版商有名称、地址、所在城市、省、国家、网站。
书籍模型:书籍有书名和出版商。一本书可以有多个作者,一个作者可以有多本书,所以作者和书籍的关系是多对多的关系【many-to-many】。一本书只能是一个出版商出版,一个出版商可以出版多本书,出版商和书籍是一对多的关系【one-to-many】,也被称为外键【foreignkey】
修改配置文件
# models.py
from django.db import models
# Create your models here.
class Publisher(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=50)
city = models.CharField(max_length=60)
state_province = models.CharField(max_length=30)
country = models.CharField(max_length=50)
website = models.URLField()
class Author(models.Model):
name = models.CharField(max_length=30)
class AuthorDetail(models.Model):
sex = models.CharField(max_length=1,choices=((0,'男'),(1,'女')))
email = models.CharField()
address = models.CharField(max_length=50)
birthday = models.CharField()
author = models.OneToOneField(Author)
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
publisher_date = models.DateField()
代码简介:
生成数据库同步脚本
> python manage.py makemigrations
同步数据库
> python manage.py migrate
查看数据库的变化
同步数据库之前:
同步数据库之后:
新增加的表就是在models.py中的class。表名就是库名,表中的字段就是类的属性。
常用的字段类型:
字段类型 | 含义 |
---|---|
AutoField | 一个根据实际ID自动增长的IntegerField |
BigIntegerField | 一个64位整数, 类似于一个 IntegerField |
BinaryField | 二进制类型 |
BooleanField | 布尔字段类型 |
CharField | 字符串类型 |
DateField | 日期字段 |
DateTimeField | 日期时间字段 |
DecimalField | 精确小数字段 |
EmailField | email字段类型 |
FileField | 文件字段类型 |
FloatField | 浮点数字段类型 |
ImageField | 图片字段类型 |
IntegerField | 整数字段类型 |
IPAddressField | IP字段类型 |
SmallIntegerField | 小整型字段类型 |
TextField | 文本字段类型 |
URLField | url字段类型 |
更多类型类型链接
字段选项
字段选项名称 | 含义 |
---|---|
null | 如果为True,Django将在数据库中将空值存储为NULL。默认值是 False |
blank | 如果为True,则该字段允许为空白。 默认值是 False |
choices | 它是一个可迭代的结构(比如,列表或是元组),由可迭代的二元组组成(比如[(A, B), (A, B) …]),用来给这个字段提供选择项。 |
default | 该字段的默认值 |
help_text | 额外的 ‘help’ 文本将被显示在表单控件form中 |
primary_key | 若为 True, 则该字段会成为模型的主键字段 |
unique | 如果为 True, 这个字段在表中必须有唯一值 |
参考文档
'''如果数据库中字段增加或修改,需啊哟重新同步数据库'''
D:\pythonwork\django\mysite>python manage.py makemigrations
You are trying to add a non-nullable field 'price' to book without a default; we
can''t do that (the database needs something to populate existing rows).
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows with a null
value for this column)
'''第二点中提示退出设置增加字段的默认值,在增加的字段中添加参数default='''
2) Quit, and let me add a default in models.py
Select an option: 2
D:\pythonwork\django\mysite>python35 manage.py makemigration
D:\pythonwork\django\mysite>python35 manage.py migrate
目录名:migrations
作用:用来存放通过makemirgrations命令生成的数据库脚本。app目录下面必须要有migrations的目录且该目录下必须存放__init__.py
才能正常的使用数据库的同步功能。
记录migrantions目录下脚本的使用情况
flush:清空数据库,恢复数据库到最初的状态
makemigrantions:生成数据同步的脚本
migrate:同步数据库
showmigrations:查看生成的数据库同步脚本
sqlflush:查看生成清空数据库的脚本
sqlmigrate:查看数据库同步的sql语句
使用原生sql的方式主要的目的是解决一些复杂的sql不能用ORM的方式写出的问题。
extra:结果集修改器,一种提供额外查询参数的机制
raw:执行原始sql并返回模式实例
直接自定义SQL(这种方式不依赖于model,前两种方式要依赖于model)
extra实例
查询山西教育出版社出版所有价格大于10元的图书
>>> Book.objects.filter(publisher__name='山西教育出版社').extra(where=['price>10']).values('title')
'title': '材料力学'}, {'title': '工程力学'}]>
等价于
>>> Book.objects.filter(publisher__name='山西教育出版社',price__gt=10).values('title')
'title': '材料力学'}, {'title': '工程力学'}]>
使用raw
>>> Book.objects.raw('select * from hello_book')
>>> book_list = Book.objects.raw('select * from hello_book')
>>> for book in book_list:
... print(book.title)
...
(0.003) select * from hello_book; args=()
岩石力学
流体力学
材料力学
工程力学
使用自定sql语句
>>> from django.db import connection
>>> cursor = connection.cursor()
'''插入数据'''
>>> cursor.execute('insert into hello_author(name) values("郭敬明")')
(0.087) insert into hello_author(name) values("郭敬明"); args=None
1
'''修改数据'''
>>> cursor.execute('update hello_author set name="韩寒" where name="郭敬明"')
(0.071) update hello_author set name="韩寒" where name="郭敬明"; args=None
1
'''删除数据'''
>>> cursor.execute('delete from hello_author where name="韩寒"')
(0.205) delete from hello_author where name="韩寒"; args=None
1
'''查询语句'''
>>> cursor.execute('select * from hello_author')
(0.002) select * from hello_author; args=None
4
'''获取数据'''
>>> raw = cursor.fetchone()
>>> cursor.fetchone()
(2, 'jim')
>>> cursor.fetchone()
(3, 'lucy')
>>> cursor.fetchone()
(4, 'jick')
>>> cursor.fetchone()
控制自动转义是否可用.这种标签带有任何 on 或 off 作为参数的话,他将决定转义块内效果。该标签会以一个endautoescape作为结束标签.
当自动转义生效时,所有变量内容会被转义成HTML输出(在所有过滤器生效后)这等同与手动将escape筛选器应用于每个变量。
唯一一个例外是,变量或者通过渲染变量的代码,或者因为它已经应用了 safe或escape过滤器,已经被标记为“safe”。
例如:
在views.py中
def test(request):
value3 = "百度"
return render(request,'test.html',locals())
在test.html中
{% autoescape on %}
{{ values4 }}
{% endautoescape %}
格式:
{% if athlete_list %}
Number of athletes: {{ athlete_list|length }}
{% elif athlete_in_locker_room_list %}
Athletes should be out of the locker room soon!
{% else %}
No athletes.
{% endif %}
实例:
#views.py
def test(request):
number1 = 20
return render(request,'test.html',locals())
#test.html
<html lang="en">
<head>
<meta charset="UTF-8">
<title>test-Titletitle>
head>
<body>
{% if number1 == 10 %}
NUM:10
{% elif number1 == 20 %}
NUM:20
{% else %}
unknow
{% endif %}
body>
html>
#mysite/urls.py
from django.conf.urls import url,include
from django.contrib import admin
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^', include('hello.urls')),
]
#hello/urls.py
from django.conf.urls import url
from hello import views
urlpatterns = [
url(r'^hello/$', views.hello,{'a':123}),
url(r'^test/$', views.test),
]
访问测试:http://127.0.0.1:8000/test/
#views.py
def test(request):
number1 = 20
num_list = [1,2,3,4,5,6,7,8]
return render(request,'test.html',locals())
#test.html
<ul>
{% for num1 in num_list %}
<li>{{ num1 }}li>
{% endfor %}
ul>
访问测试:http://127.0.0.1:8000/test/
停止模板引擎在该标签的中渲染
{% verbatim %}
{{if dying}}Still alive.{{/if}}
{% endverbatim %}
将字符全部小写
{% filter force_escape|lower %}
This text will be HTML-escaped, and will appear in all lowercase.
{% endfilter %}
全部转化为大写
{% filter force_escape|upper %}
This text will be HTML-escaped, and will appear in all lowercase.
{% endfilter %}
把add后的参数加给value
例如:
{{ value|add:"2" }}
如果 value 为 4,则会输出 6.
过滤器首先会强制把两个值转换成Int类型。如果强制转换失败, 它会试图使用各种方式吧两个值相加。它会使用一些数据类型 (字符串, 列表, 等等.) 其他类型则会失败. Day of the month, 2 digits with leading zeros.
例如:,我们使用下面的值
{{ first|add:second }}
first 是 [1, 2, 3] ,second 是 [4, 5, 6], 将会输出 [1, 2, 3, 4, 5, 6].
警告:
如果字符串可以被强制转换成int类型则会 summed,无法被转换,则和上面的第一个例子一样
例如,用于在CSV中转义字符串。
例如:
在views.py中
def test(request):
number1 = 20
num_list = [1,2,3,4,5,6,7,8]
value = datetime.datetime.now()
value1 = "I'm a boy"
return render(request,'test.html',locals())
在test.html中
{{ value1|addslashes }}
如果value 是 “I’m using Django”, 输出将变成 “I\’m using Django”.
例如:
{{ value|date:"D d M Y" }}
如果value是datetime对象(例如,datetime.datetime.now()的结果),输出将是字符串 ‘Wed 09 Jan 2008’
如果value的计算结果为False,则使用给定的默认值。否则,使用该value。
例如:
在views.py中
def test(request):
value2 = ""
return render(request,'test.html',locals())
在test.html中
{{ value2|default:"nothing" }}
如果value为”“(空字符串),则输出将为nothing。
如果(且仅当)value为None,则使用给定的默认值。否则,使用该value。
注意,如果给出一个空字符串,默认值将不被使用。如果要回退空字符串,请使用default过滤器。
例如:
{{ value|default_if_none:"nothing" }}
如果value为None,则输出将为字符串“nothing”
转义字符串的HTML。具体来说,它使这些替换:
<转换为<
>转换为>
'(单引号)转换为'
"(双引号)转换为"
&转换为&
转义仅在字符串输出时应用,因此在连接的过滤器序列中escape的位置无关紧要:它将始终应用,就像它是最后一个过滤器。如果要立即应用转义,请使用force_escape过滤器。
将转义应用于通常会对结果应用自动转义的变量只会导致一轮转义完成。因此,即使在自动逃逸环境中使用此功能也是安全的。如果要应用多个转义通过,请使用force_escape过滤器。
例如,您可以在autoescape关闭时将escape应用于字段:
{% autoescape off %}
{{ title|escape }}
{% endautoescape %}
格式化数值为“人类可读”的文件大小(例如’13 KB’, ‘4.1 MB’, ‘102 bytes’等)。
例如:
{{ value|filesizeformat }}
返回列表中的第一项。
例如:
{{ value|first }}
返回列表中的最后一个项目。
例如:
{{ value|last }}
将字符串标记为在输出之前不需要进一步的HTML转义。当自动转义关闭时,此过滤器不起作用。
注意:如果您要链接过滤器,在safe后应用的过滤器可能会使内容再次不安全。例如,以下代码按原样打印变量:
{{ var|safe|escape }}
如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“…”)结尾。
参数:要截断的字符数
例如:
{{ value|truncatechars:5 }}
如果value是“Joel is a >,输出将为“Joel i …”。
如果value是”123456789”,输出结果为“12…”。输出的总共的字符串格式是5,包含三个省略号。
在一定数量的字后截断字符串。
参数:要截断的字数
例如:
{{ value|truncatewords:2 }}
如果value 是 “Joel is a slug”, 输出变为 “Joel is …”.
尽一切可能努力剥离所有[X] HTML标签。
例如:
{{ value|striptags }}
如果 value 的值是 “Joel is a slug“, 输出的结果是”Joel is a slug”.
无安全保证
请注意,striptags不会保证其输出是HTML安全的,尤其是对于无效的HTML输入。因此,NEVER将safe过滤器应用于striptags输出。如果您正在寻找更强大的功能,可以使用bleach Python库,特别是其clean方法。
在模板的存放位置有sub.html和table.html两个模板
在sub.html中
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
这是一个子模板
body>
html>
table.html在body中增加下面一行
......
<br> {% include 'sub.html' %}
访问指定的页面会看到子模板中的内容。如果子模板在table.html同级目录下的dir1中,此处应该写
{% include 'dir1\sub.html' %}
传递变量到子模板中
table.html在body中增加下面一行
{% include "dir1/sub.html" with person="Jane" greeting="Hello" %}
sub.html在body中增加变量
<body>
这是一个子模板{{person}}
body>
views.py中增加
def test1(request):
return render(request,'test1.html',locals())
在hello/urls.py中设置
urlpatterns = [
url(r'^hello/$', views.hello,{'a':123}),
url(r'^test/$', views.test),
url(r'^testbase/$', views.test1),
]
base.html中
<html lang="en">
<head>
<link rel="stylesheet" href="style.css" />
<title>{% block title %}我的基础模板{% endblock %}title>
head>
<body>
<div id="sidebar">
{% block sidebar %}
<ul>
<li><a href="/">Homea>li>
<li><a href="/blog/">Bloga>li>
ul>
{% endblock %}
div>
<div id="content">
{% block content %}{% endblock %}
div>
body>
html>
test1.html中(base.html的子模板版)
{% extends "base.html" %}/span>
{% block title %}这是我的第I个子模板{% endblock %}
{% block content %}
这是子模板的内容
{% endblock %}
ModelAdmin objects
ModelAdmin类是模型在Admin 界面中的表示形式。通常,将它们在你的应用中的名为admin.py的文件里
from django.contrib import admin
from myproject.myapp.models import Author
class AuthorAdmin(admin.ModelAdmin):
pass
admin.site.register(Author, AuthorAdmin)
如果对于默认的Admin 界面足够满意,那你根本不需要自己定义ModelAdmin 对象, 你可以直接注册模型类而无需提供ModelAdmin 的描述
from django.contrib import admin
from myproject.myapp.models import Author
admin.site.register(Author)
实例
在文件hello/admin.py中,
class PublisherAdmin(admin.ModelAdmin):
list_display = ('name','address','city','state_province','country','website',)
admin.site.register(Author)
admin.site.register(Publisher,PublisherAdmin)
admin.site.register(AuthorDetail)
admin.site.register(Book)
@admin.register(Publisher)
class PublisherAdmin(admin.ModelAdmin):
list_display = ('name','address','city','state_province','country','website',)
admin.site.register(Author)
# admin.site.register(Publisher,PublisherAdmin)
admin.site.register(AuthorDetail)
admin.site.register(Book)
使用list_display 去控制哪些字段会显示在Admin 的修改列表页面中。
list_display = ('name','address','city','state_province','country','website',)
search_fields = ('name','address')
list_filter = ('state_province',)
ordering = ('name',)
如果界面上有name字段,会在子段的旁边显示上下箭头(选择升序或者降序)
只能编辑的表单
fields = ('name','address')
除了指定的字段之外的表单都能编辑
exclude = ('name','address')
fieldsets = (
(None, {
'fields': ('name', 'address', )
}),
('Advanced options', {
'classes': ('collapse',),
'fields': ('city', 'state_province', 'country')
}),
)
django表单系统中,所有的表单类都是作为django.forms.form的子类创建的。包括ModelForm
关于表单系统主要分为两类,
基于django.forms.Form:所有表单类的父类
基于django.forms.ModelForm: 可以和模型类绑定的Form
/hello/urls.py
from django.conf.urls import url
from hello import views
urlpatterns = [
url(r'^hello/$', views.hello,{'a':123}),
url(r'^test/$', views.test),
url(r'^testbase/$', views.test1),
url(r'^add_publisher/$', views.add_publisher,name='add_publisher'),
]
hello/views.py中增加函数
from hello.models import Publisher
.......
def add_publisher(request):
if request.method == 'POST':
# 如果是POST提交,去接受用户提交的数据
name = request.POST.get('name')
address = request.POST.get('address')
city = request.POST.get('city')
state_province = request.POST.get('state_province')
country = request.POST.get('country')
website = request.POST.get('website')
Publisher.objects.create(
name = name,
address = address,
city = city,
state_province = state_province,
country = country,
website = website,
)
return HttpResponse("添加出版社成功")
else:
# 否则将传输的数据打印
return render(request,'add_publisher.html',locals())
templates目录下增加add_publisher.html
<html lang="en">
<head>
<meta charset="UTF-8">
<title>添加出版社信息title>
head>
<body>
<form action="{% url 'add_publisher' %}" method="post" >
{% csrf_token %}
名称:<input type="text" name="name"><br>
地址:<input type="text" name="address"><br>
城市:<input type="text" name="city"><br>
省份:<input type="text" name="state_province"><br>
国家:<input type="text" name="country"><br>
网站:<input type="text" name="website"><br>
<input type="submit",name="提交"><br>
form>
body>
html>
/hello/urls.py
from django.conf.urls import url
from hello import views
urlpatterns = [
url(r'^hello/$', views.hello,{'a':123}),
url(r'^test/$', views.test),
url(r'^testbase/$', views.test1),
url(r'^add_publisher/$', views.add_publisher,name='add_publisher'),
]
hello/forms.py
from django import forms
class PublisherForm(forms.Form):
# label标签代表的是在界面上显示的信息,默认情况下显示的英文
name = forms.CharField(label='姓名')
address = forms.CharField(label='地址')
city = forms.CharField(label='城市')
state_province = forms.CharField(label='省份')
country = forms.CharField(label='国家')
website = forms.URLField(label='网站')
hello\view.py
from hello.forms import PublisherForm
from hello.models import Publisher
def add_publisher(request):
if request.method == 'POST':
# 如果是POST提交,去接受用户提交的数据
# 使用Django_form
publisher_form = PublisherForm(request.POST)
if publisher_form.is_valid():
Publisher.objects.create(
name = publisher_form.cleaned_data['name'],
address = publisher_form.cleaned_data['address'],
city = publisher_form.cleaned_data['city'],
state_province = publisher_form.cleaned_data['state_province'],
country = publisher_form.cleaned_data['country'],
website = publisher_form.cleaned_data['website'],
)
return HttpResponse("添加出版社成功")
else:
# 否则将传输的数据打印
publisher_form = PublisherForm()
return render(request,'add_publisher.html',locals())
templates目录下增加add_publisher.html
<html lang="en">
<head>
<meta charset="UTF-8">
<title>添加出版社信息title>
head>
<body>
<form action="{% url 'add_publisher' %}" method="post" >
{% csrf_token %}
{{ publisher_form.as_p }} // 将view.py中创建的表单对象传输到模版中,表单中的字段会自动生成,as_p表示的是输出的格式使用p>标签
<input type="submit" name="提交"><br>
form>
body>
html>
/hello/urls.py
from django.conf.urls import url
from hello import views
urlpatterns = [
url(r'^hello/$', views.hello,{'a':123}),
url(r'^test/$', views.test),
url(r'^testbase/$', views.test1),
url(r'^add_publisher/$', views.add_publisher,name='add_publisher'),
]
hello/forms.py
from django import forms
from hello.models import Publisher
class PublisherForm(forms.ModelForm):
class Meta:
model = Publisher
exclude = ("id",)
hello\view.py
from hello.forms import PublisherForm
from hello.models import Publisher
def add_publisher(request):
if request.method == 'POST':
# 如果是POST提交,去接受用户提交的数据
# 使用Django ModelForm
publisher_form = PublisherForm(request.POST)
if publisher_form.is_valid():
publisher_form.save()
return HttpResponse("添加出版社成功")
else:
# 否则将传输的数据打印
publisher_form = PublisherForm()
return render(request,'add_publisher.html',locals())
templates目录下增加add_publisher.html
<html lang="en">
<head>
<meta charset="UTF-8">
<title>添加出版社信息title>
head>
<body>
<form action="{% url 'add_publisher' %}" method="post" >
{% csrf_token %}
{{ publisher_form.as_p }} // 将view.py中创建的表单对象传输到模版中,表单中的字段会自动生成,as_p表示的是输出的格式使用p>标签
<input type="submit" name="提交"><br>
form>
body>
html>
Django官网
理解Django里的MTV开发模式
Django 1.8 中文站点
Django 1.11 中文站点