一、Django 模型(数据库) |
Django模型是与数据库相关的,与数据库相关的代码一般写在models.py中,Django支持sqlite3,MySQL,PostgreSQL等数据库,只需要在settings.py中配置即可,不用更改models.py中的代码,丰富的API极大的方便了使用。
本节的代码:(Django 1.6,Python 2.7 测试环境)
可以按照我的步骤来开始做:
root@w:~# django-admin startproject learn_models #新建一个项目
root@w:~# cd learn_models/ #进入该项目的文件夹
root@w:~/learn_models# django-admin startapp people #新建一个people应用(app)
补充:新建app也可以用python manage.py startapp people,需要指出的是,django-admin.py是安装Django后多出的一个命令,并不是指一个django-admin.py脚本在当前目录下。
那么project和app什么关系呢,一个项目一般包含多个应用,一个应用也可以用在多个项目中。
将我们新建的应用(people)添加到settings.py中的INSTALLED_APPS中,也就是告诉Django有这么一个应用。
root@w:~# sudo vi learn_models/learn_models/settings.py
...................省略部分........................
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'people',
)
...................省略部分........................
我们打开people/models.py文件,修改其中的代码如下:
root@w:~# sudo vi learn_models/people/models.py from django.db import models
class Person(models.Model):
name = models.CharField(max_length=)
age = models.IntegerField()
新建了一个Person类,继承自models.Model,一个人有姓名和年龄。这里用到了两种Field,更多猛插这里
Fields相关官方文档:https://docs.djangoproject.com/en/dev/ref/models/fields/
同步以下数据库
python manage.py syncdb # 进入 manage.py 所在的那个文件夹下输入这个命令
注意:Django 1.7 及以上的版本需要用以下命令
python manage.py makemigrations
python manage.py migrate
root@w:~# cd learn_models/
root@w:~/learn_models# python manage.py syncdb
Creating tables ...
Creating table django_admin_log
Creating table auth_permission
Creating table auth_group_permissions
Creating table auth_group
Creating table auth_user_groups
Creating table auth_user_user_permissions
Creating table auth_user
Creating table django_content_type
Creating table django_session
Creating table people_person You just installed Django's auth system, which means you don't have any superusers defined.
Would you like to create one now? (yes/no): yes
Username (leave blank to use 'root'): root#数据库用户名
Email address:
Password: #数据库密码
Password (again):
Superuser created successfully.
Installing custom SQL ...
Installing indexes ...
Installed object(s) from fixture(s)
到这会看到,Django生成了一系列的表,也生成了新建的people_persona这个表,想知道如何使用这个表,请继续往下看。
Django提供了丰富的API,下面演示如何使用它。
root@w:~/learn_models# python manage.py shell
Python 2.7. (default, Oct , ::)
[GCC 5.2. ] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from people.models import Person
>>> Person.objects.create(name="wulaoer", age=)
<Person: Person object>
新建了一个用户wulaoer,那么如果从数据库中查询到它呢?
>>> Person.objects.get(name="wulaoer")
<Person: Person object>
这里用到了.objects.get()方法查询出来符合条件的对象,但是上面的查询结果显示<Person: Person object>,这里并没有显示出与wulaoer相关的信息,如果用户多了就无法知道查询出来的到底是谁,查询结果是否正,我们重新修改以下
name和age等字段中不能有__(双下划线,因为在Django QuerySet API中有特殊含义(用于关系,包含,不区分大小写,以什么开头或结尾,日期的大于小于,正则等))
也不能有Python中的关键字,name 是合法的,student_name也合法,但是student__不合法,try,class,continue也不合法,因为它是Python的关键字(import keyword; print(keyword.kwlist)可以打出所有的关键字)
root@w:~# sudo vi learn_models/people/models.py from django.db import models
class Person(models.Model):
name = models.CharField(max_length=)
age = models.IntegerField()
def __unicode__(self):
#在Python3中使用 def __str__(self)
return self.name
按CTRL + C或exit()退出的Python shell,重复上面的操作,我们就可以看到:
>>> from people.models import Person
>>> Person.objects.get(name="wulaoer")
<Person: wulaoer>
新建一个对象的方法有以下几种:
这种方法是防止重复很好的方法,但是速度要相对慢些,返回一个元组,第一个为Person对象,第二个为True或False,新建时返回的是True,已经存在时返回False。
获取对象有以下方法:
二、Django 自定义(Field) |
Django 的官方提供了很多的Field,但是有时候还是不能满足我们的需求,不过Django提供了自定义Field的方法:
提示:如果现在用不到可以跳过这一节,不影响后面的学习,等用到的时候在学习也可以。
这里举一个简单的例子。
1、减少文本的长度,保存数据的时候压缩,读取的时候解压缩,如果发现压缩后更长,就用原文本直接存储:
class CompressedTextField(models.TextField):
""" model Fields for storing text in a compressed format (bz2 by default) """
__metaclass__ = models.SubfieldBase def to_python(self, value):
if not value:
return value try:
return value.decode('base64').decode('bz2').decode('utf-8')
except Exception:
return value def get_prep_value(self, value):
if not value:
return value try:
value.decode('base64')
return value
except Exception:
try:
tmp = value.encode('utf-8').encode('bz2').encode('base64')
except Exception:
return value
else:
if len(tmp) > len(value):
return value return tmp
to_python函数用于转化数据库中的字符到python的变量,get_prep_value用于将python变量处理后(此处为压缩)保存到数据库,使用和Django自带的Field一样。
2、比如想保存一个列表到数据库中,在读取用的时候要python的列表的形式,我们来自己写一个ListField:
这个ListField继承自TextField,代码如下:
from django.db import models
import ast class ListField(models.TextField):
__metaclass__ = models.SubfieldBase
description = "Stores a python list" def __init__(self, *args, **kwargs):
super(ListField, self).__init__(*args, **kwargs) def to_python(self, value):
if not value:
value = [] if isinstance(value, list):
return value return ast.literal_eval(value) def get_prep_value(self, value):
if value is None:
return value return unicode(value) # use str(value) in Python def value_to_string(self, obj):
value = self._get_val_from_obj(obj)
return self.get_db_prep_value(value)
这个使用很简单,首先导入ListField,像自带的Field一样使用:
class Article(models.Model):
labels = ListField()
在终端上尝试:
>>> from app.models import Article
>>> d = Article()
>>> d.labels
[]
>>> d.labels = ["Python", "Django"]
>>> d.labels
["Python", "Django"]
下载上面的代码,解压,进入项目目录,输入python manage.py shell搞起
>>> from blog.models import Article >>> a = Article()
>>> a.labels.append('Django')
>>> a.labels.append('custom fields') >>> a.labels
['Django', 'custom fields'] >>> type(a.labels)
<type 'list'> >>> a.content = u'我正在写一篇关于自定义Django Fields的教程'
>>> a.save()
三、Django 数据表更改 |
在工作中我们设计数据库的时候,早期设计完后,后期发现不完善,要对数据表进行更改,这时候就要用到下面的知识了。
Django 1.7.x 和后来的版本:
python manage.py makemigrations
python manage.py migrate
这两个命令就是对models.py进行检测,自动发现需要更改的,应用到数据库中。
Django 1.6.x 及以前:
在Django 1.6以及以前的版本中,我们测试,当发现model要更改,怎么办?
修改了models.py之后,我们运行:
python manage.py syncdb
这个命令只会将我们在models.py中新加的类创建相应的表。
对于原来有的,现在删除了类,Django会询问是否要删除数据库中已经存在的相关数据表。
如果在原来的类上增加字段或者删除字段,可以参考这个命令:
python manage.py sql appname
给出的SQL语句,然后自己手动到数据库执行SQL。但是这样容易出错!
Django的第三方 app South就是专门做数据库表结构自动迁移工作,Jacob Kaplan-Moss曾做过一次调查,South名列最受欢迎的第三方app。事实上,它现在已经俨然成为Django事实上的数据库表迁移标准,很多第三方app都会带South migration脚本,Django 1.7中集成了South的功能。
1、安装South
(sudo) pip install South
2、使用方法
South的宗旨是简单,只需要几步。针对已经建好model和创建完表的应用。
把south加入到settings.py中的INSTALL_APPS中
# Application definition
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles', 'blog',
'south',
)
修改好之后运行一次python manage.py syncdb,Django会新建一个south_migrationhistory表,用来记录数据表更改(Migration)的历史记录。
$ python manage.py syncdb
Syncing...
Creating tables ...
Creating table south_migrationhistory
Installing custom SQL ...
Installing indexes ...
No fixtures found. Synced:
> django.contrib.admin
> django.contrib.auth
> django.contrib.contenttypes
> django.contrib.sessions
> django.contrib.messages
> django.contrib.staticfiles
> blog
> south Not synced (use migrations):
把之前建好的blog这个app使用South来管理:
$ python manage.py convert_to_south blog
这时,你会发现blog文件夹中多了一个migration目录,里面有一个0001_initial.py文件。
注:如果blog这个app之前就创建过相关的表,可以用下面的来“假装”用South创建(伪创建,在改动models.py之前运行这个)
python manage.py migrate blog --fake
意思是这个表我以前已经创建好了,用South只是记一下这个创建记录,下次migrate的时候不必在创建了。
原理就是south_migrationhistory中记录下了models.py的修改的历史,下次在修改时会和最近一次记录比较,发现改变了什么,然后生成相应的对应文件,最终执行相应的SQL更改原有的数据表。
接着,当你对Blog.models做任何修改后,只要执行:
python manage.py schemamigration blog --auto
South就会帮助我们找出哪些地方做了修改,如果你新增的数据表没有给default值,并且没有设置null=True,south会问你一些问题,因为新增的column对于原来的旧的数据不能为Null的话就得有一个值。顺利的话,在migrations文件夹下会产生一个002_add_mobile_column.py,但是这一步并没有真正修改数据库的表,我们需要执行python manage.py migrate:
$ python manage.py migrate
Running migrations for blog:
- Migrating forwards to 0002_add_mobile_column.
> blog:0002_add_mobile_column
- Loading initial data for blog.
No fixtures found.
这样所做的更改就写入了数据库中。
恢复到以前
South好处就是可以随时恢复到之前的一个版本,比如我们想要回到最开始的哪个版本:
> python manage.py migrate blog 0001
- Soft matched migration 0001 to 0001_initial.
Running migrations for blog:
- Migrating backwards to just after 0001_initial.
< blog:0002_add_mobile_column
这样就搞定了,数据库就恢复到以前了,比你手动更改要方便多了。
参考网址:
https://djangosnippets.org/snippets/2014/
https://docs.djangoproject.com/en/dev/howto/custom-model-fields/
来源参考:http://www.ziqiangxuetang.com/