Django支持的数据库

  • PostgreSQL
  • SQLite 3
  • MySQL
  • Oracle

其中SQLite 3不需要安装,因为SQLite使用文件系统上的独立文件来存储数据

这里我们用SQLite 3测试,但如果是大型项目的话建议不要使用SQLite 3

安装sqllite3图形化工具

首先方便查看数据库的变化我们下载一个数据库图形化工具SQLiteStudio

链接:https://sqlitestudio.pl/index.rvt

打开DataBase->Add a database,填写sqllite3的文件路径

这时就能打开了,你会发现是空的,因为我们还没有添加任何数据

了解数据库的配置信息

我们查看一下Django的数据库配置文件setting.py下的DATABASES

  1. DATABASES = {
  2. 'default': {
  3. 'ENGINE': 'django.db.backends.sqlite3',
  4. 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
  5. }
  6. }
  • DATABASE_ENGINE 告诉Django使用哪个数据库引擎
  • DATABASE_NAME 将数据库名称告知 Django,我们也可以自己设置路径,不用django自带的sqlite3

以下选项默认是没有的,因为sqlite3不需要配置,如果你更换了数据库那么你需要配置这些:

  • DATABASE_USER 告诉 Django 用哪个用户连接数据库。 例如: 如果用SQLite,空白即可。
  • DATABASE_PASSWORD 告诉Django连接用户的密码。 SQLite 用空密码即可。
  • DATABASE_HOST 告诉 Django 连接哪一台主机的数据库服务器。 如果数据库与 Django 安装于同一台计算机(即本机),可将此项保留空白。 如果你使用SQLite,此项留空。

这里我们了解以下各个配置就行,因为不换数据库所以不需要做任何更改

如果你使用了其他数据库,那么你可以参考一下这个配置:

  1. import pymysql # 一定要添加这两行!通过pip install pymysql!
  2. pymysql.install_as_MySQLdb()
  3.  
  4. DATABASES = {
  5. 'default': {
  6. 'ENGINE': 'django.db.backends.mysql',
  7. 'NAME': 'mysite',
  8. 'HOST': '192.168.1.1',
  9. 'USER': 'root',
  10. 'PASSWORD': 'pwd',
  11. 'PORT': '',
  12. }
  13. }

输入下面这些命令来测试你的数据库配置:

  1. >>> from django.db import connection
  2. >>> cursor = connection.cursor()

如果没有显示什么错误信息,那么你的数据库配置是正确的。 否则,你就得 查看错误信息来纠正错误。

表 5-2. 数据库配置错误信息
错误信息 解决方法
You haven’t set the DATABASE_ENGINE setting yet. 不要以空字符串配置`` DATABASE_ENGINE`` 的值。 表格 5-1 列出可用的值。
Environment variable DJANGO_SETTINGS_MODULE is undefined. 使用`` python manager.py shell`` 命令启动交互解释器,不要以`` python`` 命令直接启动交互解释器。
Error loading _____ module: No module named _____. 未安装合适的数据库适配器 (例如, psycopg 或 MySQLdb )。Django并不自带适配器,所以你得自己下载安装。
_____ isn’t an available database backend. DATABASE_ENGINE 配置成前面提到的合法的数据库引擎。 也许是拼写错误?
database _____ does not exist 设置`` DATABASE_NAME`` 指向存在的数据库,或者先在数据库客户端中执行合适的`` CREATE DATABASE`` 语句创建数据库。
role _____ does not exist 设置`` DATABASE_USER`` 指向存在的用户,或者先在数据库客户端中执创建用户。
could not connect to server 查看DATABASE_HOST和DATABASE_PORT是否已正确配置,并确认数据库服务器是否已正常运行。

系统对app有一个约定: 如果你使用了Django的数据库层(模型),你 必须创建一个Django app。 模型必须存放在apps中。 因此,为了开始建造 我们的模型,我们必须创建一个新的app。

这在我们day5已经将过了如何创建app和配置app的视图了。

模型的使用

我们来假定下面的这些概念、字段和关系:

  • 一个作者有姓,有名及email地址。

  • 出版商有名称,地址,所在城市、省,国家,网站。

  • 书籍有书名和出版日期。 它有一个或多个作者(和作者是多对多的关联关系[many-to-many]), 只有一个出版商(和出版商是一对多的关联关系[one-to-many],也被称作外键[foreign key])

第一步是用Python代码来描述它们。 打开myapp/models.py 并输入下面的内容:

  1. from django.db import models
  2.  
  3. class Publisher(models.Model):
  4. name = models.CharField(max_length=30)
  5. address = models.CharField(max_length=50)
  6. city = models.CharField(max_length=60)
  7. state_province = models.CharField(max_length=30)
  8. country = models.CharField(max_length=50)
  9. website = models.URLField()
  10.  
  11. class Author(models.Model):
  12. first_name = models.CharField(max_length=30)
  13. last_name = models.CharField(max_length=40)
  14. email = models.EmailField(verbose_name='e-mail',blank=True)#为了指定email字段为可选,要设置blankTrue,默认为False
  15.  
  16. class Book(models.Model):
      title = models.CharField(max_length=100)
      authors = models.ManyToManyField(Author)
      publisher = models.ForeignKey(Publisher,models.CASCADE)
      publication_date = models.DateField(blank=True,null=True)

注意的是每个数据模型都是 django.db.models.Model 的子类。它的父类 Model 包含了所有必要的和数据库交互的方法,并提供了一个简洁漂亮的定义数据库字段的语法。

如果你想允许一个日期型(DateFieldTimeFieldDateTimeField)或数字型(IntegerFieldDecimalFieldFloatField)字段为空,你需要使用null=True 和 blank=True

verbose_name='e-mail'是指定属性名字(一般是以变量名作为属性名,但是如果遇到-等特殊符号就不能作为变量名,那么我们就需要以这种方式命名)

  1.  

这里django1.x于django2.x有个区别,定义外键和一对一关系的时候需要加on_delete选项,此参数为了避免两个表里的数据不一致问题,否则报错。我们一般情况下使用CASCADE就可以了。

on_delete值的详细说明:

  1. on_delete=None, # 删除关联表中的数据时,当前表与其关联的field的行为
  2. on_delete=models.CASCADE, # 删除关联数据,与之关联也删除
  3. on_delete=models.DO_NOTHING, # 删除关联数据,什么也不做
  4. on_delete=models.PROTECT, # 删除关联数据,引发错误ProtectedError
  5. # models.ForeignKey('关联表', on_delete=models.SET_NULL, blank=True, null=True)
  6. on_delete=models.SET_NULL, # 删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空,一对一同理)
  7. # models.ForeignKey('关联表', on_delete=models.SET_DEFAULT, default='默认值')
  8. on_delete=models.SET_DEFAULT, # 删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值,一对一同理)
  9. on_delete=models.SET, # 删除关联数据,
  10. a. 与之关联的值设置为指定值,设置:models.SET(值)
  11. b. 与之关联的值设置为可执行对象的返回值,设置:models.SET(可执行对象)

在创建数据库表前需要把app在setting中设置一下,这在我们day5已经设置过了

现在我们可以创建数据库表了。 首先,用下面的命令验证模型的有效性:

  1. #python manage.py validate#尝试运行,发现在django2.x中已失效
  1. python manage.py check#正确的命令

如果一切正常,你会看到System check identified no issues (0 silenced)消息。如果出错,请检查你输入的模型代码。 错误输出会给出非常有用的错误信息来帮助你修正你的模型。

接着尝试运行以下命令查询数据库创建命令:

  1. python manage.py sqlall myapp#报错

发现报错了,这个命令也被淘汰了。

现在虽然创建了模型,但是数据库还没有同步创建完成,我们需要用以下命令同步数据库和模型:

  1. python manage.py makemigrations myapp    #用来检测数据库变更和生成数据库迁移文件
  2.  
  3. python manage.py migrate     #用来迁移数据库
  4.  
  5. python manage.py sqlmigrate myapp 0001 # 用来把数据库迁移文件转换成数据库语言

在命令行依次执行完这三个命令你就可以进行数据访问了。

从图可以看出生成了四张表,myapp_author、myapp_book和myapp_publisher这三个表都是我们创建的,但是多出了一个myapp_book_authors表

myapp_book_authors表是我们用在模型下authors = models.ManyToManyField(Author)语句生成的

  1. class Book(models.Model):
      authors = models.ManyToManyField(Author)

myapp_book_authors表:

它是models中使用ManyToManyField进行多表关联产生的,里面有两个外键,这让两个实例关联起来才能顺利保存关联关系

基本数据访问

进入django交互式操作

我们先进行出版社的信息的添加

  1. from myapp.models import Publisher
  1. p1 = Publisher(name='Apress', address='2855 Telegraph Avenue',city='Berkeley', state_province='CA', country='U.S.A.',website='http://www.apress.com/')
  1. p1.save()

刷新一下数据库发现值已经成功添加进数据库了

这也可以在交互式操作中体现出来

  1. >>>from myapp.models import Publisher
  1. >>> publisher_list = Publisher.objects.all()
  2. >>> publisher_list
    <QuerySet [<Publisher: Publisher object (1)>]>

Publisher.objects.all()方法是获取数据库中 “Publisher” 类的所有对象。这个操作的幕后,Django执行了一条SQL “SELECT” 语句。

如果需要一步完成对象的创建与存储至数据库,就使用“objects.create()”方法。 下面的例子与之前的例子等价:

  1. p1 = Publisher.objects.create(name='Apress', address='2855 Telegraph Avenue',city='Berkeley', state_province='CA', country='U.S.A.',website='http://www.apress.com/')

插入数据后,Publisher.objects.all()方法会取出Publisher类的对象,但是却没有得到有用信息

我们可以通过在我们的Publisher类中添加一个名为__str __()的方法来解决这个问题

添加模型字符串表示

分别在每个类下创建__str__()方法用来自定义返回一些你需要的信息

  1. from django.db import models
  2.  
  3. class Publisher(models.Model):
  4. name = models.CharField(max_length=30)
  5. address = models.CharField(max_length=50)
  6. city = models.CharField(max_length=60)
  7. state_province = models.CharField(max_length=30)
  8. country = models.CharField(max_length=50)
  9. website = models.URLField()
  10.  
  11. def __str__(self):
  12. return self.name
  13.  
  14. class Author(models.Model):
  15. first_name = models.CharField(max_length=30)
  16. last_name = models.CharField(max_length=40)
  17. email = models.EmailField()
  18.  
  19. def __str__(self):
  20. return u'%s %s' % (self.first_name, self.last_name)
  21.  
  22. class Book(models.Model):
  23. title = models.CharField(max_length=100)
  24. authors = models.ManyToManyField(Author)
  25. publisher = models.ForeignKey(Publisher,models.CASCADE)
  26. publication_date = models.DateField()
  27.  
  28. def __str__(self):
  29. return self.title
一个__str __()方法可以做任何它需要做的事情来返回一个对象的表示,它是以字典的形式返回的。 这里,Publisher和Book的__str __()方法分别简单地返回对象的名称和标题,但是作者的__str __()稍微复杂一点 - 它将first_name和last_name字段拼在一起,用空格分隔。 __str __()的唯一要求是它返回一个字符串对象。 如果__str __()没有返回一个字符串对象 - 如果说它返回一个整数 - 那么Python会引发一个类型错误
  1. TypeError: __str__ returned non-string (type int).

插入和更新数据

你已经知道怎么做了: 先使用一些关键参数创建对象实例,如下:

  1. from myapp.models import Publisher
  1. p = Publisher(name='Apress', address='2855 Telegraph Avenue',city='Berkeley', state_province='CA', country='U.S.A.',website='http://www.apress.com/')

这个对象实例并 没有 对数据库做修改。
在调用 save() 方法之前,记录并没有保存至数据库,像这样: >>> p.save() 在SQL里,这大致可以转换成这样:

  1. INSERT INTO books_publisher (name, address, city, state_province, country, website) VALUES ('Apress', '2855 Telegraph Ave.', 'Berkeley', 'CA', 'U.S.A.', 'http://www.apress.com/');

因为 Publisher 模型有一个自动增加的主键 id ,所以第一次调用 save() 还多做了一件事:

计算这个主键的值并把它赋值给这个对象实例:

  1. >>> p.id 52 # this will differ based on your own data

接下来再调用 save() 将不会创建新的记录,而只是修改记录内容(也就是 执行 UPDATE SQL语句,而不是 INSERT 语句):

  1. >>> p.name = 'Apress Publishing'
    >>> p.save() 前面执行的 save() 相当于下面的SQL语句:
  2. UPDATE books_publisher SET name = 'Apress Publishing', address = '2855 Telegraph Ave.', city = 'Berkeley', state_province = 'CA', country = 'U.S.A.', website = 'http://www.apress.com' WHERE id = 52;

数据过滤

使用 filter() 方法对数据进行过滤:

  1. >>> Publisher.objects.filter(name='Apress')
  2. [<Publisher: Apress>]

filter() 根据关键字参数来转换成 WHERE SQL语句。 前面这个例子 相当于这样:

  1. SELECT id, name, address, city, state_province, country, website
  2. FROM books_publisher
  3. WHERE name = 'Apress';

你可以传递多个参数到 filter() 来缩小选取范围:

  1. >>> Publisher.objects.filter(country="U.S.A.", state_province="CA")
  2. [<Publisher: Apress>]

多个参数会被转换成 AND SQL从句, 因此上面的代码可以转化成这样:

  1. SELECT id, name, address, city, state_province, country, website
  2. FROM books_publisher
  3. WHERE country = 'U.S.A.'
  4. AND state_province = 'CA';

模糊匹配

  1. >>> Publisher.objects.filter(name__contains="press")
  2. [<Publisher: Apress>]

在 name 和 contains 之间有双下划线。和Python一样,Django也使用双下划线来表明会进行一些魔术般的操作。这里,contains部分会被Django翻译成LIKE语句:

  1. SELECT id, name, address, city, state_province, country, website
  2. FROM books_publisher
  3. WHERE name LIKE '%press%';

获取单个对象

上面的例子中 filter() 函数返回一个记录集,这个记录集是一个列表。 相对列表来说,有些时候我们更需要获取单个的对象,  get()  方法就是在此时使用的:

  1. >>> Publisher.objects.get(name="Apress")
  2. <Publisher: Apress>

这样,就返回了单个对象,而不是列表(更准确的说,QuerySet)。 所以,如果结果是多个对象,会导致抛出异常:

  1. >>> Publisher.objects.get(country="U.S.A.")
  2. Traceback (most recent call last):
  3. ...
  4. MultipleObjectsReturned: get() returned more than one Publisher --
  5. it returned 2! Lookup parameters were {'country': 'U.S.A.'}

如果查询没有返回结果也会抛出异常:

  1. Traceback (most recent call last):
  1. ...
  1. myapp.models.Publisher.DoesNotExist: Publisher matching query does not exist.

这个 DoesNotExist 异常 是 Publisher 这个 model 类的一个属性,即 Publisher.DoesNotExist。在你的应用中,你可以捕获并处理这个异常,像这样:

  1. try:
  2. p = Publisher.objects.get(name='Apress')
  3. except Publisher.DoesNotExist:
  4. print "Apress isn't in the database yet."
  5. else:
  6. print "Apress is in the database."

数据排序

在运行前面的例子中,你可能已经注意到返回的结果是无序的。 我们还没有告诉数据库 怎样对结果进行排序,所以我们返回的结果是无序的。

在你的 Django 应用中,你或许希望根据某字段的值对检索结果排序,比如说,按字母顺序。 那么,使用order_by() 这个方法就可以搞定了。

  1. >>> Publisher.objects.order_by("name")
  2. [<Publisher: Apress>, <Publisher: O'Reilly>]

跟以前的 all() 例子差不多,SQL语句里多了指定排序的部分:

  1. SELECT id, name, address, city, state_province, country, website
  2. FROM books_publisher
  3. ORDER BY name;

如果需要以多个字段为标准进行排序(第二个字段会在第一个字段的值相同的情况下被使用到),使用多个参数就可以了,如下:

  1. >>> Publisher.objects.order_by("state_province", "address")
  2. [<Publisher: Apress>, <Publisher: O'Reilly>]

我们还可以指定逆向排序,在前面加一个减号 - 前缀:

  1. >>> Publisher.objects.order_by("-name")
  2. [<Publisher: O'Reilly>, <Publisher: Apress>]

连锁查询

我们已经知道如何对数据进行过滤和排序。 当然,通常我们需要同时进行过滤和排序查询的操作。 因此,你可以简单地写成这种“链式”的形式:

  1. >>> Publisher.objects.filter(country="U.S.A.").order_by("-name")
  2. [<Publisher: O'Reilly>, <Publisher: Apress>]

你应该没猜错,转换成SQL查询就是 WHERE 和 ORDER BY 的组合:

  1. SELECT id, name, address, city, state_province, country, website
  2. FROM books_publisher
  3. WHERE country = 'U.S.A'
  4. ORDER BY name DESC;

限制返回的数据

另一个常用的需求就是取出固定数目的记录。 想象一下你有成千上万的出版商在你的数据库里, 但是你只想显示第一个。 你可以使用标准的Python列表裁剪语句:

  1. >>> Publisher.objects.order_by('name')[0]
  2. <Publisher: Apress>

类似的,你可以用Python的range-slicing语法来取出数据的特定子集:

  1. >>> Publisher.objects.order_by('name')[0:2]

注意,不支持Python的负索引(negative slicing)

更新多个对象

调用结果集(QuerySet)对象的update()方法: 示例如下:

  1. >>> Publisher.objects.filter(id=52).update(name='Apress Publishing')

update()方法对于任何结果集(QuerySet)均有效,这意味着你可以同时更新多条记录。 以下示例演示如何将所有Publisher的country字段值由’U.S.A’更改为’USA’:

  1. >>> Publisher.objects.all().update(country='USA')
  2. 2

update()方法会返回一个整型数值,表示受影响的记录条数。 在上面的例子中,这个值是2。

删除对象

删除数据库中的对象只需调用该对象的delete()方法即可:

  1. >>> p = Publisher.objects.get(name="O'Reilly")
  2. >>> p.delete()
  3. >>> Publisher.objects.all()
  4. [<Publisher: Apress Publishing>]

同样我们可以在结果集上调用delete()方法同时删除多条记录。这一点与我们上一小节提到的update()方法相似:

  1. >>> Publisher.objects.filter(country='USA').delete()
  2. >>> Publisher.objects.all().delete()
  3. >>> Publisher.objects.all()
  4. []

一旦使用all()方法,所有数据将会被删除

本文参考:

https://blog.csdn.net/yy_menghuanjie/article/details/51332075

http://docs.30c.org/djangobook2/chapter05/

https://www.jianshu.com/p/44dfdd6caa7b

Django学习day7——简单的使用数据库和模型的更多相关文章

  1. Django 学习笔记(七)数据库基本操作(增查改删)

    一.前期准备工作,创建数据库以及数据表,详情点击<Django 学习笔记(六)MySQL配置> 1.创建一个项目 2.创建一个应用 3.更改settings.py 4.更改models.p ...

  2. 一、Django学习之连接与建立数据库

    连接MySQL数据库 配置文件 找到DATABASES对应的设置,修改为MySQL的配置即可 DATABASES = { 'default': { 'ENGINE': 'django.db.backe ...

  3. 2 第一个Django应用 第1部分(数据库与模型)

    目标应用: 一个公开的网站,可以让访客查看投票的结果并让他们进行投票. 一个后台管理网站,你可以添加.修改和删除选票. 查看django版本 python -c "import django ...

  4. Django学习系列14:第一个数据库迁移

    在Django中,ORM的任务是模型化数据库. 创建数据库其实是由另一个系统负责的叫做迁移. 迁移的任务是根据你对models.py文件的改动情况,添加或删除表和列. 可以把迁移想象成数据库使用的版本 ...

  5. Django学习笔记009-django models进行数据库增删查改

    引入models的定义 from app.models import  myclass class  myclass(): aa =  models. CharField (max_length=No ...

  6. 我的django之旅(三)数据库和模型

    我的django之旅(三)模型和数据库 标签(空格分隔):模型 数据库 ORM 1.django ORM django内置了一套完整的解决方案,其中就包括他自己的ORM.可惜没有使用SQLAlchem ...

  7. Django 学习笔记(六)MySQL配置

    环境:Ubuntu16.4 工具:Python3.5 一.安装MySQL数据库 终端命令: sudo apt-get install mysql-server sudo apt-get install ...

  8. Django (学习第一部 基础操作)

    django 1 django 文件相关信息 2 Python创建django 3 命令行创建django 4 Django 必会三板斧 5 静态文件配置 6 request对象方法 7 pychar ...

  9. Django学习(4)表单,让数据库更美好

    表单,在HTML中的标签为<form></form>,在网页中主要负责数据采集功能.我们在浏览网站时,常常会碰到注册账号.账号登录等,这就是表单的典型应用. 在Django学习 ...

随机推荐

  1. Docker4-docker私库的搭建及常用方法-docker-registry方式

    一.简单介绍 前面已经介绍,可以使用Docker Hub公共仓库,但是大多数情况企业都需要创建一个本地仓库供自己使用.这里介绍几种搭建私库的方法 私库的好处有几点 1.节约带宽 2.可以自己定制系统 ...

  2. ShutdownHook- Java 优雅停机解决方案

    想象一下,如果你现在刚好在 word 上写需求文档,电脑突然重启.等待开机完成,你可能会发现写了一个小时文档没有保存,就这么没了... 一个正在运行 Java 应用如果突然将其停止,影响不止数据丢失, ...

  3. 高清屏下canvas重置尺寸引发的问题

    我们知道,清空canvas画布内容有以下两个方法. 第一种方法是cearRect函数: context.cearRect(0,0,canvas.width,canvas.height) 第二种方法就是 ...

  4. 队列 & 栈---概述

    队列 是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表.进行插入操作的端称为队尾,进行删除操作 ...

  5. Linux简单检查服务运行脚本

    脚本内容如下: 此脚本含义:检查服务是否运行,在运行则记录日志,不在运行则记录日志并将服务启动 #!/bin/bash svrnm="tomcat" //设置服务名称time=`d ...

  6. servlet中的forward()和redirect()

    从地址栏显示来说 forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器 浏览器根本不知道服务器发送的内容从哪里来的,所以它的地址栏 ...

  7. 低效sql语句执行缓慢引起的大量占用服务器的CPU问题处理 (优化心得)

    1> 2> 3> 4> 5>删除不良的执行计划后执行时间仍然有150s,这实在是太慢了,继续查看原sql代码,发现父表的关联条件放在了子查询里,这是应该避免的 调整原sq ...

  8. 最强最全的Java后端知识体系

    目录 最全的Java后端知识体系 Java基础 算法和数据结构 Spring相关 数据库相关 方法论 工具清单 文档 @(最强最全的Java后端知识体系) 最全的Java后端知识体系 最全的Java后 ...

  9. 章节十七章、2- 给执行失败的case截图

    一.案例演示 1.首先我们把截图的方法单独进行封装方便以后调用. package utilities; import java.io.File; import java.io.IOException; ...

  10. python-犯傻合集

    1.题目: 基于文件实现用户登录程序,提示用户输入用户名和密码,检查用户名是否存在,以及用户名密码是否正确 保存密码的文件叫user.txt,内容:   |  作分隔符 阶段一: 自己第一次的答案: ...