Django中自带轻量级数据库sqlite3,创建工程时自动在工程目录中生成一个数据库文件db.sqlite3作为数据库文件。这个单文件数据库可以满足小项目数据库的基本功能要求。Django中的models是数据库建表操作的工具,开发者无须使用复杂的SQL语句,操作简单。
使用HTML的表单操作数据库曾删改查是常规操作,而django自带一个比较完善的后台管理页面,不需要自己动手写。
模型类和自带轻量数据库db.sqlite3的部署[1]
建表步骤
修改INSTALLED_APPS列表
打开settings.py,找到INSTALLED_APPS,这个列表会让项目了解到自己管理着哪些应用,数据库数据表的创建也根据这些应用中的信息来操作。
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'helloapp',
]
在官方文档里,自己的app名写为helloapp.apps.HelloappConfig
,两种写法都可以。
在这个列表中要添加自己的应用,也可以去掉不需要的预装应用(理论上可以去掉,但是想用内置的后台管理页面就都要保留),只有在这个列表中的应用,项目才会为其创建数据库。
编写models.py文件
打开应用目录下的models.py文件,这里写数据表名和字段名等信息,这是数据库建表的依据。举例的写法如下:
class book(models.Model):
book_name = models.CharField(max_length = 100)
belong = models.ForeignKey(Course,on_delete=models.CASCADE)
price = models.IntegerField(default='0')
unlock_code = models.CharField(max_length=16,default=str(uuid.uuid4())[-16:])
def __str__(self):
return self.book_name + ':' + self.price
以上代码建了一个book表,有字符串、外键、数字、随机字符串这几种字段,还有一个magic方法。defaul=
用于设置初始的默认值。str(uuid.uuid4())
是Django内置的32位随机字符串,加上四个横杠分隔符一共36位。
类名即数据表名,成员名即字段名,赋值是用来设定字段类型和限制条件。
执行数据库创建
把models中的代码构建成实际数据库表的过程称为“迁移”。迁移分为两个步骤:准备迁移素材(生成迁移文件.py)、更新数据库(应用数据库迁移)
python manage.py makemigrations (生成迁移文件)
sudo python manage.py migrate (更新数据库,完成迁移)
注:(1)生成的迁移文件存放在一个目录里,可以打开看,但不要手动修改它。(2)在makemigrations执行时程序会检查代码,如果没有新内容系统就不写新的迁移文件。但是我们有时需要强制更新迁移文件,那么在makemigrations后面加上应用名:
python manage.py makemigrations 应用名
在shell中测试数据库使用
在工程目录中执行:
python manage.py shell
from helloapp.models import book
#此命令用于查看表中数据:
book.objects.all()
#第一种添加数据的方法:
i=book(book_name='life',price='10')
i.save()
book.objects.all()
#第二种添加数据的方法:
i=book()
i.book_name='life'
i.save()
book.objects.all()
到此,在数据库中插入了两条数据。
Django默认提供了后台网页来可视化管理数据库,非常方便,详情见下一节。
数据库基本操作:增删改查
以下示例代码模拟在控制台中操作。
增
>>> from blog.models import Blog
>>> b = Blog(name='Beatles Blog', tagline='All the latest Beatles news.')
>>> b.save()
参见
save()
接受很多此处未介绍的高级选项。参考文档save()
获取完整细节。
- 要一步创建并保存一个对象,使用
create()
方法:
p=Person.objects.create(first_name="Bruce", last_name="Springsteen")
如果有重复的主键,create()
方法会抛出异常。
- 要查询是否有某个字段,如果没有就创建,使用
get_or_create()
方法:
obj, newCreate = Person.objects.get_or_create(
first_name='John',
last_name='Lennon',
defaults={'birthday': date(1940, 10, 9)},
)
这个方法返回一个包含两个内容的元组,第一个是查询到的或者新插入的对象,第二个表示是否是新创建的对象。defaults中的内容不作为判断是否是同一个对象的依据,只在新创键对象时作为属性补充,也就是上面的代码等同于以下代码的功能:
try:
obj = Person.objects.get(first_name='John', last_name='Lennon')
except Person.DoesNotExist:
obj = Person(first_name='John', last_name='Lennon', birthday=date(1940, 10, 9))
obj.save()
删
>>> e.delete()
(1, {'weblog.Entry': 1})
e
是一条数据对象,delete()这个方法返回被删除的对象的数量和一个包含了每个被删除对象类型的数量的字典。
QuerySet
都有个 delete()
方法,它会删除 QuerySet
中的所有成员:
>>> Entry.objects.filter(pub_date__year=2005).delete()
(5, {'webapp.Entry': 5})
改
>>> b.name = 'New name'
>>> b5.save()
b
是一条数据的对象, name
是其中的一个字段。
对于自增操作,当这个数据量需要多线程互斥时,使用F表达式:
course.buy_count = F('buy_count') + 1
更新外键,直接把对象赋值到外键字段:
>>> from blog.models import Blog, Entry
>>> entry = Entry.objects.get(pk=1)
>>> cheese_blog = Blog.objects.get(name="Cheddar Talk")
>>> entry.blog = cheese_blog
>>> entry.save()
对于多对多[2],见模型的关联与约束
一次修改多个对象:
Entry.objects.filter(pub_date__year=2007).update(headline='Everything is the same')
查
取一条单独的数据记录对象
>>> one_entry = Entry.objects.get(pk=1)
如果没有满足条件的记录,或者有多个满足条件的记录,get()都会报错。所以按需适当使用try
。
获取对象的外键字段返回的也是一个对象,是外键对应的对象。
取一个数据集合
模型类有一个Manager属性,这个属性可以用数据库中的数据构建一个QuerySet,它代表数据库中的记录对象的一个集合。每个模型至少有一个 Manager
,默认名称是 objects
。直接通过模型类使用它们:
# 检索全部对象:
>>> qs_all = Entry.objects.all()
#通过过滤器检索指定对象,这里加不加all()都可以:
>>> qs_filter = Entry.objects.filter(pub_date__year=2006)
>>> qs_filter = Entry.objects.all().filter(pub_date__year=2006)
#通过过滤器检索不符合的对象:
>>> qs_exclude=Entry.objects.exclude(pub_date__gte=datetime.date.today())
#多重限制条件可以使用链式过滤器:
>>> Entry.objects.filter(
... headline__startswith='What'
... ).exclude(
... pub_date__gte=datetime.date.today()
... ).filter(
... pub_date__gte=datetime.date(2005, 1, 30)
... )
创建 QuerySet
并不会引发任何数据库活动,它表示的数据集直到你 “要使用” 时才会真正操作数据库,从数据库中拿出数据。
多对多检索见模型的关联与约束
QuerySet的操作:
- 排序 order_by()
Entry.objects.filter(pub_date__year=2005).order_by('-pub_date', 'headline')
上面的结果将按pub_date降序排列,然后按 headline升序排列。前面的负号"-pub_date"表示 降序。暗含升序。要随机排列,请使用"?",如下所示:
Entry.objects.order_by('?')
注意:order_by('?')查询可能昂贵且缓慢,具体取决于您所使用的数据库后端。
- 切片[:]
类似列表切片的操作,例如,这将返回前 5 个对象 (LIMIT 5):
>>> Entry.objects.all()[:5]
这会返回第 6 至第 10 个对象 (OFFSET 5 LIMIT 5):
>>> Entry.objects.all()[5:10]
不支持负索引 (例如 Entry.objects.all()[-1])
高级查询[3]
不分大小写的匹配:
Blog.objects.get(name__iexact="beatles blog")
大小写敏感的包含测试:
Entry.objects.get(headline__contains='Lennon')
类似的,大小写不敏感的包含测试: icontains。以……开头:startswith, 以……结尾:endswith。当然也有大小写不分的版本,名为 istartswith 和 iendswith。
使用普通查询,不同参数只有“并且”关系,如果要执行更复杂的查询,使用Q表达式[4],用&、|、~代表与或非,将表达式作为 filter()
, exclude()
, get()
的参数:
courses = courses.filter(
Q(desc__icontains=k)&Q(content__icontains=k)|
~Q(author__icontains=k)
)
使用Q查询时先导入from django.db.models import Q
其他高级用法见开发文档:其它 QuerySet 方法。
-
数据库配置-Django开发文档 ↩
-
多对多添加的方法 ↩
-
cnblogs-BigJ-双下划线查询总结 ↩
-
通过 Q 对象完成复杂查询 ↩