环境搭建
http://pan.baidu.com/s/1kVdrbKj
我用的python2.7.13+django1.5.8如果你之前玩过python,你可以很容易从网上找到这些版本,不过考虑到我中间可能用的插件你不一定有装,为了统一环境我放了一份我的环境打包成zip放在这个云盘上
安装方式:
windows:
1.下载 环境\window\python27.zip解压到C:\common\Python27
这里说一下你也可以选择自己看中的目录,不过我这个包包含eric6+PyQt4+scrapy+django1.5.8+各路通用我也忘了多少插件,虽然放在你喜欢的目录也可以运行,不过为了防止踩坑和麻烦我建议放在和我一样的目录,保证你不会出错
2.解压完后安装python2.7.13.amb64.msi 安装路径就是C:\common\Python27;询问是否覆盖的时候覆盖,这样你就有了python环境同时又我定制的所有插件
3.环境变量配置 我的电脑->属性->高级系统设置->环境变量->系统变量找到path->在最后面加上:C:\common\Python27;C:\common\Python27\Scripts;
mac:
1.下载 环境\mac\django_xadmin.zip解压到/Users/babybus/Sites/python/django_xadmin
2.网上下载mac的python2.7.13安装,一路默认到默认位置,我们很多还是引用这个系统默认的组件的
3.环境变量配置:终端输入open ~/.bash_profile 在那里面加入
PATH=”/Users/babybus/Sites/python/django_xadmin/bin:${PATH}”
export PATH
创建Django项目
推荐使用Pycharm或者直接用系统命名的django-admin都可以,我先介绍Pycharm
1.打开PyCharm => Create New Project => Django
2.填写好Location和Application name
3.Interpreter位置,这个是选择python解释器的
Mac版 选择 django_xadmin/bin/python文件
Win版 选择 Python27/python.exe
4.点击create,就生成好了一个Django项目
5.mac直接通过快捷键 Ctrl + R(win:Shift+F10) 就可以在启动网站,(如果出现端口被占用的错误,把酷狗关了再试一下),访问http://127.0.0.1:8000
通用的我介绍一下不通过PyCharm直接用命令创建项目的
1.Shift+鼠标右键在你想创建项目地方选择,在此处打开命令窗口
2.命令行如下
# 创建项目的方法
django-admin.py startproject myblog
cd 到刚创建的目录下
manage.py startapp love
# 把项目用8000端口打开来
manage.py runserver 8000
项目结构
- manage.py是网站的启动文件,一般不需要改动。
- myblog文件夹是网站配置文件夹,主要操作的文件有
- settings.py和urls.py。
- settings.py是网站的主要配置文件。
- urls.py是路由文件。
- love文件夹是创建项目时默认创建的模块,主要的开发在这里。
settings.py 网站配置
- 在settings.py开头插入# -- coding: utf-8 -- 防止中文错误。
- 注:所有python文件都要添加# -- coding: utf-8 --。
数据库
settings.py中找到DATABASES。
sqlite3数据库配置
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': 'db.sqlite3', # 数据库文件
}
}
mysql数据库配置
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'django_database', # 数据库名
'USER': 'root', # 用户名
'PASSWORD': 'sinyee123', # 密码
'HOST': '127.0.0.1', # 地址
'PORT': '3306', # 端口
}
}
其他数据库postgresql_psycopg2和oracle以此类推。
我们后面的开发以sqlite3为标准。
(一般来说本机开发测试我用sqlite3,这样数据库就在文件夹下,如果布置给企业用我上mysql)
时区
在settings.py中找到TIME_ZONE,修改为
TIME_ZONE = 'Asia/Shanghai'
SECRET_KEY不要去动他,这个每个django项目都不一样,由不同的key生成的数据库只有用这个钥匙才可以访问
MEDIA路径
settings.py中找到MEDIA_ROOT和MEDIA_URL。
MEDIA路径是用来存储上传文件的位置。(上传文件,或者作为一个项目的临时目录,拷贝东西到这里的某个子文件夹下操作)
配置如下:
MEDIA_ROOT = 'media' # 当前项目路径下的media文件夹
MEDIA_URL = '/media/'
STATIC路径
settings.py中找到STATIC_ROOT,STATIC_URL和STATICFILES_DIRS。
STATIC路径是网站的静态文件存放位置。(比如css/image/js)
配置如下:
STATIC_ROOT = 'static' # 当前项目路径下的static文件夹
STATIC_URL = '/static/'
模板路径
settings.py中找到TEMPLATE_DIRS。(一般我们会用一个html作为模板,传入参数,这里理解为放html的)
配置如下:
STATICFILES_DIRS = (
os.path.join(os.path.dirname(__file__), '../static/').replace('\\','/'),
)
MIDDLEWARE_CLASSES增加一个多语言选择的
django.middleware.locale.LocaleMiddleware
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
# 据说是让django支持语言选择
'django.middleware.locale.LocaleMiddleware',
)
# 修改TEMPLATE_DIRS--当前路径下的templates文件夹
TEMPLATE_DIRS = (os.path.join(os.path.dirname(__file__), '..', 'templates').replace('\\','/'),)
xadmin
xadmin是我们的管理后台框架,用于替代Django自带的admin模块。
settings.py找到INSTALLED_APPS。
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
# Uncomment the next line to enable the admin:
# 'django.contrib.admin',
# Uncomment the next line to enable admin documentation:
# 'django.contrib.admindocs',
'xadmin',
# 让syncdb migration 大致就是这些命令得以执行
'crispy_forms',
'ckeditor',
'south',
'love',
)
然后在settings.py最后直接添加
#xadmin配置文件
XADMIN_CONF = 'myblog.xsite'
gettext_noop = lambda s: s
ENABLE_XADMIN_THEME = True
#语言
LANGUAGES = (
('de', gettext_noop('German')),
('en', gettext_noop('English')),
('ja', gettext_noop('Japanese')),
('lt', gettext_noop('Lithuanian')),
('nl', gettext_noop('Dutch')),
('pl', gettext_noop('Polish')),
('pt', gettext_noop('Portuguese')),
('zh-cn', gettext_noop('Simplified Chinese')),
)
DATE_FORMAT = 'Y-m-d'
DATETIME_FORMAT = 'Y-m-d H:i'
TIME_FORMAT = 'H:i'
最后在myblog下建立xsite.py文件,作为xadmin的配置文件。
简单配置如下
# -*- coding:utf-8 -*-
from xadmin import Settings
class Base(Settings):
enable_themes = True
use_bootswatch = True
urls.py 路由配置
配置规则
- from django.conf.urls import patterns, include, url导入需要的方法。
- urlpatterns变量,该变量定义了URL以及用于处理这些URL的代码之间的映射关系。
- 调用patterns()方法并将返回结果保存到urlpatterns变量。patterns方法当前有一个空字符串参数和两个url参数(这两个url生成了Django自带的admin路由文件,我们可以直接注释掉)。
- url方法中第一个参数是正则,第二个参数是对应的模块。
修改后的urls.py
# -*- coding:utf-8 -*-
from django.conf.urls import patterns, include, url
# django自带的admin模块
from django.contrib import admin
admin.autodiscover()
from django.conf import settings
from django.conf.urls.static import static
# 我们要用的好看一些的后台管理
import xadmin
xadmin.autodiscover()
# from xadmin.plugins import xversion
# xversion.register_models()
urlpatterns = patterns('',
# Uncomment the next line to enable the admin:
url(r'^admin',include(xadmin.site.urls)),
url(r'^hello', 'love.views.hello'),
# 最后这个+是为了识别media路径,让media文件夹下的文件可以访问。
) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
此时我们访问 http://127.0.0.1:8000/admin
出现数据库错误,因为我们还没有生成数据库。接下来会介绍Django的数据库操作。
模型
Django模型Models是与数据库相关的,与数据库相关的代码一般写在models.py中。
Django数据库操作采用ORM方式,从建表到增删改查都不需要直接操作数据库。
初始化操作
1.Ctrl+Alt+R 打开Django命令行模式(mac:Alt+R)
2.输入命令syncdb,先自动生成已有模块的表(配置INSTALLED_APPS中的模块)。
中间会让你生成superuser账号,输入yes。然后再依次输入Username,Email,Password即可。
这里我放了两张执行同一个命令的图片,一个是Pycharm执行的,另一个是终端直接运行的,为了便于读者清楚命令Pycharm的命令模式对应manage.py+命名(Pycharm是主流的开发django编辑器,但是实话说对于我个人而言我更喜欢用SublimeText+终端)
接着
这时候我们发现我们的db.sqlite3已经有许多自动生成的表。
3.完成数据库初始化。
创建第一个模型
一个模型对应的是数据库中的一张表。
找到love模块下的models.py编写第一个模型。
# -*- coding:utf-8 -*-
from django.db import models
class Students(models.Model):
id = models.AutoField(verbose_name=u'ID',primary_key=True)
name = models.CharField(verbose_name=u'姓名',max_length=255)
free = models.BooleanField(verbose_name=u'免费',default=True)
score = models.IntegerField(verbose_name=u'评分',default=0)
SEXS = {
(0,u'男'),
(1,u'女')
}
sex = models.SmallIntegerField(verbose_name=u'性别',default=0,choices=SEXS)
TYPES = {
(1,'初级'),
(2,'中级'),
(3,'高级')
}
type = models.IntegerField(verbose_name=u'类型',default=1,choices=TYPES)
birthday = models.DateTimeField(verbose_name=u'生日')
photo = models.ImageField(verbose_name=u'照片',upload_to='img')
description = models.TextField(verbose_name=u'介绍',blank=True,null=True)
ctime = models.TimeField(verbose_name=u'创建时间',auto_now_add=True)
下面我们慢慢分析其中的内容。
class Students(models.Model)
定义了一个学生模型,继承models.Model类,实际中就是对应了数据库中的一张学生表。id = models.AutoField(verbose_name=u’ID’, primary_key=True)
id变量定义了一个数据表中的id字段
models.AutoField定义了字段类型,这里是自增长类型
参数verbose_name是该字段的显示名,在前端显示时就不会显示原始字段名
参数primary_key为True定义了这个字段是主键,默认为False
这样就定义了我们Students表的第一个字段,主键自增长ID
这个主键自增长ID基本都不需要写,当模型中没有主键时,系统会自动帮你生成加上这个字段。- name = models.CharField(verbose_name=u’姓名’, max_length=255)
models.CharField => 字符串类型
参数max_length定义了字符串长度255
name => 姓名 字符类型 长度255 - free = models.BooleanField(verbose_name=u’免费’, default=True)
models.BooleanField => 布尔类型
参数default定义了该字段的默认值True
free => 是否免费 布尔类型 默认值True - score = models.IntegerField(verbose_name=u’评分’, default=0)
models.IntegerField => 数字类型
score => 评分 数字类型 默认值0 - sex = models.SmallIntegerField(verbose_name=u’性别’, default=0,
choices=SEXS)
models.SmallIntegerField => 小数字类型
参数choices定义了一个可选择范围SEXS
SEXS = {
(0,u'男'),
(1,u'女')
}
0代表男,1代表女
sex => 性别 小数字类型 默认为男
- type = models.IntegerField(verbose_name=u’类型’, default=1,
choices=TYPES)
type => 类型 数字类型 默认为初级 - birthday = models.DateTimeField(verbose_name=u’生日’)
models.DateTimeField => 时间类型(对应Python的datetime类型)
birthday => 生日 时间类型 - photo = models.ImageField(verbose_name=u’照片’, upload_to=’img’)
models.ImageField => 图片类型
参数upload_to定义了图片上传的文件夹
photo => 照片 图片类型 上传文件夹img - description = models.TextField(verbose_name=u’介绍’, blank=True,
null=True)
models.TextField => 文本类型
参数blank为True定义了字段允许为空值,默认为False
参数null为True定义了空值将会被存储为NULL,默认为False
默认情况下,字段都是不允许为空值的,只有设置后才可以
description => 介绍 文本类型 允许为空值 空值存为NULL - ctime = models.TimeField(verbose_name=u’创建时间’, auto_now_add=True)
models.TimeField => 时间类型(对应Python的time类型)
时间类型还有models.DateField(对应Python的date类型)
参数auto_now_add为True定义了添加时自动写入添加时间
ctime => 创建时间 时间类型 添加时自动写入添加时间
数据库生成
已经创建好了模型,下一步我们就可以用模型生成数据库。
Django的数据库不需要我们手动去建表,而是直接根据模型生成的。
模块初始化:
1.输入命令schemamigration love --initial
,其中love是模块名,来初始化自定义模型。
- 完成后会在love文件夹下生成migrations文件夹,这个文件夹就是记录数据库信息的。
- 现在下面就只有0001_initial.py这个文件夹,代表了刚才所做的数据库结构操作。
- 每次对数据库结构的操作都会表现在后续的xxxx_xxx.py的文件中,稍后就会根据最后的.py文件来对数据库进行修改。
2.输入命令migrate love,其中love是模块名,这步就会生成表到数据库了。
3.查看数据库就有了love_students这张表。
修改数据库结构:
1.修改models.py,比如添加一个字段
remark = models.CharField(verbose_name=u'备注', max_length=255)
2.输入命令schemamigration love --auto
,love是模块名。
此时出现了一个选择项,因为我们新加了一个字段,但数据库中已有的数据需要给新加的字段赋一个默认值。
处理方式1:选择选项1退出。修改remark,增加一个default属性。
remark = models.CharField(verbose_name=u'备注', max_length=255, default='')
再执行刚才的命令,就可以了。
处理方式2:选择选项2,直接给已存在的数据赋一个值。
3.完成上面的命令后,在migrationgs里就生成了一个0002_auto__add_field_students_remark.py文件。这个文件就对应了我们刚才对数据库结构的操作。
4.输入命令migrate love,love是模块名。
根据刚才的0002_auto__add_field_students_remark.py文件,对数据库结构进行操作。
5.查看数据库,就多了这个字段
- 在Django中,我们不需要关心数据库的任何细节,就可以完成数据表的创建和修改。
- 这里我们使用的Django版本是1.5,Django1.7以上版本的操作略有不同。
- 这里有个严重警告:schemamigration love –auto有时候执行到一半被中断或者某种特殊原因,会导致后面migrate love一直提示love_xxx已经存在,处理方式一:把love下的migrations,甚至是db.sqlite3数据库全部删了重新创建。处理方式二:你要备份啊,你要有migrations的备份的话,把那部分拷贝过来,重新执行命令,这样只会替换你新增的字段,还有Pycharm执行命令经常导致这种情况发生,这也是我为什么一直选择SublimeText+用终端来执行这些命令
关系数据类型
前面我们已经了解了Django模型中的大部分的基础字段类型,如IntegerField。如果我们需要建立多张表,并且相互之间有关联,这时我们就需要建立多个关系模型。
Django将关系型数据库的关系统一成3种:外键、- 多对多和一对一,对应的字段类型是ForeignKey、ManyToManyField和OneToOneField。
外键 => ForeignKey
1.创建班级Class模型
class Class(models.Model):
name = models.CharField(verbose_name=u'名称', max_length=64)
2. Students模型添加班级外键
cls = models.ForeignKey(Class, verbose_name=u'班级')
models.ForeignKey => 外键
第一个参数Class就是班级模型,说明cls这个字段和Class模型是外键的关系。
models.ForeignKey => 外键
第一个参数Class就是班级模型,说明cls这个字段和Class模型是外键的关系。
3. 命令行修改数据库结构。
注:Class模型的定义必须在Students之前,不然会报没有找到Class的错误。
4. 查看数据库
增加了love_class表
love_students表中就加入了下面的字段。
多对多 => ManyToManyField
1.同外键,先创建一个学科Subject模型
class Subject(models.Model):
name = models.CharField(verbose_name=u'科目', max_length=64)
2. Studetns模型添加多对多关系
subject = models.ManyToManyField(Subject, verbose_name=u'学科')
models.ManyToManyField => 外键
第一个参数Subject就是学科模型,说明subject这个字段和Subject模型是多对多的关系。
3. 命令行修改数据库结构。
4.查看数据库 增加了love_subject表
love_students表没有变化
增加了love_students_subject表(中间表)
5. 这里我们看到Django在处理多对多时,中间表都已经帮我们生成好了。让我们可以更纯粹的去处理业务。
一对一 => OneToOneField
1.创建一个ID卡模型
class IDCard(models.Model):
number = models.CharField(verbose_name=u'卡号', max_length=30)
student = models.OneToOneField(Students, verbose_name=u'学生')
models.OneToOneField => 一对一
第一个参数Stuednts就是学生模型,说明student这个字段和Students模型是一对一的关系。
2.命令行修改数据库结构
3.查看数据库 增加了love_idcard表
后台管理
进入后台管理
建立完模型,我们再访问http://127.0.0.1:8000/admin“,就可以进入我们的管理界面。
输入刚才的superuser的用户名和密码进入(admin/admin)
添加第一个管理模块
在love模块下新建文件adminx.py。这个文件就是xadmin的配置文件,先写入
# -*- coding: utf-8 -*-
import xadmin
from .models import *
class ClassAdmin(object):
list_display = ('id', 'name')
xadmin.site.register(Class, ClassAdmin)
- import xadmin => 导入xadmin
- from .models import * => 从模型中导入所有模型
- class ClassAdmin(object): => 班级管理页面配置
- list_display => 设置管理列表页显示的字段(‘id’, ‘name’),还可以继续添加其他字段
- xadmin.site.register(Class, ClassAdmin) => 注册班级管理页面 将班级模型和班级管理页面连接
2.看管理后台就出现了Classs的菜单,我们已经可以直接增删改查班级模型了。
3.菜单中我们显示的是Classs。我们在模型Class中定义Meta子类。
class Class(models.Model):
name = models.CharField(verbose_name=u'名称', max_length=64)
class Meta:
verbose_name = u'班级'
verbose_name_plural = u'班级'
ordering = ['name', '-id']
- Meta子类定义模型的行为特征。
- verbose_name和verbose_name_plural分别定义了模型的显示名称,一个单数,一个复数。
- ordering定义了列表的默认排序[‘name’, ‘-id’],先正排序name字段,再反排序id字段(负号代表反序)
- Meta的其他参数还包括unique_together(联合主键时使用)等等。
4.不显示ID,ID并不是我们关心的东西。修改list_display = (‘name’, )。
5.添加学科管理SubjcetAdmin
class SubjectAdmin(object):
list_display = ('name', )
xadmin.site.register(Subject, SubjectAdmin)
添加关系模型管理
- 下面我们添加Students管理。
# 学生管理
class StudentsAdmin(object):
list_display = ('name', 'sex', 'free', 'score', 'type', 'birthday', 'cls', 'subject')
style_fields = {'subject': 'checkbox-inline'}
xadmin.site.register(Students, StudentsAdmin)
style_fields定义部分字段的表单显示方式,这里将多对多关系的subject表现为checkbox。
点击添加学生
关系字段的表单显示
- 外键 - 班级自动表现为select形式。
- 多对多 - 学科表现为checkbox形式。
- 但是我们发现学科三个选项都是Subject objcet,班级的三个选项也都是Subject
object。因为我们没设置模型的显示方式,这里就直接将Python的默认类输出形式打印了出来。 - 设置模型的显示方式
class Class(models.Model):
name = models.CharField(verbose_name=u'名称', max_length=64)
class Meta:
verbose_name = u'班级'
verbose_name_plural = u'班级'
ordering = ['name', '-id']
def __unicode__(self):
return self.name
模型中定义类方法unicode,并返回对应的值,这里返回了名称字段。然后再看表单上显示就正常了。
一般会给所有模型都加上unicode方法,返回可以表示这条记录的字段,比如ID,名称等。
- 添加IDCard管理
class IDCardAdmin(object):
list_display = ('number', 'student')
xadmin.site.register(IDCard, IDCardAdmin)
- inlines将有关系的表操作更直观。 一对一的Students。
class IDCardInline(object):
model = IDCard
class StudentsAdmin(object):
# ...
inlines = (IDCardInline, )
添加IDCardInline类,定义其中的model为IDCard。
StudetnsAdmin类中添加inlines = (IDCardInline, )就可以了。
在添加学生时就出现了ID卡号的填写。
inlines中,Inline类的模型必须有字段是Admin类的OneToOneField或ForeignKey。
列表页额外操作
- 额外字段添加,并在列表页显示
如果我们想在列表中除了显示生日,还显示出当前的年龄,就要在students里面添加额外的字段。
额外字段并不是真实存在的字段,而是一个模型类的类方法,但是可以在list_display中。
在Students模型中加入下面的代码
def age(self):
import datetime
_age = datetime.datetime.now().year - self.birthday.year
return str(_age) + u'岁'
age.short_description = u'年龄'
age方法中,我们计算了年龄,并返回多少岁。
age.short_description定义了age字段的显示名称。
然后在StudentsAdmin的list_display中加上’age’,就会在列表页显示了。
- 搜索功能
在StudentsAdmin中添加
search_fields = ('name', )
列表页就可以输入关键字进行搜索了,可以设置多个字段,但必须是数据库字段。
一般将文本设置为搜索,其他类型可以设置成过滤。
- 过滤功能
同样在StudentsAdmin中添加
list_filter = ('sex', 'free', 'score', 'type', 'birthday', 'cls', 'subject')
列表页就会提供这些字段的过滤功能。
一般将数字,时间,选项等设置成过滤。
结果
数据库操作
查询所有数据
urls => url(r’^query_all/$’, ‘love.views.query_all’)
views
from models import *
import json
def query_all(request)
# 获得所有数据
students = Students.objects.all()
data = [i.name for i in students]
return HttpResponse(json.dumps(data, ensure_ascii=False))
- from models import * => 导入所有模型
- Students.objects => 学生模型的实体数据对象
- all() => all方法是获得所有对象
- [i.name for i in students] => all方法返回数组,其中每项都可以用.属性名的方式获得对应数据
- HttpResponse(json.dumps(data, ensure_ascii=False)) => 返回json数据
- 访问http://127.0.0.1:8000/query_all/得到对应结果
查询一个
urls => url(r’^query_get/(?P.+)/$’, ‘love.views.query_get’)
views
def query_get(request, name):
# 查询一个
try:
student = Students.objects.get(name=name)
return HttpResponse(student.name)
except Exception, e:
return HttpResponse('不存在')
- get(查询条件) => get方法会根据查询条件,返回一条数据。当没有数据时,抛出异常
- 查询条件 => key=value形式,可以有多个,如get(name=’a’, type=1)
- 访问http://127.0.0.1:8000/query_get/ZergL/得到结果
- 查询条件
key__exact = value => 基本的查询条件形式就是 key = value
key__contains = value => 字符串包含条件
key__startswith = value => 字符串开头
key__endswith = value => 字符串结尾
key__gt = value => 大于
key__gte = value => 大等于
key__lt = value => 小于
key__lte = value => 小等于
key__in = [] => 存在于一个list范围内
key__isnull = bool => 是否为空
foreignkey_key__** => value => 外键查询条件
前面的查询语句就可以写为
students = Students.objects.filter(name__contains=name, cls__name__contains=cls)
排序order_by
Students.objects.order_by('id')
Students.objects.order_by('id').get()
exclude() 与filter相反,排除某些项,用法同filter
增
- 方式一
urls => url(r’^add_student/(?P.+)/(?P.+)/$’, ‘love.views.add_student’)
views
def add_student(request, name, cls):
cls = Class.objects.get(name__contains=cls)
subjects = Subject.objects.all()
student = Students(name=name, free=True, score=1,
sex=1, type=1, birthday=datetime.now(),
description='a', remark='a', cls=cls,
subject=subjects)
student.subject.add(Subject.objects.all())
student.save()
return HttpResponse('ok')
创建一个Students对象,执行save方法就可以了。
student.subject.add(Subject.objects.all()) => 多对多关系添加数据。
- 方式二
- views
Students.objects.create(name=name, free=True, score=1,
sex=1, type=1, birthday=datetime.now(),
description='a', remark='a', cls=cls,
subject=subjects)
改
- 方式一
urls => url(r’^update_student/(?P.+)/(?P.+)’, ‘demo.views.update_student’)
views
def update_student(request, name, remark):
Students.objects.filter(name__contains=name).update(remark=remark)
return HttpResponse('ok')
先filter查询,后update。
- 方式二
views
student = Students.objects.get(name__contains=name)
student.remark = remark
student.save()
先查询到数据,再修改,最后save
删
- 与修改差不多
urls => url(r’^delete_student/(?P.+)/’, ‘love.views.delete_student’)
views
def delete_student(request, name):
Students.objects.filter(name__exact=name).delete()
return HttpResponse('ok')
- 更多
模型建立 https://docs.djangoproject.com/en/1.5/topics/db/models/
模型数据类型 https://docs.djangoproject.com/en/1.5/ref/models/fields/
模型Meta属性 https://docs.djangoproject.com/en/1.5/ref/models/options/
模型操作 https://docs.djangoproject.com/en/1.5/topics/db/queries/
模型方法 https://docs.djangoproject.com/en/1.5/ref/models/instances/
模板
以上代码模板放置于 http://pan.baidu.com/s/1kVdrbKj 的01_创建myblog
xadmin插件开发
简单插件开发
插件开发就是管理页面右上角的功能开发
比如导出功能就是一个内置的插件。下面我们写一个简单的插件来学习。
1.在模块下建立plugins.py文件,在这里编写插件。
2.编写插件
# -*- coding: utf-8 -*-
from django.http import HttpResponse
from django.template import loader
from xadmin.views import BaseAdminPlugin
class DemoPlugin(BaseAdminPlugin):
demo_plugin = False
def init_request(self, *args, **kwargs):
return self.demo_plugin
def block_top_toolbar(self, context, nodes):
if self.demo_plugin:
content = 'Python + Django + xadmin 快速开发教程'
context.update({
'about_content': content
})
nodes.append(
loader.render_to_string('xadmin/blocks/model_list.top_toolbar.demo.html',
context_instance=context)
)
from xadmin.views import BaseAdminPlugin => 导入要继承的插件类
init_request => 初始化,是否实例化插件,当返回False时,不显示插件
block_top_toolbar => 显示在上面工具栏的实例化方法
context.update({}) => 更新模板内容
nodes.append() => 添加节点,即这个插件
loader.render_to_string => 根据模板文件渲染插件
‘xadmin/blocks/model_list.top_toolbar.demo.html’ => 模板文件
3.在templates文件夹下建立xadmin/blocks/model_list.top_toolbar.demo.html模板文件
{% load i18n %}
<div class="btn-group export">
<a class="btn btn-primary btn-sm" data-toggle="modal" data-target="#msg_rule" href="#">
<i class="fa fa-question-circle"></i>关于
</a>
<div id="msg_rule" class="modal fade">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title">关于</h4>
</div>
<div class="modal-body">
{{ about_content|safe }}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">{% trans "Close" %}</button>
</div>
</div>
</div>
</div>
</div>
这里就是点击后会出现一个模态宽,显示对应的about_content内容。
插件的模板文件一般会写在xadmin的blocks目录下,并指名model_list.top_toolbar的位置,这样与xadmin框架一样,也方便后期重写xadmin的模板文件。
4.注册插件,在adminx.py中添加
from .plugins import *
from xadmin.views import ListAdminView
xadmin.site.register_plugin(DemoPlugin, ListAdminView)
from xadmin.views import ListAdminView => 导入管理页面View
xadmin.site.register_plugin(DemoPlugin, ListAdminView) => 注册插件
每个插件都要注册,才可用。
5.此时init_request中返回的demo_plugin变量还是False,所以还无法显示。
6.在StuedntsAdmin中添加demo_plugin = True这个变量。在Students这个管理页面就可以显示这个插件了。在对应的管理页面写入,就可以控制插件显示的页面。
高级插件开发
1.上面的插件只与页面相关,二高级的插件开发就与具体请求相关,下面开始编写一个自定义查询插件。
2.首先还是要有一个插件按钮,和上面的步骤一致
plugins.py
class QueryMenuPlugin(BaseAdminPlugin):
demo_query_menu = False
def init_request(self, *args, **kwargs):
return self.demo_query_menu
def block_top_toolbar(self, context, nodes):
if self.demo_query_menu:
nodes.append(
loader.render_to_string('xadmin/blocks/model_list.top_toolbar.demo_query.html',
context_instance=context)
)
xadmin/blocks/model_list.top_toolbar.demo_query.html
{% load i18n %}
<div class="btn-group export">
<a class="btn btn-primary btn-sm" data-toggle="modal" data-target="#msg_query_score" href="#">
<i class="fa fa-money"></i>积分查询
</a>
<div id="msg_query_score" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<form method="post" action="">{% csrf_token %}
<input type="hidden" name="demo_do" value="query">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title">积分查询</h4>
</div>
<div class="modal-body">
<div class="input-group">
<span class="input-group-addon">姓名</span>
<input name="name" type="text" class="form-control" placeholder="多个姓名用|分割">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">{% trans "Close" %}</button>
<button class="btn btn-success" type="submit"><i class="fa fa-money"></i>查询</button>
</div>
</form>
</div>
</div>
</div>
</div>
模板中添加了一个查询的post请求,直接请求当前页面(action=”“)
adminx.py 注册并添加
xadmin.site.register_plugin(QueryMenuPlugin, ListAdminView)
demo_query_menu = True
但此时点击查询只会调回原页面,没有任何功能,下面我们就要利用插件的开发来完成这个功能。
3.查询功能的post请求中有一个隐藏的input , 我们就要用这个参数来完成功能。 在plugins.py中先写入
class QueryPlugin(BaseAdminPlugin):
def init_request(self, *args, **kwargs):
return self.request.POST.get('demo_do') == 'query'
查询插件在初始化时就不再是写死的了,而是根据POST请求,当demo_do参数是query时,才实例化。
这个插件不再是简单地添加一个功能按钮,所以没有block_top_toolbar方法,下面要添加其他方法来完成功能。
4.plugins.py
from django.template import loader
from django.template.response import TemplateResponse
from xadmin.views import BaseAdminPlugin
from xadmin.plugins.actions import BaseActionView
from .models import *
class QueryView(BaseActionView):
def do_action(self, context):
return TemplateResponse(self.request, self.get_template_list('views/demo_query.html'), context, current_app=self.admin_site.name)
class QueryPlugin(BaseAdminPlugin):
def init_request(self, *args, **kwargs):
return self.request.POST.get('demo_do') == 'query'
def response_action(self, ac, context):
if isinstance(ac, type) and issubclass(ac, BaseActionView):
action_view = self.get_model_view(ac, self.admin_view.model)
action_view.init_action(self.admin_view)
return action_view.do_action(context)
else:
return ac(self.admin_view, self.request, context)
def get_response(self, response, context, *args, **kwargs):
names = self.request.POST.get('name')
studetns = []
if names is u'':
studetns = Students.objects.all()
else:
names = (i.strip() for i in names.split('|'))
studetns = Students.objects.filter(name__in=names)
context.update({
'studetns': studetns,
})
return self.response_action(QueryView, context)
from xadmin.plugins.actions import BaseActionView => 导入xadmin的一种基本页面类,用于生成结果页面。还有其他类型,这里就用BaseActionView。
QueryView => 继承BaseActionView,查询结果页面。
do_action(self, context) => BaseActionView的继承方法,返回渲染的页面。
get_response(self, response, context, *args, **kwargs) => 继承方法,完成当插件被启用后的处理。
response_action(self, ac, context) => 生成页面方法,当参数ac是BaseActionView时,生成新页面。
这里根据POST参数name查询了Students模型,并返回了查询结果。
5.views/demo_query.html
{% extends base_template %}
{% load i18n l10n %}
{% load url from future %}
{% load xadmin_tags %}
{% block breadcrumbs %}
<ul class="breadcrumb">
<li><a href="{% url 'xadmin:index' %}">{% trans 'Home' %}</a></li>
<li><a href="{% url opts|admin_urlname:'changelist' %}">{{ opts.verbose_name_plural|capfirst }}</a></li>
<li>{% trans "Export" %} App</li>
</ul>
{% endblock %}
{% block nav_title %}
积分查询
{% endblock %}
{% block content %}
<table class="table table-bordered table-hover table-condensed">
<thead>
<tr>
<th>姓名</th>
<th>积分</th>
</tr>
</thead>
<tbody>
{% for s in students %}
<tr>
<td>{{ s.name }}</td>
<td>{{ s.score }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="form-actions well well-sm">
<form method="post" action="">{% csrf_token %}
<button class="btn btn-default" ><i class="fa fa-backward"></i> 返回</button>
</form>
</div>
{% endblock %}
一个BaseActionView的模板文件,主要完成的就是{% block content %}到{% endblock %}间的页面内容。其他部分基本不变。
我们将views模板都写在views文件夹下。
6.注册插件xadmin.site.register_plugin(QueryPlugin, ListAdminView)
7.输入名字查询积分,就看到下面的页面
插件原理
在上面的例子中,我们看到我们创建了两个插件,一个是简单的按钮显示和出发表单,另一个则是根据请求内容来完成对应的功能,来完成功能。
其实在请求当前页面时,系统会遍历所有注册插件,根据配置或请求的内容来决定如何展示插件。
我们这里所做的查询插件就是直接拦截了原本应该完成正常管理页面的方法,转而显示我们自定义的页面。
Action开发
Action其实是内置的Action插件的进一步开发,可以针对选择的项进行操作。
比如删除这样的操作,我们要开发的功能也会在这里出现。
简单Action
1.模块下建立actions.py。
from xadmin.plugins.actions import BaseActionView
class DemoAction(BaseActionView):
action_name = "Demo_Action"
description = u'设置免费 %(verbose_name_plural)s'
model_perm = 'change'
def do_action(self, queryset):
for obj in queryset:
obj.free = True
obj.save()
return None
- Action直接继承BaseActionView
- action_name => Action的唯一标示, 尽量用比较针对性的名字
- description => 描述, 出现在 Action 菜单中, 可以使用 %(verbose_name_plural)s 代替
Model 的名字 - model_perm => 该 Action 所需权限
- do_action => 继承方法,实际操作
- queryset => 选择项,遍历就可以得到对应的数据,这里将每项的free设置为True
- return None => 返回None则完成后直接返回当前页面,也可以返回其他HttpResponse。
2.添加Action,在StudentsAdmin里添加actions = [DemoAction, ]。
就出现了设置免费的操做。
复杂Action
复杂Action就是多个页面的Action,下面我们做一个确认页面来做说明。
1. 与高级插件开发一样,利用post请求的参数来判断返回的页面。 2. actions.py
ACTION_CHECKBOX_NAME = '_selected_action'
class SubjectAction(BaseActionView):
action_name = "Subject_Action"
description = u'批量修改学科'
model_perm = 'change'
def do_action(self, queryset):
if self.request.POST.get('finish') and self.request.POST.get('action') == self.action_name:
subjects = []
for i in Subject.objects.all():
if self.request.POST.get(str(i.id)) == u'on':
subjects.append(i)
for i in queryset:
i.subject = subjects
i.save()
return None
return self.comfirm_view(queryset)
def comfirm_view(self, queryset):
objects_name = force_unicode(self.opts.verbose_name)
app_th = [u'姓名']
app_td = [[app.name] for app in queryset]
context = self.get_context()
context.update({
"title": _("Are you sure?"),
"objects_name": objects_name,
'queryset': queryset,
"opts": self.opts,
"app_label": self.app_label,
'action_checkbox_name': ACTION_CHECKBOX_NAME,
'subjects': Subject.objects.all(),
'app_th': app_th,
'app_td': app_td,
})
return TemplateResponse(self.request,
self.get_template_list('views/demo_confirm.html'),
context,
current_app=self.admin_site.name)
comfirm_view => 确认页面
do_action中根据前台POST数据来决定如何操作,这里默认情况下回返回确认页面,然后确认页面上传action,finish以及选择的学科参数来完成学科的批量修改。
views/demo_confirm.html
{% extends base_template %}
{% load i18n l10n %}
{% load url from future %}
{% load xadmin_tags %}
{% block breadcrumbs %}
<ul class="breadcrumb">
<li><a href="{% url 'xadmin:index' %}">{% trans 'Home' %}</a></li>
<li><a href="{% url opts|admin_urlname:'changelist' %}">{{ opts.verbose_name_plural|capfirst }}</a></li>
<li>{% trans "Export" %} App</li>
</ul>
{% endblock %}
{% block nav_title %}
{{title}}
{% endblock %}
{% block content %}
<table class="table table-bordered table-hover table-condensed">
<thead>
<tr>
{% for foo in app_th %}
<th>{{ foo }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for foo in app_td %}
<tr>
{% for i in foo %}
<td>{{ i|safe }}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
<div class="form-actions well well-sm">
<a class="btn btn-danger btn-lg"
data-toggle="modal"
data-target="#export-app-modal"
>
{% trans "Yes, I'm sure" %}
</a>
<a class="btn btn-default pull-right"
onclick="javascript:history.back();" >
{% trans 'Cancel' %}
</a>
</div>
<div id="export-app-modal" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<form method="post" action="">{% csrf_token %}
<div class="modal-header">
<h4 class="modal-title">{% trans "Export" %} {{et.name}}</h4>
</div>
<div class="modal-body">
{% for obj in queryset %}
<input type="hidden" name="{{ action_checkbox_name }}" value="{{ obj.pk|unlocalize }}" />
{% endfor %}
<input type="hidden" name="action" value="Subject_Action" />
<input type="hidden" name="finish" value="yes" />
{% view_block 'form_fields' %}
{% for type in subjects %}
{% if type.checked %}
<label class="checkbox">
<input type="checkbox" name="{{ type.id }}" checked="checked" value="on"> {{ type.name }}
</label>
{% else %}
<label class="checkbox">
<input type="checkbox" name="{{ type.id }}" value="on"> {{ type.name }}
</label>
{% endif %}
{% endfor %}
</div>
<div class="modal-footer">
<button id="myButton" class="btn btn-success btn-lg ladda-button center-block" data-loading-text="打包中...请耐心等待..."><i class="fa fa-apple"></i> 开始打包
<span class="ladda-label">
</span>
</button>
</div>
<script>
$('#myButton').on('click', function () {
var $btn = $(this).button('loading')
})
</script>
</form>
</div><!-- /.modal-content -->
</div><!-- /.modal-dalog -->
</div><!-- /.modal -->
{% endblock %}