Python的WEB框架有Django、Tornado、Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了ORM、模型绑定、模板引擎、缓存、Session等诸多功能。
基本配置
跨文件导入模型注意事项:
1、当从其他应用的model导入模型时,会遇到循环导入错误。可以django.db.models.loading.get_model
用来解决这个问题。
from django.db.models.loading import get_model
Libro = get_model('libros', 'Libro')
class Perfil(models.Model):
usuario = models.OneToOneField(User, null=True)
actualmente_leyendo = models.ForeignKey(Libro, related_name="actualmente_leyendo")
或者更好的是,不要导入模型,只需<app>.<model_name>
在引用其他应用程序中的模型时传递带有格式的字符串
class Perfil(models.Model):
usuario = models.OneToOneField(User, null=True)
actualmente_leyendo = models.ForeignKey('libros.Libro', related_name="actualmente_leyendo
2、makemigrations,migrate的时候指定app名(先执行带有user模块的app模型),如:python manage.py makemigrations appname,python manage.py migrate appname
3、再执行一遍python manage.py migrate
一、创建django程序
- 添加环境变量,python中有个script文件夹
- 终端命令:django-admin startproject sitename
- IDE创建Django程序时,本质上都是自动执行上述命令
- 进入创建的工程名字文件夹
- 执行:python manage.py runserver ip:端口(例如:127.0.0.1:8800)
例如:
wsgi是一套规则,一个接口,
mysite
-mysite
- -init-.py
- settings.py 配置文件:支持缓存,连接数据库,做静态文件处理,找模板,加密的加严都是这个文件
- urls.py url对应关系,用户访问django程序,进行匹配,如果有就去提取,
- wsgi.py 遵循WSGI规范,以后上线的时候会变成uwsgi+nginx才能跑起来,wsgi是一套规则,一个接口,
-db.sqlite3
-manage.py 管理Django程序
其他管理Django的常用命令:
python manage.py runserver 0.0.0.0
python manage.py startapp appname
python manage.py syncdb
python manage.py makemigrations
python manage.py migrate
python manage.py createsuperuser
python manage.py
python manage.
网站设计模型:
-抽屉网
-配置、数据库
-主站app
-后台管理app
创建app
python manage.py startapp cmdb
python manage.py startapp openstack
.
创建完app之后,可以把自己写的函数放在相关app文件夹下面的view.py文件里面
二、程序目录
wsgi:帮助django自动创建socket,其实是一套规则接口,其可以适应多种socket服务:django系统内部就是调用的wsgiref模块,一般上线的时候会变成uwgi第三方模块,需要自己安装,现在只是在测试调试阶段,namewsgi支持一下服务:
server_names
=
{
'cgi'
: CGIServer,
'flup'
: FlupFCGIServer,
'wsgiref'
: WSGIRefServer,
'waitress'
: WaitressServer,
'cherrypy'
: CherryPyServer,
'paste'
: PasteServer,
'fapws3'
: FapwsServer,
'tornado'
: TornadoServer,
'gae'
: AppEngineServer,
'twisted'
: TwistedServer,
'diesel'
: DieselServer,
'meinheld'
: MeinheldServer,
'gunicorn'
: GunicornServer,
'eventlet'
: EventletServer,
'gevent'
: GeventServer,
'geventSocketIO'
:GeventSocketIOServer,
'rocket'
: RocketServer,
'bjoern'
: BjoernServer,
'auto'
: AutoServer,
app里面的文件详解:
1、配置作用的文件:
-migrations文件夹:数据库操作记录,在django创建修改数据库的时候,就会在这个文件生成记录,记录操作,只记录修改表结构的记录
-admin django为我们提供的后台管理
-app 配置当前app
-models 创建数据库表ORM,写指定的类,再通过命令执行可以创建数据库结构
-tests 单元测试
2、写代码的文件:
-views 写对app管理的业务代码
三、配置文件,当创建了工程的时候就要先执行下面的操作
1、数据库
1、数据库
1
2
3
4
5
6
7
8
9
10
|
DATABASES
=
{
'default'
: {
'ENGINE'
:
'django.db.backends.mysql'
,
'NAME'
:
'dbname'
,
'USER'
:
'root'
,
'PASSWORD'
:
'xxx'
,
'HOST'
: '',
'PORT'
: '',
}
}
|
1
2
3
4
5
6
|
# 由于Django内部连接MySQL时使用的是MySQLdb模块,而python3中还无此模块,所以需要使用pymysql来代替
# 如下设置放置的与project同名的配置的 __init__.py文件中
import
pymysql
pymysql.install_as_MySQLdb()
|
2、模版
1
2
3
|
TEMPLATE_DIRS
=
(
os.path.join(BASE_DIR,
'templates'
),
)
|
3、静态文件(在settings文件的最下面行设置)
1
2
3
|
STATICFILES_DIRS
=
(
os.path.join(BASE_DIR,
'static'
),
) #记得后面加逗号,不加会报错
|
下面是提示用户输入信息错误出现提示信息实例:
工程文件显示图片实例:
views文件代码:
from __future__ import unicode_literals
# from django.shortcuts import render
from django.shortcuts import redirect
# Create your views here.
from django.shortcuts import render
def login(request):
# 先指定error_msg为空,这样就不会显示要提示的信息
error_msg= ''
if request.method=='POST':
user=request.POST.get('user',None)
pwd=request.POST.get('pwd',None)
if user=='root' and pwd=='123':
return redirect('https://www.baidu.com') #重定向用redirect方法
else:
error_msg='用户名密码错误'
# 第三个参数是用来和html文件里面的span标签对应,用户密码错误的时候,在客户端浏览器提示信息,用来替换需要输出给屏幕的信息
return render(request,'login.html',{'error_msg':error_msg})
urls文件代码:
from django.conf.urls import url
from django.contrib import admin
from cmdb import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^login', views.login), #注意,这里的r"^login"后面没有/,因为django会自动添加,如果这里后面添加了/,
那么在login.html文件的<form action="/login" method="post"> 中的action参数后面也要加上/变成"/login/".
]
templates下面的login.html文件代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="/static/comments.css">
<style>
lable{
text-align: right;
display: inline-block;
width: 80px;
}
</style>
</head>
<body>
<form action="/login" method="post">
<p>
<lable for="username">用户名:</lable>
{ #提交表单的时候,input表单必须制定name,不然POST的时候无法获取对应信息#}
<input id='username' type="text" name="user" />
</p>
<p>
<lable for="lpassword">密码:</lable>
<input id='password' type="password" name="pwd" />
<input type="submit" value="提交">
{ #下面标签用的两个{}是为了在客户端调用网页的时候,login函数可以调用并替换其内容#}
<span style="color: red">{{ error_msg }}</span>
</p>
</form>
<script src="/static/jquery-3.3.1.min.js"></script>
</body>
</html>
知识梳理:
对于文件的接收,用request.FILES.get('file标签的name'),注意:form标签要做特殊设置
obj=request.FILES.get('文件名')
boj.name
f=open(obj.name,mode='wb')
for item in obj.chunks():
f.write(item)
f.close
对于checkbox等多选的内容,用request.getlist(),
变量里面如果有字典和字符串等,字典就用.key,字符串就用.下标(.0/.1)这种形式
if语句也可以嵌套在for循环里面用
4、FBV和CBV,今后的工程开发中,两种方法都可以使用;
FBV: function base view 通过函数实现
url.py
index-->函数名
view.py
def 函数(request):
...
CBV:通过类class实现
urls中的代码:
from app001 import views
urlpatterns = [
url(r'^home', views.Home.as_view()), #固定格式,必须这么写
]
views中的代码:
from django.views import View
class Home(View):
'''
类的执行过程:首先urls里面的是home选择的话,先执行View里面的dispatch方法,然后选择http_method_names里面的方法(比如get和post)执行,
将执行的结果再通过dispatch给返回,所以和浏览器客户交流的数据其实是通过dispatch中间调度来通信的。
'''''
# http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'] 其实view里面有这么多调用方法
#下面是自己来定义dispatch方法,可以自己添加某些功能,这里实例中没有做什么功能的修改,只是作为演示。
def dispatch(self, request, *args, **kwargs):
print('before')
# 调用父类中的dispatch方法,
result=super(Home,self).dispatch(request, *args, **kwargs)
print('after')
return result
def get(self,request):
print(request.method)
return render(request,'home.html')
def post(self,request):
print(request.method)
return render(request, 'home.html')
5、装饰器知识点:其他:在循环字典的时候,在html中有key,values,items方法来循环,注意这里和python不一样的是后面不需要加( ),
6、装饰器实现用户登陆认证(结合cookie):
路由系统,url
1、单一路由对应
1
|
url(r
'^index$'
, views.index),
|
2、基于正则的路由
url代码:
1
2
|
url(r
'^index/(\d*)'
, views.index),
url(r
'^manage/(?P<name>\w*)/(?P<id>\d*)'
, views.manage),#这种方式是按照位置参数传递值的,推荐用这种方式
|
views代码:
def detail(request,nid):
# n=request.GET.get('nid')
# info=USER_LIST[n]
# # return HttpResponse(n)
# return render(request,'detail.html',{'info':info})
a=USER_LIST[nid]
return render(request,'detail.html',{"info":a})
3、添加额外的参数
1
|
url(r
'^manage/(?P<name>\w*)'
, views.manage,{
'id'
:
333
}),
|
4、为路由映射设置名称
1
2
|
url(r
'^home'
, views.home, name
=
'h1'
),
url(r
'^index/(\d*)'
, views.index, name
=
'h2'
),
|
设置名称之后,可以在不同的地方调用,如:
- 模板中使用生成URL {% url 'h2' 2012 %}
- 函数中使用生成URL reverse('h2', args=(2012,)) 路径:django.urls.reverse
- Model中使用获取URL 自定义get_absolute_url() 方法
class NewType(models.Model):
caption = models.CharField(max_length=16)
def get_absolute_url(self):
"""
为每个对象生成一个URL
应用:在对象列表中生成查看详细的URL,使用此方法即可!!!
:return:
"""
# return '/%s/%s' % (self._meta.db_table, self.id)
# 或
from django.urls import reverse
return reverse('NewType.Detail', kwargs={'nid': self.id})class NewType(models.Model): caption = models.CharField(max_length=16) def get_absolute_url(self): """ 为每个对象生成一个URL 应用:在对象列表中生成查看详细的URL,使用此方法即可!!! :return: """ # return '/%s/%s' % (self._meta.db_table, self.id) # 或 from django.urls import reverse return reverse('NewType.Detail', kwargs={'nid': self.id})
获取请求匹配成功的URL信息:request.resolver_match
补充:
name
对url路由的关系进行命名,以后可以根据名称生成自己想要的url
url(r'^sdfas/', views.detail,name='i1')
url(r'^sdfas/(\d+)/(\d+)/', views.detail,name='i2')
url(r'^sdfas/(?p<nid>\d+)/(?p<nid>\d+)/', views.detail,name='i3')
def func(request,*args,**kwargs):
from django.urls import reverse
url1=reverse('i1') #相当于sdfas/
url1=reverse('i1',args=(1,2)) #相当于sdfas/1/2
url1=reverse('i1',kwargs={'pid':1,'nid':2}) #相当于sdfas/1/9
xxx.html模板语言action=:
{% url "i1" %} #相当于sdfas/
{% url "i2" 1 2 %} #相当于sdfas/1/2
{% url "i2" pid=1 nid=9 %} #相当于sdfas/1/9
注意:
当前的URL:request.path_info
5、根据app对路由规则进行分类
1
|
url(r
'^web/'
,include(
'web.urls'
)),
|
6、命名空间
a. project.urls.py
1
2
3
4
5
6
|
from
django.conf.urls
import
url,include
urlpatterns
=
[
url(r
'^a/'
, include(
'app01.urls'
, namespace
=
'author-polls'
)),
url(r
'^b/'
, include(
'app01.urls'
, namespace
=
'publisher-polls'
)),
]
|
b. app01.urls.py
1
2
3
4
5
6
7
|
from
django.conf.urls
import
url
from
app01
import
views
app_name
=
'app01'
urlpatterns
=
[
url(r
'^(?P<pk>\d+)/$'
, views.detail, name
=
'detail'
)
]
|
c. app01.views.py
1
2
3
|
def
detail(request, pk):
print
(request.resolver_match)
return
HttpResponse(pk)
|
以上定义带命名空间的url之后,使用name生成URL时候,应该如下:
- v = reverse('author-polls:detail', kwargs={'pk':11})
- {% url 'author-polls:detail' pk=12 pp=99 %}
django中的路由系统和其他语言的框架有所不同,在django中每一个请求的url都要有一条路由映射,这样才能将请求交给对一个的view中的函数去处理。其他大部分的Web框架则是对一类的url请求做一条路由映射,从而是路由系统变得简洁。
注意,一般namespace主要用在不同页面要用到同一个app的同一个视图函数,而name主要用在同一个app不同的视图函数,这是两者的主要应用却别;
中间件
django 中的中间件(middleware),在django中,中间件其实就是一个类,在请求到来和结束后,django会根据自己的规则在合适的时机执行中间件中相应的方法。
在django项目的settings模块中,有一个 MIDDLEWARE_CLASSES 变量,其中每一个元素就是一个中间件,如下图。
与mange.py在同一目录下的文件夹 wupeiqi/middleware下的auth.py文件中的Authentication类
里面的def定义的requeset和response名称是不能变的,类继承的类名也不能变;
这种操作适合对所有操作,也能进行黑名单、ip过滤的操作;
处了自定义上面2个方法,还可以加上下面4个方法
中间件中可以定义四个方法,分别是:
-
- process_request(self,request) #重要
- process_view(self, request, callback, callback_args, callback_kwargs) #重要 callback就是view函数,后面的args和kwargs就是view函数的参数
- process_template_response(self,request,response) 如果有render函数返回,才执行这条,例如下面:
- process_exception(self, request, exception) 如果views函数返回有错误,就会执行,然后再继续response,返回给用户,exception是异常信息
- process_response(self, request, response) #重要
以上方法的返回值可以是None和HttpResonse对象,如果是None,则继续按照django定义的规则向下执行,如果是HttpResonse对象,则直接将该对象返回给用户。
自定义中间件
1、创建中间件类
1
2
3
4
5
6
7
8
9
10
11
12
|
class
RequestExeute(
object
):
def
process_request(
self
,request):
pass
def
process_view(
self
, request, callback, callback_args, callback_kwargs):
i
=
1
pass
def
process_exception(
self
, request, exception):
pass
def
process_response(
self
, request, response):
return
response
|
2、注册中间件
1
2
3
4
5
6
7
8
9
10
|
MIDDLEWARE_CLASSES
=
(
'django.contrib.sessions.middleware.SessionMiddleware'
,
'django.middleware.common.CommonMiddleware'
,
'django.middleware.csrf.CsrfViewMiddleware'
,
'django.contrib.auth.middleware.AuthenticationMiddleware'
,
'django.contrib.auth.middleware.SessionAuthenticationMiddleware'
,
'django.contrib.messages.middleware.MessageMiddleware'
,
'django.middleware.clickjacking.XFrameOptionsMiddleware'
,
'wupeiqi.middleware.auth.RequestExeute'
,
)
|
中间件执行流程(程序请求声明周期):
1、当用户发送请求的时候,先经过中间件的process_request(按照settings配置的中间件顺序执行),拿到客户端发送过来的request信息一层一层的传递;
2、在传递到最后一层中间件后,先做了urls关系映射的处理,然后中间件里面如果有process_view函数,就会转到process_vies函数里面也是一层一层的执行(这里就可以做参数错误处理、黑名单、ip过滤操作);
3、当中间件的所有process_view执行完了之后就会到达视图views执行相应的函数;
4、在服务端向客户端返回信息的时候,再经过process_exception,判断视图函数是否出现了执行错误,如果出现了执行错误,捕捉错误,返回给最靠近视图view的中间件的process_response函数(这里可以做抛出页面丢失、或者403等界面的处理),改变了process_response返回的信息后一层一层传递到客户端;
5、如果中间件没有定义process_exception函数,那么视图函数返回的信息就会直接经过中间件的process_response一层一层的向最外层传递信息,也可以在函数里面做操作,返回给用户自定义的字符串等信息,最后,信息一层一层传回给客户端的浏览器。
另外一个不重要的中间件函数是process_template_response(self,request,response) 如果有render函数返回,才执行这条,而且要render response,不然客户端接受不到数据,
admin
django amdin是django提供的一个后台管理页面,该管理页面提供完善的html和css,使得你在通过Model创建完数据库表之后,就可以对数据进行增删改查,而使用django admin 则需要以下步骤:
- 创建后台管理员
- 配置url
- 注册和配置django admin后台管理页面
1、创建后台管理员
1
|
python manage.py createsuperuser
|
2、配置后台管理url
1
|
url(r
'^admin/'
, include(admin.site.urls))
|
3、注册和配置django admin 后台管理页面
a、在admin中执行如下配置
1
2
3
4
5
6
7
8
|
from
django.contrib
import
admin
from
app01
import
models
admin.site.register(models.UserType)
admin.site.register(models.UserInfo)
admin.site.register(models.UserGroup)
admin.site.register(models.Asset)
|
b、设置数据表名称
1
2
3
4
5
6
|
class
UserType(models.Model):
name
=
models.CharField(max_length
=
50
)
class
Meta:
verbose_name
=
'用户类型'
verbose_name_plural
=
'用户类型'
|
c、打开表之后,设定默认显示,需要在model中作如下配置
1
2
3
4
5
|
class
UserType(models.Model):
name
=
models.CharField(max_length
=
50
)
def
__unicode__(
self
):
return
self
.name
|
1
2
3
4
5
6
7
8
9
10
11
12
|
from
django.contrib
import
admin
from
app01
import
models
class
UserInfoAdmin(admin.ModelAdmin):
list_display
=
(
'username'
,
'password'
,
'email'
)
admin.site.register(models.UserType)
admin.site.register(models.UserInfo,UserInfoAdmin)
admin.site.register(models.UserGroup)
admin.site.register(models.Asset)
|
d、为数据表添加搜索功能
1
2
3
4
5
6
7
8
9
10
11
12
|
from
django.contrib
import
admin
from
app01
import
models
class
UserInfoAdmin(admin.ModelAdmin):
list_display
=
(
'username'
,
'password'
,
'email'
)
search_fields
=
(
'username'
,
'email'
)
admin.site.register(models.UserType)
admin.site.register(models.UserInfo,UserInfoAdmin)
admin.site.register(models.UserGroup)
admin.site.register(models.Asset)
|
e、添加快速过滤
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
from
django.contrib
import
admin
from
app01
import
models
class
UserInfoAdmin(admin.ModelAdmin):
list_display
=
(
'username'
,
'password'
,
'email'
)
search_fields
=
(
'username'
,
'email'
)
list_filter
=
(
'username'
,
'email'
)
admin.site.register(models.UserType)
admin.site.register(models.UserInfo,UserInfoAdmin)
admin.site.register(models.UserGroup)
admin.site.register(models.Asset)
|
更多:http://docs.30c.org/djangobook2/chapter06/