Python自动化运维之27、Django(一)
一、概述
1、什么是框架?
框架,即framework,特指为解决一个开放性问题而设计的具有一定约束性的支撑结构,使用框架可以帮你快速开发特定的系统,简单说就是使用别人搭好的舞台,你来做表演。
2、常见的Python Web框架:
Full-Stack Frameworks(全栈框架、重量级框架):
Django、web2py、TurboGears、Pylons、...
Non Full-Stack Frameworks(非全栈框架、轻量级的框架):
tornado、Flask、Bottle、web.py、Pyramid、...
详见:https://wiki.python.org/moin/WebFrameworks
3、这么多框架,如何选择?
a、根据项目需求去选择。
b、根据框架的特点去选择
国内常用:django、tornado、flask、bottle,Django相较与其他WEB框架其优势为:大而全,框架本身集成了ORM、模型绑定、模板引擎、缓存、Session等诸多功能。
Django官网:https://docs.djangoproject.com/en/1.11/
二、基本配置
1、创建django程序
- 终端命令:django-admin startproject sitename
- IDE创建Django程序时,本质上都是自动执行上述命令
常用命令:
- django-admin startproject sitename
- django-admin startapp appname
- python manage.py runserver 0.0.0.0:8000
- python manage.py makemigrations
- python manage.py migrate
- python manage.py createsuperuser
- python manage.py changepassword
- python manage.py clearsessions
其他命令:
- python manage.py shell #进入django shell
- python manage.py dbshell #进入django dbshell
- python manage.py check #检查django项目完整性
- python manage.py flush #清空数据库
- python manage.py compilemessages #编译语言文件
- python manage.py makemessages #创建语言文件
- python manage.py showmigrations #查看生成的数据库同步脚本
- python manage.py sqlflush #查看生成清空数据库的脚本
- python manage.py sqlmigrate #查看数据库同步的sql语句
- python manage.py dumpdata #导出数据
- python manage.py loaddata #导入数据
- python manage.py diffsettings #查看你的配置和django默认配置的不同之处
其他命令
2、程序目录,django 1.9以上templates会自动创建
3、配置文件
(1)APP配置,后续创建app需要添加进这里
- INSTALLED_APPS = [
- 'django.contrib.admin',
- 'django.contrib.auth',
- 'django.contrib.contenttypes',
- 'django.contrib.sessions',
- 'django.contrib.messages',
- 'django.contrib.staticfiles',
- 'cmdb',
- ]
(2)数据库配置,默认是sqlite3
- DATABASES = {
- 'default': {
- 'ENGINE': 'django.db.backends.mysql',
- 'NAME':'dbname',
- 'USER': 'root',
- 'PASSWORD': '123456',
- 'HOST': '',
- 'PORT': '',
- }
- }
由于Django内部连接MySQL时使用的是MySQLdb模块,而python3中还无此模块,所以需要使用pymysql来代替
如下设置放置的与project同名的配置的 __init__.py文件中
- import pymysql
- pymysql.install_as_MySQLdb()
(3)模版配置
templates是用于放置模板html,在django1.9以上中会自动创建并设置
- TEMPLATES = [
- {
- 'BACKEND': 'django.template.backends.django.DjangoTemplates',
- 'DIRS': [os.path.join(BASE_DIR, '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',
- ],
- },
- },
- ]
(4)静态文件配置
static是自己创建的目录用于放置css,js,image,需要在settings中设置这个目录
- STATIC_URL = '/static/'
- # 这个路径是对应 src="/static/ 这个的别名, 如果这个路径改为 STATIC_URL = '/abc/' 那么<script src="/abc/jquery-2.2.4.min.js"></script>
- STATICFILES_DIRS = (
- os.path.join(BASE_DIR,'static'),
- )
- <script src="/static/jquery-2.2.4.min.js"></script>
MEDIA是自己创建的目录用于上传图片和文件
MEDIA_ROOT:是本地路径的绝对路径,一般是这样写
MEDIA_URL:是指从浏览器访问时的地址前缀
- MEDIA_URL = '/upload/'
- MEDIA_ROOT = os.path.join(BASE_DIR,'upload')
from django.conf.urls import url
from django.contrib import admin
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^upload/(?P<path>.*)$', "django.views.static.serve", {"document_root": settings.MEDIA_ROOT,}), #以前是这种
] + static(settings.MEDIA_URL, document_root = settings.MEDIA_ROOT) #现在的版本应该是这样
- from django.db import models
- class Article(models.Model):
- '''
- 图片上传的路径就会在/upload/article/2016/09/23/a1.jpg
- 浏览器访问:http://127.0.0.1:8000/upload/article/2016/09/23/a1.jpg
- '''
- head_img = models.ImageField(max_length=200,upload_to='article/%Y/%m/%d',\
- default='article/default.png',null=True,blank=True)
models.py
文件上传类似,前端form属性要有enctype='multipart/form-data',models中的字段为models.FileField(max_length='',upload_to='')
三、路由系统详解
- urlpatterns = [
- url(正则表达式, views视图函数, 参数, 别名name=""),
- url(r'^index/(\d*)', views.index, {'id':333}, name="test")
- ]
- #别名name="test" 那么前端比如form <form action="{% url "test" %}" method="post"></form> 这样提交就会交给 views.index这个方法
1、每个路由规则对应一个view中的函数,前端传的任何数据类型到后端都是字符串
- # 有分组后端view即需要参数接收
- url(r'^index/(\d*)', views.index),
- url(r'^list/(\d*)/(\d*)/$', views.list),
- url(r'^manage/(?P<name>\w*)/(?P<id>\d*)', views.manage),
- url(r'^login/(?P<name>\w*)', views.login,{'id':333}),
- url(r'^login/(?P<id>[0-9]{4})', views.login,{'id':333}), #id:333会覆盖掉前面匹配到的值
- def index(request,id): # id形参的名字是随便定义的
- return render_to_response('index.html')
- def list(request,id1,id2): # id1,id2形参的名字是随便定义的
- return render_to_response('list.html')
- def manage(request,name,id): # name,id形参的名字是和(?P<name>\w*)/(?P<id>\d*)是一样的
- return render_to_response('index.html')
- def login(request,name,id): # name,id形参的名字是和(?P<name>\w*),{'id':}是一样的
- return render_to_response('login.html')
2、根据app对路由规则进行一次分类
- from django.conf.urls import include
- urlpatterns = patterns[
- url(r'^web/', include('web.url')),
- url(r'^app01/', include('app01.url')),
- ]
django中的路由系统和其他语言的框架有所不同,在django中每一个请求的url都要有一条路由映射,这样才能将请求交给对一个的view中的函数去处理。其他大部分的Web框架则是对一类的url请求做一条路由映射,从而是路由系统变得简洁。
通过反射机制,为django开发一套动态的路由系统Demo: 点击下载
四、views详解

.png)
1、HttpRequest:
(1)HttpRequest对象的属性:
- get_full_path():返回包含查询字符串的请求路径。例如, "/music/bands/the_beatles/?print=true"
- get():如果key对应多个value,get()返回最后一个value。
2、HttpResponse:
- >>> response = HttpResponse("Here's the text of the Web page.")
- >>> response = HttpResponse("Text only, please.", mimetype="text/plain")
- # 在HttpResponse对象上常用方法:render、render_to_response、redirect(重定向)
- >>> response = render(request,'index.html',{向模板传递的变量})
- >>> response = render_to_response('index.html',{向模板传递的变量})
- >>> response = redirect("http://www.baidu.com") 或者 redirect("/blog/py/login")
- # render与render_to_response区别在于第一个参数是否要request,所以就用render
- # 表单提交的时候render_to_response还需要添加 context_instance=RequestContext(request)否则会报csrf错误
更多详见:
更详细的有关request和response对象的介绍:
https://docs.djangoproject.com/en/1.11/ref/request-response/
五、模板详解
1、模版的执行
- return render(request,"index.html",{"name":"alex"})
- # "index.html是Template模板
- # {"name":"alex"}是上下文
HttpResponse模版的创建过程,对于模版,其实就是读取模版(其中嵌套着模版标签),
是通过Template,Context对象来创建渲染模板的,所以render已经封装了HttpResponse,Template,Context所以很简单
- def current_datetime(request):
- now = datetime.datetime.now()
- html = "<html><body>It is now %s.</body></html>" % now
- return HttpResponse(html)
手动嵌套变量到模板中
- from django import template
- t = template.Template('My name is {{ name }}.')
- c = template.Context({'name': 'Adrian'})
- print(t.render(c))
django通过模板语言将变量嵌套html中(一)
- import datetime
- from django import template
- import DjangoDemo.settings
- now = datetime.datetime.now()
- fp = open(settings.BASE_DIR+'/templates/Home/Index.html')
- t = template.Template(fp.read())
- fp.close()
- html = t.render(template.Context({'current_date': now}))
- return HttpResponse(html)
django通过模板语言将变量嵌套html中(二)
- from django.template.loader import get_template
- from django.template import Context
- from django.http import HttpResponse
- import datetime
- def current_datetime(request):
- now = datetime.datetime.now()
- t = get_template('current_datetime.html')
- html = t.render(Context({'current_date': now}))
- return HttpResponse(html)
django通过模板语言将变量嵌套html中(三)
- return render_to_response('Account/Login.html',data,context_instance=RequestContext(request))
- 注意:当数据POST的时候,Django做了跨站请求伪造
2、模版语言
模板中也有自己的语言,该语言可以实现数据展示
(1)模板取值
- # views函数返回的是字符串,通过{{ k1 }}获取字符串v1,前端引用的名字是k1
- return render('index.html',{'k1':'v1'}
- # views函数返回的是列表,通过{{ list.0 }}获取字符串11,{{ list.1 }}获取字符串22,前端引用的名字是list
- return render('index.html',{'list':[11,22,33,44]}
- # views函数返回的是字典,通过{{ dict.k1 }}获取字符串v1,{{ dict.k2 }}获取字符串v2,前端引用的名字是dict
- return render('index.html',{'dict':{'k1':'v1','k2':'v2'}}
- # views把全部变量传入前端,locals(),前端引用的名字直接是views中的变量名
- return render('index.html',locals()}
- # views把一个对象传入前端,前端通过obj.name,obj.age来取值
- def index(request):
- class Person():
- def __init__(self,name,age):
- self.name = name
- self.age = age
- s4 = Person("xiao",18)
- return render(request,"index.html",{"obj":s4})
(2)流程控制
- {% if a > b %}
- .......
- {% elif a == b %}
- .......
- {% else %}
- .......
- {% endif %}
(3)for循环
- {% for item in data %}
- {{ item }}
- {# 下面几个是特殊变量 #}
- forloop.counter {# 索引从1开始 #}
- forloop.counter0 {# 索引从0开始 #}
- forloop.first {# 是否是循环的第一个 #}
- forloop.last {# 是否是循环的最后一个 #}
- {% endfor %}
- 1、{% if %}
- 可以使用and, or, not来组织你的逻辑。但不允许and和or同时出现的条件语句中。新版本中已经支持{% elif %}这样的用法。
- 2、{% ifequal %}和{% ifnotequal %}
- 比较是否相等,只限于简单的类型,比如字符串,整数,小数的比较,列表,字典,元组不支持。
- 3、{% for %}
- 用来循环一个list,还可以使用resersed关键字来进行倒序遍历,一般可以用if语句来先判断一下列表是否为空,再进行遍历;还可以使用empty关键字来进行为空时候的跳转。
- ** for标签中可以使用forloop
- a. forloop.counter 当前循环计数,从1开始
- b. forloop.counter0 当前循环计数,从0开始,标准索引方式
- c. forloop.revcounter 当前循环的倒数计数,从列表长度开始
- d. forloop.revcounter0 当前循环的倒数计数,从列表长度减1开始,标准
- e. forloop.first bool值,判断是不是循环的第一个元素
- f. forloop.last 同上,判断是不是循环的最后一个元素
- g. forloop.parentloop 用在嵌套循环中,得到parent循环的引用,然后可以使用以上的参数
- 4、{% cycle %}
- 在循环时轮流使用给定的字符串列表中的值。
- 5、{# #} 单行注释,{% comment %}多行注释
- 6、{% csrf_token %}
- 生成csrf_token的标签,用于防止跨站攻击验证。
- 7、{% debug %}
- 调用调试信息
- 8、{% filter %}
- 将filter 标签圈定的内容执行过滤器操作。
- 9、{% autoescape %}
- 自动转义设置
- 10、{% firstof %}
- 输出第一个值不等于False的变量
- 11、{% load %}
- 加载标签库
- 12、{% now %}
- 获取当前时间
- 13、{% spaceless %}
- 移除空格
- 14、{% url %}
- 引入路由配置的地址
- 15、{% verbatim %}
- 禁止render
- 16、{% with %}
- 用更简单的变量名缓存复杂的变量名
更多常用标签
(4)内置过滤器
- {{ item.event_start|date:"Y-m-d H:i:s"}}
- {{ bio|truncatewords:"30" }}
- {{ my_list|first|upper }}
- {{ name|lower }}
- {{ obj | safe }}
- {% autoescape off %}
- {{ obj }}
- {% endautoescape %}
- {% csrf_token %} # 提交表单的时候需要加上否则django中间件会报csrf错误
其他常用内置过滤器
- 0、date:date:"F j Y",data过滤器通过使用"F j Y"这几个参数来格式化日期数据。
- 1、add:给变量加上响应的值
- 2、addslashes:给变量中的引号前加上斜线
- 3、capfirst:首字母大写
- 4、cut:从字符串中移除指定的字符
- 5、date:格式化日期字符串
- 6、default:如果值是False,就替换成设置的默认值,否则就使用本来的值
- 7、default_if_none:如果值是None,就替换成设置的默认值,否则就使用本来的值
- 8、dictsort:按照设定参数(key)对应的value对列表进行排序
- 9、dictsortreversed:和上面恰好相反
- 10、divisibleby:是否能够被某个数字整除,是的话返回True,否则返回False
- 11、escape:对字符串进行转义
- 12、escapejs:替换value中的某些字符,以适应JAVASCRIPT和JSON格式
- 13、filesizeformat:格式化文件大小显示
- 14、first:返回列表中的第一个值
- 15、last:返回列表中最后一个值
- 16、floatformat:格式化浮点数
- 17、length:求字符串或者列表长度
- 18、length_is:比较字符串或者列表的长度
- 19、urlencode:对URL进行编码处理
- 20、upper\lower:大写\小写
- 21、safe:对某个变量关闭自动转义
- 22、slice:切片操作
- 23、time:格式化时间
- 24、timesince:格式化时间 (e.g., “4 days, 6 hours”).
- 25、truncatechars:按照字符截取字符串
- 26、truncatewords:按照单词截取字符串
- 27、striptags:过滤掉html标签
其他常用内置过滤器
(5)自定义方法filter或者simple_tag
filter和simple_tag的区别:
filter:限制传参2个,支持 if 条件
simple_tag:不限制传参,不支持 if 条件
官网:https://docs.djangoproject.com/en/1.11/howto/custom-template-tags/
1、在app01中创建templatetags模块(templatetags名字是不能变)
2、创建任意 .py 文件,如:mysimple.py
- 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)
- @register.filter
- def f1(value):
- return value + '1000'
- @register.filter
- def f2(value,arg):
- '''传递一个参数'''
- return value + '1000' + arg
- @register.filter
- def f3(value):
- if value == 'vvv':
- return True
- else:
- return False
3、在使用自定义simple_tag的html文件中导入之前创建的 mysimple.py 文件名
- {% load mysimple %}
4、使用simple_tag和filter,它们使用是不一样的
- {% my_simple_time 1 2 3%} # 可以传递多个参数
- {% my_input 'id_username' 'hide'%}
- {{ k1 | f1 }}
- {{ k1 | f2:'python' }} # 只能传递一个参数
- {% if k1 | f3 %}
- <h1>True</h1>
- {% else %}
- <h1>False</h1>
- {% endif %}
5、在settings中配置当前app,不然django无法找到自定义的simple_tag
- INSTALLED_APPS = (
- 'django.contrib.admin',
- 'django.contrib.auth',
- 'django.contrib.contenttypes',
- 'django.contrib.sessions',
- 'django.contrib.messages',
- 'django.contrib.staticfiles',
- 'app01',
- )
(六)模板继承
- 母板:{% block title %}{% endblock %}
- 子板:{% extends "base.html" %}
- {% include "xx.html" %} # 在子板中使用其他模板
- {% block title %}{% endblock %}
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title></title>
- <link rel="stylesheet" href="..." />
- <style>
- .pg-header{
- height: 48px;
- background-color: cadetblue;
- }
- .pg-body{
- min-height: 500px;
- }
- .pg-body .body-menu{
- width: 20%;
- float: left;
- }
- .pg-body .body-content{
- width: 80%;
- float: left;
- }
- .pg-footer{
- height: 100px;
- background-color: brown;
- }
- .active{
- background-color: aquamarine;
- color: white;
- }
- </style>
- {% block css %}{% endblock %}
- </head>
- <body>
- <div class="pg-header">
- 后台系统V1
- </div>
- <div class="pg-body">
- <div class="body-menu">
- <ul>
- <li><a id="userinfo" href="/userinfo">用户管理</a></li>
- <li><a id="assets" href="/assets">资产管理</a></li>
- </ul>
- </div>
- <div class="body-content">
- {% block body %}{% endblock %}
- </div>
- </div>
- <div class="pg-footer"></div>
- <script src="xxx"></script>
- {% block js %}{% endblock %}
- </body>
- </html>
layout.html
- {% extends 'layout.html' %}
- {% block body %}
- {% include 'xx.html' %}
- <table>
- {% for item in assets_list %}
- <tr>
- <td>{{ item.hostname }}</td>
- <td>{{ item.port }}</td>
- </tr>
- {% endfor %}
- </table>
- {% endblock %}
- {% block js %}
- <script>
- document.getElementById('assets').className = 'active';
- </script>
- {% endblock %}
assets.html
- {% extends 'layout.html' %}
- {% block css %}
- <style></style>
- {% endblock %}
- {% block body %}
- {% include 'xx.html' %}
- <ul>
- {% for item in user_list %}
- <li>{{ item.username }},{{ item.salary }}</li>
- {% endfor %}
- </ul>
- {% endblock %}
- {% block js %}
- <script>
- document.getElementById('userinfo').className = 'active';
- </script>
- {% endblock %}
userinfo.html
- <form>
- <input type="text" placeholder="请输入内容"/>
- <input type="text" placeholder="请输入内容"/>
- <input type="text" placeholder="请输入内容"/>
- <input type="text" placeholder="请输入内容"/>
- </form>
xx.html
- from django.shortcuts import render,HttpResponse
- # Create your views here.
- USER_LSIT = []
- for item in range(94):
- temp = {"id":item, "ip":"192.168.1." + str(item),"username":"user" + str(item)}
- USER_LSIT.append(temp)
- def index(request,page):
- page = int(page)
- start = (page - 1) * 10
- end = page * 10
- user_list = USER_LSIT[start:end]
- return render(request,'index.html',{'user_list':user_list})
- def detail(request,nid):
- nid = int(nid)
- current_detail_dict = USER_LSIT[nid]
- return render(request,"detail.html",{"current_detail_dict":current_detail_dict})
- def assets(request):
- assets_list = []
- for i in range(10):
- temp = {'hostname':'192.168.1.'+str(i),'port':80}
- assets_list.append(temp)
- return render(request,'assets.html',{'assets_list':assets_list})
- def userinfo(request):
- user_list = []
- for i in range(10):
- temp = {'username': 'user' + str(i),'salary':80}
- user_list.append(temp)
- return render(request,'userinfo.html',{'user_list':user_list})
views
- from django.conf.urls import url
- from django.contrib import admin
- from cmdb import views
- urlpatterns = [
- url(r'^admin/', admin.site.urls),
- url(r'^assets/', views.assets),
- url(r'^userinfo/', views.userinfo),
- ]
urls
更多官网模板介绍:
https://docs.djangoproject.com/en/1.11/ref/templates/builtins/
https://docs.djangoproject.com/en/1.11/ref/templates/builtins/#extends
https://docs.djangoproject.com/en/1.11/ref/templates/builtins/#block
https://docs.djangoproject.com/en/1.11/ref/templates/builtins/#include
六、Model详解
2、mysql驱动程序:
- MySQLdb(mysql-python):https://pypi.python.org/pypi/MySQL-python/1.2.5(支持python2)
- mysqlclient:https://pypi.python.org/pypi/mysqlclient (支持python3)
- MySQL Connector/Python: https://dev.mysql.com/downloads/connector/python
- PyMySQL(纯python的mysql驱动):https://pypi.python.org/pypi/PyMySQL (python3中使用,常用)
3、model配置步骤:
- 1、创建数据库
- >> CREATE DATABASE IF NOT EXISTS testdb DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
- 2、配置文件settings里连接数据库
- INSTALLED_APPS = [
- .......
- 'app02',
- 'app01',
- ]
- DATABASES = {
- 'default': {
- 'ENGINE': 'django.db.backends.mysql’,#注意改成mysql后台
- 'NAME': 'hello_django_db',
- 'USER':'root',
- 'PASSWORD':'123456’,#就是连接mysql的密码
- #'HOST':'',
- #'PORT':'',
- }
- }
- 3、和项目project同名的__init__中
- import pymysql
- pymysql.install_as_MySQLdb()
- 4、创建model,继承自models.Model类
- name = models.CharField(max_length=50)
- 5、同步数据库
- python manage.py makemigrations
- python manage.py migrate
(一)、使用原生SQL
到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞:
- 创建数据库,设计表结构和字段
- 使用 MySQLdb 来连接数据库,并编写数据访问层代码
- 业务逻辑层去调用数据访问层执行数据库操作
- import pymysql
- def GetList(sql):
- db = pymysql.connect(user='root', db='wupeiqidb', passwd='', host='localhost')
- cursor = db.cursor()
- cursor.execute(sql)
- data = cursor.fetchall()
- db.close()
- return data
- def GetSingle(sql):
- db = pymysql.connect(user='root', db='wupeiqidb', passwd='', host='localhost')
- cursor = db.cursor()
- cursor.execute(sql)
- data = cursor.fetchone()
- db.close()
- return data
通过pymysql操作数据库
(二)、使用Django的ORM
django为使用一种新的方式,即:关系对象映射(Object Relational Mapping,简称ORM)。
PHP:activerecord
Java:Hibernate
C#:Entity Framework
django中遵循 Code Frist 的原则,即:根据代码中定义的类来自动生成数据库表。
1、创建Model,之后可以根据Model来创建数据库表
- from django.db import models
- class userinfo(models.Model):
- name = models.CharField(max_length=30)
- email = models.EmailField()
- memo = models.TextField()
更多字段:
- 1、models.AutoField 自增列 = int(11)
- 如果没有的话,默认会生成一个名称为 id 的列,如果要显示的自定义一个自增列,必须将给列设置为主键 primary_key=True。
- 2、models.CharField 字符串字段
- 必须 max_length 参数
- 3、models.BooleanField 布尔类型=tinyint(1)
- 不能为空,Blank=True
- 4、models.ComaSeparatedIntegerField 用逗号分割的数字=varchar
- 继承CharField,所以必须 max_lenght 参数
- 5、models.DateField 日期类型 date
- 对于参数,auto_now = True 则每次更新都会更新这个时间;auto_now_add 则只是第一次创建添加,之后的更新不再改变。
- 6、models.DateTimeField 日期类型 datetime
- 同DateField的参数
- 7、models.Decimal 十进制小数类型 = decimal
- 必须指定整数位max_digits和小数位decimal_places
- 8、models.EmailField 字符串类型(正则表达式邮箱) =varchar
- 对字符串进行正则表达式
- 9、models.FloatField 浮点类型 = double
- 10、models.IntegerField 整形
- 11、models.BigIntegerField 长整形
- integer_field_ranges = {
- 'SmallIntegerField': (-32768, 32767),
- 'IntegerField': (-2147483648, 2147483647),
- 'BigIntegerField': (-9223372036854775808, 9223372036854775807),
- 'PositiveSmallIntegerField': (0, 32767),
- 'PositiveIntegerField': (0, 2147483647),
- }
- 12、models.IPAddressField 字符串类型(ip4正则表达式),django1.10逐步废弃使用下面一种
- 13、models.GenericIPAddressField 字符串类型(ip4和ip6是可选的)
- 参数protocol可以是:both、ipv4、ipv6
- 验证时,会根据设置报错
- 14、models.NullBooleanField 允许为空的布尔类型
- 15、models.PositiveIntegerFiel 正Integer
- 16、models.PositiveSmallIntegerField 正smallInteger
- 17、models.SlugField 减号、下划线、字母、数字
- 18、models.SmallIntegerField 数字
- 数据库中的字段有:tinyint、smallint、int、bigint
- 19、models.TextField 字符串=longtext
- 20、models.TimeField 时间 HH:MM[:ss[.uuuuuu]]
- 21、models.URLField 字符串,地址正则表达式
- 22、models.BinaryField 二进制
- 23、models.ImageField 图片,需要max_length
- 24、models.FilePathField 文件,需要max_length
更多参数:
- 1、null=True # 数据库中字段是否可以为空
- 2、blank=True # django的 Admin 中添加数据时是否可允许空值
- 3、primary_key = False #主键,对AutoField设置主键后,就会代替原来的自增 id 列
- 4、auto_now、auto_now_add
- auto_now # 自动创建---无论添加或修改,都是当前操作的时间
- auto_now_add # 自动创建---永远是创建时的时间
- 5、choices
- GENDER_CHOICE = (
- (u'M', u'Male'),
- (u'F', u'Female'),
- )
- gender = models.CharField(max_length=2,choices = GENDER_CHOICE)
- gender_choice = (
(0,'男'),
(1,'女'),
)
gender = models.IntergetFiled(choice=gener_choice) # 数据库中存储的是0,1但是显示的是男,女- 6、max_length # 在charfield必须指定最大长度
- 7、default # 默认值
- 8、verbose_name # Admin中字段的显示名称
- 9、name|db_column # 数据库中的字段名称
- 10、unique=True # 不允许重复
- 11、db_index = True # 数据库索引
- 12、editable=True # 在Admin里是否可编辑
- 13、error_messages=None # 在Admin错误提示
- 14、auto_created=False # 自动创建
- 15、help_text # 在Admin中提示帮助信息
- 16、validators=[] # 自定义规则
- 17、upload-to # 指定上传的路径
18、class Meta():
verbose_name = '这张表的名字在admin后台的显示名字'
verbose_name_plural = verbose_name
ordering = ['-id'] # 根据id反向排序
2、数据库操作
增加:create()、bulk_create()
- # create 第一种方式
- models.类名.objects.create(hostname="name")
- # create 第二种方式,推荐这种
- models.类名.objects.create(**{"hostname":"name"})
- # save 第三种方式
- obj = 类名(hostname="name")
- obj.save()
- # save 第四种方式,其实和第三种是一样的,推荐第二种
- obj = 类名()
- obj.hostname = "name"
- obj.save()
- 注意:hostname是数据库中的字段名,name是值
- # bulk_create() 批量创建数据
- models.类名.objexts.bulk_create([
- 类名(字段=值),
- 类名(字段=值),
- ])
更新:update()
- # 第一种方式,推荐这种,而且高效
- models.类名.objects.filter(id=2).update(hostname='tomcat')
- # 第二种方式
- obj = models.类名.objects.get(id=2)
- obj.hostname = 'tomcat'
- obj.save()
第二种方式修改不能用get的原因是:update是QuerySet对象的方法,get返回的是一个model对象,它没有update方法,而filter返回的是一个QuerySet对象(filter里面的条件可能有多个条件符合,比如name='alvin',可能有两个name='alvin'的行数据)
删除:delete()
- models.类名.objects.get(id=2).delete() # 不建议
- models.类名.objects.filter(id=2).delete()
- models.类名.objects.all().delete()
查询:
filter() 集合queryset对象
all(), 集合queryset对象
get(),获取单条数据,不存在就报错
getlist()用于取多个值
- models.类名.objects.get(id=123) # 获取单条数据,不存在则报错(不建议),
- models.类名.objects.all() # 获取全部
- models.类名.objects.filter(name='tomcat') # 获取指定条件的数据
显示指定字段:values(),values_list()
- models.类名.objects.get(id=123).values('id','name') # 返回的是queryset字典
- models.类名.objects.get(id=123).values__list('id','name') # 返回的是queryset元组
复杂查询:Q()表达式:
https://docs.djangoproject.com/en/1.11/topics/db/queries/#complex-lookups-with-q-objects
数量:count()
- models.类名.objects.filter(name='tomcat').count()
- models.类名.objects.get(name='tomcat').count()
- models.类名.objects.all().count()
去重:distinct()
- models.类名.objects.values('字段').distinct()
大于小于:__gt,__lt,__gte,__lte
- models.类名.objects.filter(id__gt=1) # 获取id大于1的值
- models.类名.objects.filter(id__lt=10) # 获取id小于10的值
- models.类名.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值
等于多个值:__in
- models.类名.objects.filter(id__in=[11, 22, 33]) # 获取id等于11、22、33的数据
- models.类名.objects.exclude(id__in=[11, 22, 33]) # not in
模糊查询:__contains,__icontains
- models.类名.objects.filter(name__contains="ven")
- models.类名.objects.filter(name__icontains="ven") # icontains大小写不敏感
- models.类名.objects.exclude(name__icontains="ven")
范围查询:__range
- models.类名.objects.filter(id__range=[1, 2]) # 范围bettwen and
其他类似:__startswith,__endswith, __iendswith, __istartswith
排序:order_by("name") 相当于asc;order_by("-name") 相当于desc;
- models.类名.objects.filter(name='seven').order_by('id') # asc,从小到大
- models.类名.objects.filter(name='seven').order_by('-id') # desc,从大到小
返回第n-m条:第n条[0];前两条[0:2]
- # limit 、offset
- models.类名.objects.all()[10:20]
分组与聚合:group_by,annotate,aggregate
- Avg(返回所给字段的平均值)
- Count(根据所给的关联字段返回被关联 model 的数量)
- Max(返回所给字段的最大值)
- Min(返回所给字段的最小值)
- Sum(计算所给字段值的总和)
- # group by
- from django.db.models import Count, Min, Max, Sum
- # models.类名.objects.filter(c1=1).values('id').annotate(c=Count('num'))
- # SELECT "app01_类名"."id", COUNT("app01_类名"."num") AS "c" FROM "app01_类名" WHERE "app01_类名"."c1" = 1 GROUP BY "app01_类名"."id"
更多实例:
- >>> Publisher.objects.filter(name='广东人民出版社').aggregate(Count('name'))
- 还可以自定义别名
- >>> Publisher.objects.filter(name='广东人民出版社').aggregate(mycount = Count('name'))
- 查询胡大海出的书的总价格是多少
- >>> Book.objects.filter(authors__name='胡大海').aggregate(Sum('price'))
- 查询各个作者出的书的总价格是多少
- >>> Book.objects.values('authors__name').annotate(Sum('price'))
- 查询各个出版社最便宜的书价是多少
- >>> Book.objects.values('publisher__name').annotate(Min('price'))
更多:
https://docs.djangoproject.com/en/1.11/topics/db/aggregation/
https://docs.djangoproject.com/en/1.11/topics/db/annotate/
原始SQL:
- extra:结果集修改器 - 一种提供额外查询参数的机制
- raw:执行原始sql并返回模型实例,最适合用于查询,(异常:Raw query must include the primary key,返回结果必须包含主键)
- 直接执行自定义SQL(这种方式完全不依赖model,前面两种方式还是要依赖于model),适合增删改
- A.使用extra:
- >>> Book.objects.filter(publisher__name='广东人民出版社').extra(where=['price>50’])
- >>> Book.objects.filter(publisher__name='广东人民出版社', price__gt=50)
- >>> Book.objects.extra(select={'count':'select count(*) from hello_book'})
- B.使用raw:
- >>> Book.objects.raw('select * from hello_book')
- C.自定义sql:
- from django.db import connection
- cursor = connection.cursor() #获得一个游标(cursor)对象
- cursor.execute("insert into hello_author(name) values('郭敬明')") #插入操作
- cursor.execute("update hello_author set name = '韩寒' where name='郭敬明'") #更新操作
- cursor.execute("delete from hello_author where name='韩寒'") #删除操作
- cursor.execute('select * from hello_author') #查询操作
- raw = cursor.fetchone() #返回结果行
- cursor.fetchall()
3、连表操作:
- 一对多,models.ForeignKey('UserType')
- 一对一,models.OneToOneField('UserType',on_delete=models.SET_NULL)
- 多对多,models.ManyToManyField('UserType',on_delete=models.CASCADE)
应用场景:
- 一对一:在某表中创建一行数据时,有一个单选的下拉框(下拉框中的内容被用过一次就消失了)。
例如:原有含10列数据的一张表保存相关信息,经过一段时间之后,10列无法满足需求,需要为原来的表再添加5列数据。- 一对多:当一张表中创建一行数据时,有一个单选的下拉框(可以被重复选择)。
例如:创建用户信息时候,需要选择一个用户类型【普通用户】【金牌用户】【铂金用户】等。- 多对多:在某表中创建一行数据是,有一个可以多选的下拉框。
例如:创建用户信息,需要为用户指定多个爱好。
利用双下划线和 _set 将表之间的操作连接起来
- from django.db import models
- class UserProfile(models.Model):
- username = models.CharField(max_length=64)
- password = models.CharField(max_length=64)
- user_info = models.OneToOneField('UserInfo')
- def __str__(self): # __unicode__ on python2
- return self.username
- class UserInfo(models.Model):
- user_type_choice = (
- (0, '普通用户'),
- (1, '高级用户'),
- )
- user_type = models.IntegerField(choices=user_type_choice)
- name = models.CharField(max_length=32)
- email = models.CharField(max_length=32)
- address = models.CharField(max_length=128)
- def __str__(self): # __unicode__ on python2
- return self.name
- class UserGroup(models.Model):
- caption = models.CharField(max_length=64)
- user_info = models.ManyToManyField('UserInfo')
- def __str__(self): # __unicode__ on python2
- return self.caption
- class Host(models.Model):
- hostname = models.CharField(max_length=64)
- ip = models.GenericIPAddressField()
- user_group = models.ForeignKey('UserGroup')
- def __str__(self): # __unicode__ on python2
- return self.hostname
表结构实例:models.py
- urlpatterns = [
- url(r'^admin/', admin.site.urls),
- url(r'^add/', views.addata),
- url(r'^danbiao/', views.danbiao),
- url(r'^yiduiyi/', views.yiduiyi),
- url(r'^yiduiduo/', views.yiduiduo),
- url(r'^duoduiduo/', views.duoduiduo),
- ]
urls.py
- def addata(request):
- # 批量插入UserInfo表
- models.UserInfo.objects.bulk_create([
- UserInfo(user_type=0, name='Shi Zhongyu', email='shizhongyu@163.com', address='深圳市'),
- UserInfo(user_type=0, name='Sun Dasheng', email='sundasheng@163.com', address='佛山市'),
- UserInfo(user_type=0, name='Lin Daiyu', email='lindaiyu@163.com', address='揭阳市'),
- UserInfo(user_type=0, name='Lin Chong', email='linchong@163.com', address='中山市'),
- UserInfo(user_type=0, name='Ma Chao', email='machao@126.com', address='福州市'),
- UserInfo(user_type=0, name='Xie Yanke', email='xieyanke@126.com', address='厦门市'),
- UserInfo(user_type=0, name='Xiao Qiao', email='xiaoqiao@yahoo.com', address='漳州市'),
- UserInfo(user_type=0, name='Tian Boguang', email='tianboguang@qq.com', address='龙岩市'),
- UserInfo(user_type=0, name='Yuan Chengzhi', email='yuanchengzhi@qq.com', address='北京市'),
- UserInfo(user_type=0, name='Ren Yingying', email='renyingying@360.com', address='上海市'),
- UserInfo(user_type=0, name='Diao Chan', email='diaochan@baidu.com', address='南京市'),
- UserInfo(user_type=0, name='Lu Wushuang', email='luwushuang@ali.com', address='青岛市'),
- UserInfo(user_type=0, name='Xue Baochai', email='xuebaochai@live.com', address='浙江市'),
- UserInfo(user_type=1, name='Xiao Dasheng', email='xiaodasheng@gmail.com', address='伊拉克'),
- ])
- # 批量插入UserProfile表
- userprofile_list = []
- for i in range(1,16):
- username = 'zhanghao' + str(i)
- password = ''
- userinfo = i
- uprofile = models.UserProfile(username=username,password=password,userinfo=userinfo)
- userprofile_list.append(uprofile)
- models.UserProfile.objects.bulk_create(userprofile_list)
- # 批量插入UserGroup表
- models.UserGroup.objects.bulk_create([
- UserInfo(capation='CTO'),
- UserInfo(capation='CEO'),
- UserInfo(capation='COO'),
- ])
- # 批量插入Host表
- models.Host.objects.bulk_create([
- UserInfo(hostname='c1.salt.com',ip='192.168.1.1',user_group_id=1),
- UserInfo(hostname='c2.salt.com',ip='192.168.1.2',user_group_id=1),
- UserInfo(hostname='c3.salt.com',ip='192.168.1.3',user_group_id=1),
- UserInfo(hostname='c4.salt.com',ip='192.168.1.4',user_group_id=1),
- UserInfo(hostname='c5.salt.com',ip='192.168.1.5',user_group_id=1),
- UserInfo(hostname='c6.salt.com',ip='192.168.1.6',user_group_id=2),
- UserInfo(hostname='c7.salt.com',ip='192.168.1.7',user_group_id=2),
- UserInfo(hostname='c8.salt.com',ip='192.168.1.8',user_group_id=2),
- UserInfo(hostname='c9.salt.com',ip='192.168.1.9',user_group_id=2),
- UserInfo(hostname='c10.salt.com',ip='192.168.1.10',user_group_id=2),
- UserInfo(hostname='c11.salt.com',ip='192.168.1.11',user_group_id=3),
- UserInfo(hostname='c12.salt.com',ip='192.168.1.12',user_group_id=3),
- UserInfo(hostname='c13.salt.com',ip='192.168.1.13',user_group_id=3),
- UserInfo(hostname='c14.salt.com',ip='192.168.1.14',user_group_id=3),
- UserInfo(hostname='c15.salt.com',ip='192.168.1.15',user_group_id=3),
- ])
- return render(request,'addata.html')
增加数据:views.py
多对多那张表可以自己在数据库插入数据,所有html都是空的
- def danbiao(request):
- # filter是querset对象,所以要迭代取出值
- queryset = models.UserInfo.objects.filter(name='user')
- print(queryset.query)
- print(type(queryset))
- for item in queryset:
- print(item.id)
- print(item.user_type)
- print(item.name)
- print(item.email)
- print(item.address)
- # get是userinfo类对象,不需要迭代取值,直接取
- obj = models.UserInfo.objects.get(id=10)
- print(type(obj))
- print(obj.id)
- print(obj.name)
- print(obj.user_type)
- print(obj.email)
- print(obj.address)
- # values也是queryset对象,需要迭代取值,values是字典
- obj1 = models.UserInfo.objects.filter(name='redhat').values('id','name')
- print(type(obj1))
- for i in obj1:
- print(i['id'])
- print(i['name'])
- # values_list也是queryset对象,需要迭代取值,values_list元组
- obj2 = models.UserInfo.objects.filter(name='centos').values_list('id','name')
- print(type(obj2))
- for i in obj2:
- print(i[0])
- print(i[1])
- obj3 = models.UserInfo.objects.all()
- print(type(obj3))
- for iter in obj3:
- print(iter.id)
- print(iter.name)
- return render(request,'danbiao.html',locals())
单表操作:views.py
- def yiduiyi(request):
- # 正向查询
- u_profile = models.UserProfile.objects.all()
- for i in u_profile:
- print(i.id)
- print(i.username)
- print(i.password)
- print(i.user_info.get_user_type_display())
- print(i.user_info.name)
- print(i.user_info.email)
- print(i.user_info.address)
- # 正向连表查询
- u_profile1 = models.UserProfile.objects.values('username','password','user_info__user_type','user_info__name')
- for i in u_profile1:
- print(i['username'])
- obj = models.UserProfile.objects.values('username','password','user_info__user_type','user_info__name').first()
- print(obj['username'])
- print(obj['password'])
- print(obj['user_info__user_type'])
- print(obj['user_info__name'])
- # 反向查询userprofile表
- user_info_obj = models.UserInfo.objects.filter(id=1).first()
- print(type(user_info_obj))
- print(user_info_obj.user_type)
- print(user_info_obj.get_user_type_display())
- print(user_info_obj.userprofile.password)
- # 反向连表查询
- user_info_obj1 = models.UserInfo.objects.filter(id=1).values('email', 'userprofile__username').first()
- print(type(user_info_obj1))
- print(user_info_obj1.keys())
- print(user_info_obj1.values())
- return render(request,'yiduiyi.html',locals())
一对一操作:views.py
- def yiduiduo(request):
- # 正向查询
- obj = models.Host.objects.all()
- for i in obj:
- print(i.id)
- print(i.hostname)
- print(i.ip)
- print(i.user_group.caption)
- # 正向查询连表操作
- obj1 = models.Host.objects.all().values('hostname','user_group__caption').first()
- print(obj1)
- print(obj1['hostname'])
- print(obj1['user_group__caption'])
- obj2 = models.Host.objects.all().values('hostname','user_group__caption')
- print(type(obj2))
- for i in obj2:
- print(i.keys())
- print(i.values())
- # 反向查询
- obj3 = models.UserGroup.objects.all()
- print(obj3)
- print(type(obj3))
- for i in obj3:
- print(i.caption)
- print(i.host_set.all())
- host_obj = i.host_set.all()
- for j in host_obj:
- print(j.hostname)
- print(j.ip)
- # 反向查询连表操作
- obj4 = models.UserGroup.objects.all().values('caption','host__hostname').first()
- print(obj4['caption'])
- print(obj4['host__hostname'])
- obj5 = models.UserGroup.objects.all().values('caption','host__hostname')
- for i in obj5:
- print(i['caption'])
- print(i['host__hostname'])
- # 一对多,三表关联
- allobj = models.Host.objects.filter(user_group__user_info__user_type=0)
- print(allobj.query)
- print(type(allobj))
- for i in allobj:
- print(i)
- print(i.user_group.caption)
- return render(request,'yiduiduo.html',locals())
一对多:views.py
- def duoduiduo(request):
- # 在关联连表的时候不知道填什么字段,故意填错,django会提示可以填入的字段
- # 正向添加数据,多对多的第三表存储的是两张表的主键id
- user_info_obj = models.UserInfo.objects.get(id=1)
- user_info_objs = models.UserInfo.objects.all()
- group_obj = models.UserGroup.objects.get(id=1)
- group_obj.user_info.add(user_info_obj)
- group_obj.user_info.add(*user_info_objs)
- group_obj.user_info.add(1)
- group_obj.user_info.add(*[1,2,4])
- # 正向删除数据
- group_obj.user_info.clear() # 清空所有与第三张表usergroup id=1的所有数据
- group_obj.user_info.remove(*[2,3,4]) # 删除,2,3,4条数据
- # 正向查询数据
- group_obj = models.UserGroup.objects.get(id=1)
- obj = group_obj.user_info.all()
- for i in obj:
- print(i.id)
- print(i.name)
- print(i.email)
- print(i.address)
- print(i.get_user_type_display())
- # 正向关联表查询
- dic = models.UserGroup.objects.all().values('caption','user_info__name','user_info__address','user_info__email')
- print(dic)
- # 反向添加数据
- user_info_obj = models.UserInfo.objects.get(id=1)
- group_obj1 = models.UserGroup.objects.get(id=1)
- group_obj2 = models.UserGroup.objects.all()
- obj2 = user_info_obj.usergroup_set.add(group_obj1)
- obj3 = user_info_obj.usergroup_set.add(*group_obj2)
- user_info_obj.usergroup_set.add(1)
- user_info_obj.usergroup_set.add(*[1,2,3,4])
- # 反向删除数据
- user_info_obj.usergroup_set.clear() # 清空所有第三张表userinfo id=1的所有数据
- user_info_obj.usergroup_set.remove(*[2,3,4])
- # 反向查询
- user_info_obj = models.UserInfo.objects.get(id=1)
- obj4 = user_info_obj.usergroup_set.all()
- print(obj4)
- print(type(obj4))
- for i in obj4:
- print(i.id)
- print(i.caption)
- # 反向连表查询
- dic1 = models.UserInfo.objects.all().values('name','email','address','usergroup__caption')
- print(dic)
- return render(request,'duoduiduo.html',locals())
多对多操作:views.py
其他操作中包含:F()和Q查询
- # F 使用查询条件的值
- #
- # from django.db.models import F
- # models.Tb1.objects.update(num=F('num')+1)
- # Q 构建搜索条件
- from django.db.models import Q
- # con = Q()
- #
- # q1 = Q()
- # q1.connector = 'OR'
- # q1.children.append(('id', 1))
- # q1.children.append(('id', 10))
- # q1.children.append(('id', 9))
- #
- # q2 = Q()
- # q2.connector = 'OR'
- # q2.children.append(('c1', 1))
- # q2.children.append(('c1', 10))
- # q2.children.append(('c1', 9))
- #
- # con.add(q1, 'AND')
- # con.add(q2, 'AND')
- #
- # models.Tb1.objects.filter(con)
- #
- # from django.db import connection
- # cursor = connection.cursor()
- # cursor.execute("""SELECT * from tb where name = %s""", ['Lennon'])
- # row = cursor.fetchone()
其他操作
注意:xx_set中的【_set】是多对多中的固定搭配,用于反响查询,一对多中反向也可以用_set
自连接F()表达式:
https://docs.djangoproject.com/en/1.9/ref/models/expressions/#
4、扩展:
(1)自定义上传
- def upload_file(request):
- if request.method == "POST":
- obj = request.FILES.get('fafafa')
- f = open(obj.name, 'wb')
- for chunk in obj.chunks():
- f.write(chunk)
- f.close()
- return render(request, 'file.html')
(2)Form上传文件实例
form.py
- class FileForm(forms.Form):
- ExcelFile = forms.FileField()
model.py
- from django.db import models
- class UploadFile(models.Model):
- userid = models.CharField(max_length = 30)
- file = models.FileField(upload_to = './upload/')
- date = models.DateTimeField(auto_now_add=True)
view.py
- def UploadFile(request):
- uf = AssetForm.FileForm(request.POST,request.FILES)
- if uf.is_valid():
- upload = models.UploadFile()
- upload.userid = 1
- upload.file = uf.cleaned_data['ExcelFile']
- upload.save()
- print upload.file
更多model相关:https://docs.djangoproject.com/en/1.9/topics/db/models/
七、admin
django amdin是django提供的一个后台管理页面,改管理页面提供完善的html和css,使得你在通过Model创建完数据库表之后,就可以对数据进行增删改查,而使用django admin 则需要以下步骤:
- 创建后台管理员
- 配置url
- 注册和配置django admin后台管理页面
更多:https://docs.djangoproject.com/en/1.11/ref/contrib/admin/
admin基本使用:
1、创建后台管理员
- python manage.py createsuperuser
- python manage.py changepassword
2、配置后台管理url
- url(r'^admin/', include(admin.site.urls))
3、注册和配置django admin 后台管理页面
a、设置数据表名称
- class UserType(models.Model):
- name = models.CharField(max_length=50,verbose_name='类型的名字')
- class Meta:
- verbose_name = '用户类型'
- verbose_name_plural = verbose_name
- def __str__(self): # __unicode__ on python2
- return self.name
b、在admin中执行如下配置
- from django.contrib import admin
- from app01 import models
- admin.site.register(models.UserType)
(1)在admin中显示的字段
- from django.contrib import admin
- from app01 import models
- class UserInfoAdmin(admin.ModelAdmin):
- list_display = ('id','name')
- admin.site.register(models.UserType,UserInfoAdmin)
(2)为数据表添加搜索功能
- from django.contrib import admin
- from app01 import models
- class UserInfoAdmin(admin.ModelAdmin):
- list_display = ('id','name')
- search_fields = ('name')
- admin.site.register(models.UserType,UserInfoAdmin)
(3)添加快速过滤、可编辑、分页
- from django.contrib import admin
- from app01 import models
- class UserInfoAdmin(admin.ModelAdmin):
- list_display = ('id','name')
- search_fields = ('name')
- list_filter = ('name')
- list_editable = ('name')
list_per_page = 10- admin.site.register(models.UserType,UserInfoAdmin)
admin中的action:
- from django.db import models
- STATUS_CHOICES = (
- ('d', 'Draft'),
- ('p', 'Published'),
- ('w', 'Withdrawn'),
- )
- class Article(models.Model):
- title = models.CharField(max_length=100)
- body = models.TextField()
- status = models.CharField(max_length=1, choices=STATUS_CHOICES)
- def __str__(self): # __unicode__ on Python 2
- return self.title
admin.py
- from django.contrib import admin
- from myapp.models import Article
- def make_published(modeladmin, request, queryset):
- queryset.update(status='p')
- make_published.short_description = "Mark selected stories as published" # 在admin后台action显示的操作
- class ArticleAdmin(admin.ModelAdmin):
- list_display = ['title', 'status']
- ordering = ['title']
- actions = [make_published] # 将上面定义的action function添加进来
- admin.site.register(Article, ArticleAdmin)
给状态加上html
- from django.db import models
- from django.utils.html import format_html
- STATUS_CHOICES = (
- ('d', 'Draft'),
- ('p', 'Published'),
- ('w', 'Withdrawn'),
- )
- class Article(models.Model):
- title = models.CharField(max_length=100)
- body = models.TextField()
- status = models.CharField(max_length=1, choices=STATUS_CHOICES)
- def __str__(self): # __unicode__ on Python 2
- return self.title
- def colored_status(self):
- if self.status == 'd':
- format_td = format_html('<span style="padding:2px;background-color:yellowgreen;color:white">Draft</span>')
- elif self.status == 'p':
- format_td = format_html('<span style="padding:2px;background-color:green;color:white">Published</span>')
- elif self.status == 'w':
- format_td = format_html('<span style="padding:2px;background-color:orange;color:white">Withdrawn</span>')
- return format_td
- colored_status.short_description = 'status' # 在admin后台显示字段改名字
models.py
- from django.contrib import admin
- from myapp.models import Article
- def make_published(modeladmin, request, queryset):
- queryset.update(status='p')
- make_published.short_description = "Mark selected stories as published" # 在admin后台action显示的操作
- class ArticleAdmin(admin.ModelAdmin):
- list_display = ['title', 'status','colored_status'] # 这里直接添加一个字段即可
- ordering = ['title']
- actions = [make_published] # 将上面定义的action function添加进来
- admin.site.register(Article, ArticleAdmin)
admin.py
更多:https://docs.djangoproject.com/en/1.11/ref/contrib/admin/actions/#writing-actions
Python自动化运维之27、Django(一)的更多相关文章
- Python自动化运维:技术与最佳实践 PDF高清完整版|网盘下载内附地址提取码|
内容简介: <Python自动化运维:技术与最佳实践>一书在中国运维领域将有“划时代”的重要意义:一方面,这是国内第一本从纵.深和实践角度探讨Python在运维领域应用的著作:一方面本书的 ...
- 【目录】Python自动化运维
目录:Python自动化运维笔记 Python自动化运维 - day2 - 数据类型 Python自动化运维 - day3 - 函数part1 Python自动化运维 - day4 - 函数Part2 ...
- python自动化运维篇
1-1 Python运维-课程简介及基础 1-2 Python运维-自动化运维脚本编写 2-1 Python自动化运维-Ansible教程-Ansible介绍 2-2 Python自动化运维-Ansi ...
- Day1 老男孩python自动化运维课程学习笔记
2017年1月7日老男孩python自动化运维课程正式开课 第一天学习内容: 上午 1.python语言的基本介绍 python语言是一门解释型的语言,与1989年的圣诞节期间,吉多·范罗苏姆为了在阿 ...
- python自动化运维学习第一天--day1
学习python自动化运维第一天自己总结的作业 所使用到知识:json模块,用于数据转化sys.exit 用于中断循环退出程序字符串格式化.format字典.文件打开读写with open(file, ...
- Python自动化运维的职业发展道路(暂定)
Python职业发展之路 Python自动化运维工程 Python基础 Linux Shell Fabric Ansible Playbook Zabbix Saltstack Puppet Dock ...
- Python自动化运维 技术与最佳实践PDF高清完整版免费下载|百度云盘|Python基础教程免费电子书
点击获取提取码:7bl4 一.内容简介 <python自动化运维:技术与最佳实践>一书在中国运维领域将有"划时代"的重要意义:一方面,这是国内第一本从纵.深和实践角度探 ...
- python自动化运维之CMDB篇-大米哥
python自动化运维之CMDB篇 视频地址:复制这段内容后打开百度网盘手机App,操作更方便哦 链接:https://pan.baidu.com/s/1Oj_sglTi2P1CMjfMkYKwCQ ...
- python自动化运维之路~DAY5
python自动化运维之路~DAY5 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.模块的分类 模块,用一砣代码实现了某个功能的代码集合. 类似于函数式编程和面向过程编程,函数 ...
随机推荐
- 390. Elimination Game
正规解法直接跳到代码上面一点的部分就可以了.但我想记录下自己的思考和尝试过程,希望二刷能看到问题所在. 找规律的时候写了好多,虽然规律很简单. 只要随便写3以上的例子,就应该发现,相邻的2个最后结果是 ...
- myeclipse svn
打开myeclipse的help---install from site 点击add弹出对话框 在输入框中输入对应内容 http://subclipse.tigris.org/update_1.10. ...
- python google play
#!/usr/env python #-*- coding: utf-8 -*- import urllib import urllib2 import random import requests ...
- Teamcity+SVN+VisualStudio在持续集成简明教程
Teamcity+SVN+VisualStudio持续集成 简明教程 一.写在最前: 1. 各组件版本号例如以下: Teamcity(简称tc)版本号:8.1.4 SVN版本号:Tortoi ...
- C开发之----#if、#ifdef、#if defined之间的区别
#if的使用说明 #if的后面接的是表达式 #if (MAX==10)||(MAX==20) code... #endif 它的作用是:如果(MAX==10)||(MAX==20)成立,那么编译器就会 ...
- Qt 学习之路:QML 组件
前面我们简单介绍了几种 QML 的基本元素.QML 可以由这些基本元素组合成一个复杂的元素,方便以后我们的重用.这种组合元素就被称为组件.组件就是一种可重用的元素.QML 提供了很多方法来创建组件.不 ...
- c#中跨线程调用windows窗体控件
c#中跨线程调用windows窗体控件解决. 我们在做winform应用的时候,大部分情况下都会碰到使用多线程控制界面上控件信息的问题.然而我们并不能用传统方法来做这个问题,下面我将详细的介绍.首先来 ...
- js分家效应
(原创文章,转载请注明出处) 有继承,那么就有分家.让我们看以下例子. var parents = function(){ } parents.prototype.money = 200; var c ...
- 原生JS添加节点方法与jQuery添加节点方法的比较及总结
一.首先构建一个简单布局,来供下边讲解使用 1.HTML部分代码: <div id="div1">div1</div> <div id="d ...
- MEF依赖注入调试小技巧!
自从哥的项目使用MEF以来,天天那个纠结啊,甭提了.稍有错误,MEF就报错,但就不告诉你哪错了,大爷的. 后来看了MEFX的相关调试方法,感觉也不太理想,根本不够直观的看到错误原因,也许是没有深入学习 ...