码迷,mamicode.com
首页 > 其他好文 > 详细

Django模型

时间:2019-07-05 12:51:45      阅读:101      评论:0      收藏:0      [点我收藏+]

标签:技术   dac   tab   rap   命令   list   where   website   lin   

  在当代 Web 应用中,主观逻辑经常牵涉到与数据库的交互。 数据库驱动网站 在后台连接数据库服务器,从中取出一些数据,然后在 Web 页面用漂亮的格式展示这些数据。 这个网站也可能会向访问者提供修改数据库数据的方法。由于先天具备 Python 简单而强大的数据库查询执行方法,Django 非常适合开发数据库驱动网站。 本章深入介绍了该功能: Django 数据库层。

  示例版本:python 3.6 + django 2.2.2 。

1. 数据库配置

  在settings.py中配置数据库信息,这里mysql配置信息参数如下:

技术图片
DATABASES = {
    default: {
        ENGINE: django.db.backends.mysql,
        NAME: spiderdb,
        USER: spider,
        PASSWORD: 123456,
        HOST: 127.0.0.1,
        PORT: 3306,
    }
}
View Code

2. 第一个应用程序

  创建一个 Django app-一个包含模型,视图和Django代码,并且形式为独立Python包的完整Django应用。创建之前先解释下 django中的project和app的区别。

  一个project包含很多个Django app以及对它们的配置。技术上,project的作用是提供配置文件,比方说哪里定义数据库连接信息, 安装的app列表, TEMPLATE_DIRS ,等等。一个app是一套Django功能的集合,通常包括模型和视图,按Python的包结构的方式存在。

技术图片
# 执行命令
python manage.py startapp books

# 创建的app目录结构
books/
    __init__.py
    models.py
    tests.py
    views.py
View Code

3. 定义一个模型

技术图片
from django.db import models

class Publisher(models.Model):
    name = models.CharField(max_length=30)
    address = models.CharField(max_length=50)
    city = models.CharField(max_length=60)
    state_province = models.CharField(max_length=30)
    country = models.CharField(max_length=50)
    website = models.URLField()

class Author(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=40)
    email = models.EmailField()

class Book(models.Model):
    title = models.CharField(max_length=100)
    authors = models.ManyToManyField(Author)
    publisher = models.ForeignKey(Publisher)
    publication_date = models.DateField()
View Code

  “每个数据库表对应一个类”这条规则的例外情况是多对多关系。 在我们的范例模型中, Book 有一个 多对多字段叫做 authors 。 该字段表明一本书籍有一个或多个作者,但 Book 数据库表却并没有 authors 字段。 相反,Django创建了一个额外的表(多对多连接表)来处理书籍和作者之间的映射关系。

  最后需要注意的是,我们并没有显式地为这些模型定义任何主键。 除非你单独指明,否则Django会自动为每个模型生成一个自增长的整数主键字段每个Django模型都要求有单独的主键。id

4. 模型安装

  完成这些代码之后,现在让我们来在数据库中创建这些表。 要完成该项工作,第一步是在 Django 项目中 激活这些模型。 将 books app 添加到配置文件的已安装应用列表中即可完成此步骤。再次编辑 settings.py 文件, 找到 INSTALLED_APPS 设置。 INSTALLED_APPS 告诉 Django 项目哪些 app 处于激活状态。 

技术图片
INSTALLED_APPS = [
    django.contrib.admin,
    django.contrib.auth,
    django.contrib.contenttypes,
    django.contrib.sessions,
    django.contrib.messages,
    django.contrib.staticfiles,
    spider,
    books,
]
View Code

  执行命令,生成表到数据库。

技术图片
python manage.py makemigrations
python manage.py migrate
View Code

5. 基本数据访问

   一旦你创建了模型,Django自动为这些模型提供了高级的Python API。 运行 python manage.py shell 并输入下面的内容试试看:

技术图片
>>> from books.models import Publisher
>>> p1 = Publisher(name=Apress, address=2855 Telegraph Avenue,
...     city=Berkeley, state_province=CA, country=U.S.A.,
...     website=http://www.apress.com/)
>>> p1.save()
>>> p2 = Publisher(name="O‘Reilly", address=10 Fawcett St.,
...     city=Cambridge, state_province=MA, country=U.S.A.,
...     website=http://www.oreilly.com/)
>>> p2.save()
>>> publisher_list = Publisher.objects.all()
>>> publisher_list
[<Publisher: Publisher object>, <Publisher: Publisher object>]
View Code
  • 首先,导入Publisher模型类, 通过这个类我们可以与包含 出版社 的数据表进行交互。

  • 接着,创建一个`` Publisher`` 类的实例并设置了字段`` name, address`` 等的值。

     
  • 调用该对象的 save() 方法,将对象保存到数据库中。 Django 会在后台执行一条 INSERT 语句。

  • 最后,使用`` Publisher.objects`` 属性从数据库取出出版商的信息,这个属性可以认为是包含出版商的记录集。 这个属性有许多方法, 这里先介绍调用`` Publisher.objects.all()`` 方法获取数据库中`` Publisher`` 类的所有对象。这个操作的幕后,Django执行了一条SQL `` SELECT`` 语句。

 6. 添加模块字符串表现

  当我们打印整个publisher列表时,我们没有得到想要的有用信息,无法将对象信息分开。可以添加一个方法 __str__() 来实现。

技术图片
from django.db import models

# Create your models here.


class Publisher(models.Model):
    name = models.CharField(max_length=30)
    address = models.CharField(max_length=50)
    city = models.CharField(max_length=60)
    state_province = models.CharField(max_length=30)
    country = models.CharField(max_length=50)
    website = models.URLField()

    def __str__(self):
        return self.name

class Author(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=40)
    email = models.EmailField(blank=True, verbose_name=e-mail)

    def __str__(self):
        return u%s, %s % (self.first_name, self.last_name)


class Book(models.Model):
    title = models.CharField(max_length=100)
    authors = models.ManyToManyField(Author)
    publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)
    publication_date = models.DateField()

    def __str__(self):
        return self.title
View Code

7. 插入和更新数据

技术图片
>>> p = Publisher(name=Apress,
...         address=2855 Telegraph Ave.,
...         city=Berkeley,
...         state_province=CA,
...         country=U.S.A.,
...         website=http://www.apress.com/)
View Code

8. 选择对象

  当然,创建新的数据库,并更新之中的数据是必要的,但是,对于 Web 应用程序来说,更多的时候是在检索查询数据库。 我们已经知道如何从一个给定的模型中取出所有记录:

技术图片
>>> Publisher.objects.all()
[<Publisher: Apress>, <Publisher: OReilly>]
View Code

  注意到 Django在选择所有数据时并没有使用 SELECT* ,而是显式列出了所有字段。 设计的时候就是这样: SELECT* 会更慢,而且最重要的是列出所有字段遵循了Python 界的一个信条: 明言胜于暗示。(提示: 在python命令行输入 import this 看看!)

9. 数据过滤

  我们很少会一次性从数据库中取出所有的数据;通常都只针对一部分数据进行操作。 在Django API中,我们可以使用`` filter()`` 方法对数据进行过滤:

技术图片
# 单条件过滤
>>> Publisher.objects.filter(name=Apress)
[<Publisher: Apress>]

# 多条件过滤
>>> Publisher.objects.filter(country="U.S.A.", state_province="CA")
[<Publisher: Apress>]

# SQL缺省的 = 操作符是精确匹配的, 其他类型的查找也可以使用:
>>> Publisher.objects.filter(name__contains="press")
[<Publisher: Apress>]

# 在 name 和 contains 之间有双下划线。和Python一样,Django也使用双下划线来表明会进行一些魔术般的操作。这里,contains部分会被Django翻译成LIKE语句:
SELECT id, name, address, city, state_province, country, website
FROM books_publisher
WHERE name LIKE %press%;
View Code

10 . 获取单个对象

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

技术图片
>>> Publisher.objects.get(name="Apress")
<Publisher: Apress>

# 这样,就返回了单个对象,而不是列表(更准确的说,QuerySet)。 所以,如果结果是多个对象,会导致抛出异常:
>>> Publisher.objects.get(country="U.S.A.")
Traceback (most recent call last):
    ...
MultipleObjectsReturned: get() returned more than one Publisher --
    it returned 2! Lookup parameters were {country: U.S.A.}

# 如果查询没有返回结果也会抛出异常:
>>> Publisher.objects.get(name="Penguin")
Traceback (most recent call last):
    ...
DoesNotExist: Publisher matching query does not exist.

# 这个 DoesNotExist 异常 是 Publisher 这个 model 类的一个属性,即 Publisher.DoesNotExist。在你的应用中,你可以捕获并处理这个异常,像这样:
try:
    p = Publisher.objects.get(name=Apress)
except Publisher.DoesNotExist:
    print "Apress isn‘t in the database yet."
else:
    print "Apress is in the database."
View Code

11. 数据排序

  在运行前面的例子中,你可能已经注意到返回的结果是无序的。 我们还没有告诉数据库 怎样对结果进行排序,所以我们返回的结果是无序的。在你的 Django 应用中,你或许希望根据某字段的值对检索结果排序,比如说,按字母顺序。 那么,使用 order_by() 这个方法就可以搞定了。

技术图片
>>> Publisher.objects.order_by("name")
[<Publisher: Apress>, <Publisher: OReilly>]
View Code

  我们可以对任意字段进行排序:

技术图片
>>> Publisher.objects.order_by("address")
[<Publisher: OReilly>, <Publisher: Apress>]

>>> Publisher.objects.order_by("state_province")
[<Publisher: Apress>, <Publisher: OReilly>]
View Code

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

技术图片
>>> Publisher.objects.order_by("state_province", "address")
 [<Publisher: Apress>, <Publisher: OReilly>]
View Code

  尽管很灵活,但是每次都要用 order_by() 显得有点啰嗦。 大多数时间你通常只会对某些 字段进行排序。 在这种情况下,Django让你可以指定模型的缺省排序方式:

技术图片
class Publisher(models.Model):
    name = models.CharField(max_length=30)
    address = models.CharField(max_length=50)
    city = models.CharField(max_length=60)
    state_province = models.CharField(max_length=30)
    country = models.CharField(max_length=50)
    website = models.URLField()

    def __str__(self):
        return self.name

    class Meta:
        ordering = [name]
View Code

   class Meta,内嵌于 Publisher 这个类的定义中(如果 class Publisher是顶格的,那么 class Meta 在它之下要缩进4个空格--按 Python 的传统 )。你可以在任意一个 模型 类中使用 Meta 类,来设置一些与特定模型相关的选项。 在 附录B 中有 Meta 中所有可选项的完整参考,现在,我们关注 ordering 这个选项就够了。 如果你设置了这个选项,那么除非你检索时特意额外地使用了 order_by(),否则,当你使用 Django 的数据库 API 去检索时,Publisher对象的相关返回值默认地都会按 name 字段排序。

12 . 连锁查询

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

技术图片
>>> Publisher.objects.filter(country="U.S.A.").order_by("-name")
[<Publisher: OReilly>, <Publisher: Apress>]

# 转换成SQL查询就是 WHERE 和 ORDER BY 的组合:
SELECT id, name, address, city, state_province, country, website
FROM books_publisher
WHERE country = U.S.A
ORDER BY name DESC;
View Code

13 限制返回数据

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

技术图片
>>> Publisher.objects.order_by(name)[0]
<Publisher: Apress>

# 这相当于:
SELECT id, name, address, city, state_province, country, website
FROM books_publisher
ORDER BY name
LIMIT 1;

# 类似的,你可以用Python的range-slicing语法来取出数据的特定子集:
>>> Publisher.objects.order_by(name)[0:2]

# 这个例子返回两个对象,等同于以下的SQL语句:
SELECT id, name, address, city, state_province, country, website
FROM books_publisher
ORDER BY name
OFFSET 0 LIMIT 2;
View Code

14 . 更新多个对象

  在“插入和更新数据”小节中,我们有提到模型的save()方法,这个方法会更新一行里的所有列。 而某些情况下,我们只需要更新行里的某几列。

技术图片
# 例如说我们现在想要将Apress Publisher的名称由原来的”Apress”更改为”Apress Publishing”。若使用save()方法,如:
>>> p = Publisher.objects.get(name=Apress)
>>> p.name = Apress Publishing
>>> p.save()

# 在这个例子里我们可以看到Django的save()方法更新了不仅仅是name列的值,还有更新了所有的列。 若name以外的列有可能会被其他的进程所改动的情况下,只更改name列显然是更加明智的。 更改某一指定的列,我们可以调用结果集(QuerySet)对象的update()方法: 示例如下:
>>> Publisher.objects.filter(id=52).update(name=Apress Publishing)

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

15 . 删除对象

技术图片
# 删除数据库中的对象只需调用该对象的delete()方法即可:
>>> p = Publisher.objects.get(name="O‘Reilly")
>>> p.delete()
>>> Publisher.objects.all()
[<Publisher: Apress Publishing>]

# 同样我们可以在结果集上调用delete()方法同时删除多条记录。这一点与我们上一小节提到的update()方法相似:
>>> Publisher.objects.filter(country=USA).delete()
>>> Publisher.objects.all().delete()
>>> Publisher.objects.all()
[]

# 删除数据时要谨慎! 为了预防误删除掉某一个表内的所有数据,Django要求在删除表内所有数据时显示使用all()。 比如,下面的操作将会出错:
>>> Publisher.objects.delete()
Traceback (most recent call last):
  File "<console>", line 1, in <module>
AttributeError: Manager object has no attribute delete

# 而一旦使用all()方法,所有数据将会被删除:
>>> Publisher.objects.all().delete()

# 如果只需要删除部分的数据,就不需要调用all()方法。再看一下之前的例子:
>>> Publisher.objects.filter(country=USA).delete()
View Code

Django模型

标签:技术   dac   tab   rap   命令   list   where   website   lin   

原文地址:https://www.cnblogs.com/blackysy/p/11137179.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!