Django学习(4)Model类操作自带数据库sqlite3

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 方法


  1. 数据库配置-Django开发文档

  2. 多对多添加的方法

  3. cnblogs-BigJ-双下划线查询总结

  4. 通过 Q 对象完成复杂查询

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,552评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,666评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,519评论 0 334
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,180评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,205评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,344评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,781评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,449评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,635评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,467评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,515评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,217评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,775评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,851评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,084评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,637评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,204评论 2 341

推荐阅读更多精彩内容