http://docs.30c.org/djangobook2
MVC 设计模式
首先,我们分成4个Python的文件,(models.py ,views.py , urls.py ) 和html模板文件 (latest_books.html )
-
models.py 文件主要用一个 Python 类来描述数据表。 称为 模型(model) 。 运用这个类,你可以通过简单的 Python 的代码来创建、检索、更新、删除 数据库中的记录而无需写一条又一条的SQL语句。
-
views.py文件包含了页面的业务逻辑。 latest_books()函数叫做视图。
-
urls.py 指出了什么样的 URL 调用什么的视图。 在这个例子中 /latest/ URL 将会调用 latest_books()这个函数。 换句话说,如果你的域名是example.com,任何人浏览网址http://example.com/latest/将会调用latest_books()这个函数。
-
latest_books.html 是 html 模板,它描述了这个页面的设计是如何的。 使用带基本逻辑声明的模板语言,如{% for book in book_list %}
结合起来,这些部分松散遵循的模式称为模型-视图-控制器(MVC)。 简单的说, MVC 是一种软件开发的方法,它把代码的定义和数据访问的方法(模型)与请求逻辑 (控制器)还有用户接口(视图)分开来。
Django 里更关注的是模型(Model)、模板(Template)和视图(Views),Django 也被称为 MTV 框架 。在 MTV 开发模式中:
-
M 代表模型(Model),即数据存取层。 该层处理与数据相关的所有事务: 如何存取、如何验证有效性、包含哪些行为以及数据之间的关系等。
-
T 代表模板(Template),即表现层。 该层处理与表现相关的决定: 如何在页面或其他类型文档中进行显示。
-
V 代表视图(View),即业务逻辑层。 该层包含存取模型及调取恰当模板的相关逻辑。 你可以把它看作模型与模板之间的桥梁。
Django基本配置
Python的WEB框架有Django、Tornado、Flask 等多种,Django相较与其他WEB框架其优势为:大而全,框架本身集成了ORM、模型绑定、模板引擎、缓存、Session等诸多功能
1、安装:
方式一、pip3 install django
方式二、官网下载
解压
python3 setup.py install
# 添加环境变量 C:Python3Scripts
2、基本操作:
- 创建project
先进入自己指定的目录
django-admin startproject mysite
- 创建app
cd mysite
python3 manage.py startapp cmdb
python3 manage.py startapp monitor
mysite对应的目录结构
- mysite (配置文件)
-init
-settings 配置文件
-urls URL对应关系
-wsgi 遵循WSIG规范,uwsgi+nginx
- manage.py (管理Project)
- app(cmdb)
- models.py 数据库操作
- admin.py 配置Django自带的后台管理
- apps.py 当前app的配置
- tests.py 单元测试
- views.py 做业务处理...
Django里面没封装socket,当进行socket数据交互时要用到wsgi,生产环境下一般用第三方模块uwsgi和nginx就可以把Django程序跑起来
- 创建templates目录
放html文件
需要在settings.py中加上
'DIRS': [os.path.join(BASE_DIR,'templates')],
- 编辑url.py view.py
url是路由系统,每个url对应view函数处理业务
view.py 业务处理
1、return render(request,模板路径,{'key':'value'})
2、return redirect(url) 跳转
3、return HttpResponse('ok')
- 运行
cd mysite
python3 manage.py runserver 127.0.0.1:8000
1.urls.py下面指定url,一个url对应一个函数 from cmdb import view
2.view.py下面写函数,return的html会去templates目录下找
3.settings.py指定了html在templates目录下,如果POST的方式发送,这行需要注释,否则forbidden
# 'django.middleware.csrf.CsrfViewMiddleware',
用户在浏览器中输入url,看到页面展示,整个流程
url.py中匹配对应的路由系统,去view.py中找对应的函数处理,默认method=get,返回templates中的html。
静态文件(css,js,图片)
创建statics文件夹(文件夹名字随意)
settings.py最后加上
STATIC_URL = '/static/' STATICFILES_DIRS = ( os.path.join(BASE_DIR,'statics'),#这里面的路径一定是创建的文件
os.path.join(BASE_DIR,'static'),#如果statics和static下面都有相同的js,优先执行statics的,static下面的不执行 )
css
创建commons.css
<link rel="stylesheet" href="/static/commons.css">
js
创建commons.js,记得把jquery也放在此目录下
{% load staticfiles %}#放在html最上面
<script src="{% static "jquery-1.12.4.js" %}"></script>
<script src="{% static "commons.js"%}"></script>
django数据库操作
类 --> 数据库的表
字段 --> 列
对象 --> 一行数据
创建数据库表sqlite
models.py
class UserInfo(models.Model): nid = models.AutoField(primary_key=True)
user_group = models.ForeignKey('UserGroup') username = models.CharField(max_length=32) pwd = models.CharField(max_length=64) age = models.IntegerField()
class UserGroup(models.Model):
uid = models.AutoField(primary_key=True)
caption = models.CharField(max_length=64)
*需要在settings.py下 INSTALLED_APPS加上app名字,否则不能创建表
termail下执行
python3 manage.py makemigrations
python3 manage.py migrate
需要注意的是,在创建完数据库后,UserInfo表中会出现user_group_id的字段,user_group存在的,代表UserGroup这个对象
在view.py中,能通过user_group访问对象的属性
obj = models.UserInfo.objects.all()
for row in obj:
row.user_group.uid
row.user_group.caption
连接mysql
*需要自己先创建数据库
create database day19 charset utf8;
*django连接mysql用的是MySqlDB,如果用的是python3的话,需要在配置目录的init.py中加上:
import pymysql pymysql.install_as_MySQLdb()
settings.py
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'day19', 'USER': 'root', 'PASSWORD': 'centos', 'HOST': '192.168.147.147', 'PORT': '3306', } }
数据库基本操作
a. 查
models.tb.objects.all()
models.tb.objects.filter(nid=1)
models.tb.objects.filter(nid=1).first()
b. 增
1.models.tb.objects.create(...)
2.
obj = models.tb(...)
obj.save()
c. 删
models.tb.objects.all().delete()
models.tb.objects.filter(nid=1).delete()
d. 改
models.tb.objects.all().update(...)
models.tb.objects.filter(nid=1).update(...)
路由系统urls.py
1、单一路由对应
1
|
url(r '^index$' , views.index), |
2、基于正则的路由
1
2
|
url(r '^index/(d*)' , views.index), url(r '^manage/(?P<name>w*)/(?P<id>d*)' , views.manage), |
利用 url(r'^edit_user_new-(?P<nnid>d+).html$', views.edit_user_new)实现编辑,url中带.html以为是静态文件,权重会高点。
整个流程
user.html中<a href="/edit_user_new-{{ row.nid }}.html">新编辑</a>
新编辑跳转到这个url,url.py中加url(r'^edit_user_new-(?P<nnid>d+).html$', views.edit_user_new)
views.py中def edit_user_new(request,nnid)需要带上参数,method是GET
编辑完之后提交,action="/edit_user_new-{{ obj.nid }}.html"
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' ), |
h1就代指这个url
<form method="POST" action="{% url 'nnn' nnid=obj.nid %}">
设置名称之后,可以在不同的地方调用,如:
- 模板中使用生成URL {% url 'h2' 2012 %}
- 函数中使用生成URL reverse('h2', args=(2012,)) 路径:django.urls.reverse
- Model中使用获取URL 自定义get_absolute_url() 方法
5、根据app对路由规则进行分类
1
|
url(r '^app01/' ,include( 'app01.urls' )), |
当访问127.0.0.1:8000/app01/user时,先去匹配前面的app01,然后去app01下面的url.py中匹配
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 'app01:detail' pk=12 pp=99 %}
django中的路由系统和其他语言的框架有所不同,在django中每一个请求的url都要有一条路由映射,这样才能将请求交给对一个的view中的函数去处理。其他大部分的Web框架则是对一类的url请求做一条路由映射,从而是路由系统变得简洁。
视图函数views.py
获取请求信息:
request.POST {'username':'root'..}
request.GET
request.FILES
obj = request.FILES.get(input里面的name)
文件名 obj.name
for line in obj.chunks()
request.method
request.body = username=root;age=18;gender=male
响应结果:
return HttpReponse(..)
return render(request,'path/a.html',{})
return redirect('http://www.baidu.com')
模板
模板中也有自己的语言,该语言可以实现数据展示
- {{ item }}
- {% for item in item_list %} <a>{{ item }}</a> {% endfor %}
forloop.counter
forloop.first
forloop.last - {% if ordered_warranty %} {% else %} {% endif %}
- extend
母板:{% block title %}{% endblock %}
子板:{% extends "base.html" %}
{% block title %}新内容{% endblock %}
- include
子板:{% extends "base.html" %}
{% block title %}新内容{%include 'small.html'%}{% endblock %}
- 字典.key 列表.索引
- 帮助方法:
{{ item.event_start|date:"Y-m-d H:i:s"}}
{{ bio|truncatewords:"30" }}
{{ my_list|first|upper }}
{{ name|lower }}
3、自定义simple_tag(页面展示)
a、在app中创建templatetags模块
b、创建任意 .py 文件,如:xx.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
#!/usr/bin/env python #coding:utf-8 from django import template from django.utils.safestring import mark_safe register = template.Library() @register .simple_tag def my_simple_time(v1,v2,v3): return v1 + v2 + v3 @register .simple_tag def my_input( id ,arg): result = "<input type='text' id='%s' class='%s' />" % ( id ,arg,) return mark_safe(result) |
from django import template from django.utils.safestring import mark_safe register = template.Library() @register.filter() def anyway(value,num): return 'dassssssssssssssssssssssssssss'+value+str(num) @register.filter() def ya(value,v): temp = "<a href='http://www.baidu.com?t=%s'>%s</a>"%(v,value) return mark_safe(temp)
c、在使用自定义simple_tag的html文件中导入之前创建的 xx.py 文件名
1
|
{ % load xx % } |
d、使用simple_tag
1
2
|
{ % my_simple_time 1 2 3 % } { % my_input 'id_username' 'hide' % } |
e、在settings中配置当前app,不然django无法找到自定义的simple_tag
1
2
3
4
5
6
7
8
9
|
INSTALLED_APPS = ( 'django.contrib.admin' , 'django.contrib.auth' , 'django.contrib.contenttypes' , 'django.contrib.sessions' , 'django.contrib.messages' , 'django.contrib.staticfiles' , 'app01' , ) |
4、自定义filter(在if条件中做条件时)
{{ summary|anyway:8 }}
在页面仅显示内容用simple_tag
cookie
- 是用户浏览器上的一个键值对
- 设置超时时间
利用cookie可实现:
- 登录验证
- 页面显示条数
- 拖动位置..
两大忌讳:
- 敏感信息
- 简单
1、获取Cookie:
1
2
3
4
5
6
|
request.COOKIES.get( 'key')
request.get_signed_cookie(key, default = RAISE_ERROR, salt = '', max_age = None ) 参数: default: 默认值 salt: 加密盐 max_age: 后台控制过期时间 |
2、设置Cookie:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
rep = HttpResponse(...) 或 rep = render(request, ...) 或 rep = redirect(url) rep.set_cookie(key,value,...) rep.set_signed_cookie(key,value,salt = '加密盐' ,...) 参数: key, 键 value = '', 值 max_age = None , 超时时间 expires = None , 超时时间(IE requires expires, so set it if hasn't been already.) path = '/' , Cookie生效的路径, / 表示根路径,特殊的:跟路径的cookie可以被任何url的页面访问 domain = None , Cookie生效的域名 secure = False , https传输 httponly = False 只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖) |
由于cookie保存在客户端的电脑上,所以,JavaScript和jquery也可以操作cookie。
1
2
|
<script src = '/static/js/jquery.cookie.js' >< / script> $.cookie( "list_pager_num" , 30 ,{ path: '/' }); |
设置cookie
obj = redirect('/app02/groups')
obj.set_cookie(key='user_name',value=u,max_age=10)
return obj
获取cookie
request.COOKIES.get('user_name')
session
session依赖cookie
SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默认)
SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径(默认)
SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默认)
SESSION_COOKIE_SECURE = False # 是否Https传输cookie(默认)
SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输(默认)
SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默认)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期(默认)
SESSION_SAVE_EVERY_REQUEST = False
生成随机字符串保存在客户端,服务器端保存形式字典,{'随机字符串':{'username':'root','password':'pwd'}}
request.session['user'] = u
v = request.session.get('user')
装饰器+session实现登录认证
from django.shortcuts import render from django.shortcuts import redirect from django.shortcuts import HttpResponse from app01 import models # Create your views here. def auth(func): def inner(request,*args,**kwargs): v = request.session.get('user') if not v: return redirect('/app02/login') else: return func(request,*args,**kwargs) return inner @auth # group = auth(group) def group(request): # # v = request.session.get('username') # if not v: # return redirect('/app02/login') # else: return render(request,'groups.html') @auth def user(request): return render(request,'user.html') def login(request): if request.method == 'GET': return render(request,'login.html') elif request.method == 'POST': u = request.POST.get('username') p = request.POST.get('pwd') v = models.UserInfo.objects.filter(username=u,pwd=p).first() if v: obj = redirect('/app02/groups') # obj.set_cookie(key='user',value=u,max_age=10) request.session['user'] = u return obj else: return render(request, 'login.html',{'msg':'用户名或密码错误'})
主要加了个auth函数,auth函数功能,取session,有执行func,没有的话跳转到login