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= 30) 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 0 object(s) from 0 fixture(s)到这会看到,Django生成了一系列的表,也生成了新建的people_persona这个表,想知道如何使用这个表,请继续往下看。
Django提供了丰富的API,下面演示如何使用它。
root@w:~/learn_models# python manage.py shell Python 2.7. 10 ( default, Oct 14 2015, 16: 09: 02) [GCC 5.2. 1 20151010] on linux2 Type " help ", " copyright ", " credits " or " license " for more information. (InteractiveConsole) >>> from people.models import Person >>> Person.objects.create(name= " wulaoer ", age= 20) <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= 30) 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>新建一个对象的方法有以下几种:
1、Person.objects.create(name=name,age=age) 2、p = Person(name="wulaoer", age=23) p.save() 3、p = Person(name="laowu") p.age = 23 p.save() 4、Person.objects.get_or_create(name="laowu", age=23)这种方法是防止重复很好的方法,但是速度要相对慢些,返回一个元组,第一个为Person对象,第二个为True或False,新建时返回的是True,已经存在时返回False。
获取对象有以下方法:
1、Person.objects.all() 2、Person.objects.all()[:10] 切片操作,获取10个人,不支持负索引,切片可以节约内存 3、Person.objects.get(name=name) get是用来获取一个对象的,如果需要获取满足条件的一些人,就要用到filter 4、Person.objects.filter(name="abc") # 等于Person.objects.filter(name__exact="abc") 名称严格等于 "abc" 的人 5、Person.objects.filter(name__iexact="abc") # 名称为 abc 但是不区分大小写,可以找到 ABC, Abc, aBC,这些都符合条件 6、Person.objects.filter(name__contains="abc") # 名称中包含 "abc"的人 7、Person.objects.filter(name__icontains="abc") #名称中包含 "abc",且abc不区分大小写 8、Person.objects.filter(name__regex="^abc") # 正则表达式查询 9、Person.objects.filter(name__iregex="^abc")# 正则表达式不区分大小写 filter是找出满足条件的,当然也有排除符合某条件的 10、Person.objects.exclude(name__contains="LW") # 排除包含 LW 的Person对象 11、Person.objects.filter(name__contains="abc").exclude(age=23) # 找出名称含有abc, 但是排除年龄是23岁的 二、Django 自定义(Field)Django 的官方提供了很多的Field,但是有时候还是不能满足我们的需求,不过Django提供了自定义Field的方法:
提示:如果现在用不到可以跳过这一节,不影响后面的学习,等用到的时候在学习也可以。
这里举一个简单的例子。
1、减少文本的长度,保存数据的时候压缩,读取的时候解压缩,如果发现压缩后更长,就用原文本直接存储:
1 class CompressedTextField(models.TextField): 2 """ model Fields for storing text in a compressed format (bz2 by default) """ 3 __metaclass__ = models.SubfieldBase 4 5 def to_python(self, value): 6 if not value: 7 return value 8 9 try: 10 return value.decode('base64').decode('bz2').decode('utf-8') 11 except Exception: 12 return value 13 14 def get_prep_value(self, value): 15 if not value: 16 return value 17 18 try: 19 value.decode('base64') 20 return value 21 except Exception: 22 try: 23 tmp = value.encode('utf-8').encode('bz2').encode('base64') 24 except Exception: 25 return value 26 else: 27 if len(tmp) > len(value): 28 return value 29 30 return tmpto_python函数用于转化数据库中的字符到python的变量,get_prep_value用于将python变量处理后(此处为压缩)保存到数据库,使用和Django自带的Field一样。
2、比如想保存一个列表到数据库中,在读取用的时候要python的列表的形式,我们来自己写一个ListField:
这个ListField继承自TextField,代码如下:
1 from django.db import models 2 import ast 3 4 class ListField(models.TextField): 5 __metaclass__ = models.SubfieldBase 6 description = "Stores a python list" 7 8 def __init__(self, *args, **kwargs): 9 super(ListField, self).__init__(*args, **kwargs) 10 11 def to_python(self, value): 12 if not value: 13 value = [] 14 15 if isinstance(value, list): 16 return value 17 18 return ast.literal_eval(value) 19 20 def get_prep_value(self, value): 21 if value is None: 22 return value 23 24 return unicode(value) # use str(value) in Python 3 25 26 def value_to_string(self, obj): 27 value = self._get_val_from_obj(obj) 28 return self.get_db_prep_value(value)这个使用很简单,首先导入ListField,像自带的Field一样使用:
1 class Article(models.Model): 2 labels = ListField()在终端上尝试:
1 >>> from app.models import Article 2 >>> d = Article() 3 >>> d.labels 4 [] 5 >>> d.labels = ["Python", "Django"] 6 >>> d.labels 7 ["Python", "Django"]示例代码
下载上面的代码,解压,进入项目目录,输入python manage.py shell搞起
1 >>> from blog.models import Article 2 3 >>> a = Article() 4 >>> a.labels.append('Django') 5 >>> a.labels.append('custom fields') 6 7 >>> a.labels 8 ['Django', 'custom fields'] 9 10 >>> type(a.labels) 11 <type 'list'> 12 13 >>> a.content = u'我正在写一篇关于自定义Django Fields的教程' 14 >>> 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 South2、使用方法
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 --autoSouth就会帮助我们找出哪些地方做了修改,如果你新增的数据表没有给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/
转载于:https://www.cnblogs.com/wulaoer/p/5102425.html