【Django】模型和数据库

模型和数据库

  • Models and databases
    • 模型
      • 快速示例
      • 字段
      • 字段类型
      • 字段选项
    • 关系
      • 多对一关系
      • 多对多关系
      • 跨文件模型
      • 模型属性
      • 模型方法
      • 超类方法
    • 执行自定义 SQL
      • 模型继承
      • 代理模型
    • 在包中组织模型

Models and databases

模型是有关您的数据的唯一、明确的数据源。它包含您存储的数据的基本字段和行为。通常,每个模型都映射到单个数据库表

模型

基础知识:
每个模型都是一个子类化的 Python 类 django.db.models.Model
模型的每个属性代表一个数据库字段
有了所有这些,Django 为您提供了一个自动生成的数据库访问 API;请参阅进行查询。

快速示例

这个示例模型定义了一个Person,它有一个first_name和 last_name:

from django.db import models
class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)

first_namelast_name是模型的字段。每个字段都被指定为一个类属性每个属性都映射到一个数据库列

上面的Person模型将创建一个这样的数据库表:

CREATE TABLE myapp_person (
    "id" serial NOT NULL PRIMARY KEY,
    "first_name" varchar(30) NOT NULL,
    "last_name" varchar(30) NOT NULL
);

一些技术说明:
表的名称myapp_person自动从某些模型元数据派生而来,但可以被覆盖。有关更多详细信息,请参阅表名称。
一个id字段被自动添加,但这种行为可以被覆盖。请参阅自动主键字段。
此示例中的CREATE TABLE SQL 使用 PostgreSQL 语法进行格式化,但值得注意的是 Django 使用为您的设置文件中指定的数据库后端量身定制的 SQL 。

一旦你定义了你的模型,你需要告诉 Django 你将使用这些模型。 为此,请编辑您的设置文件并更改 INSTALLED_APPS 设置以添加包含您的 models.py 的模块的名称。
在这里插入图片描述

例如,如果应用程序的模型位于 myapp.models 模块(由 manage.py startapp 脚本为应用程序创建的包结构)中,则 INSTALLED_APPS 应部分读取:

INSTALLED_APPS = [
    #...
    'myapp',
    #...
]

当您向 INSTALLED_APPS 添加新应用程序时,请确保运行 manage.py migrate,可选择首先使用 manage.py makemigrations 为它们进行迁移。

字段

模型最重要的部分——也是模型唯一需要的部分——是它定义的数据库字段列表。字段由类属性指定。要小心,不要选择字段名称与冲突 模型API一样比如clean,save或 delete。

字段类型

模型中的每个字段都应该是相应 Field 类的实例。 Django 使用字段类类型来确定一些事情:

  • 列类型,它告诉数据库要存储的数据类型(例如 INTEGER、VARCHAR、TEXT)。
  • 渲染表单字段时使用的默认 HTML 小部件(例如 <input type="text">, <select>)。
  • 在 Django 的管理和自动生成的表单中使用的最小验证要求。

Django 附带了数十种内置字段类型; 您可以在模型字段参考中找到完整列表。 如果 Django 的内置字段不起作用,您可以轻松编写自己的字段; 请参阅编写自定义模型字段。

字段选项

每个字段采用一组特定于字段的参数(记录在 模型字段参考中)。例如, CharField(及其子类)需要一个 max_length参数来指定VARCHAR用于存储数据的数据库字段的大小。

还有一组适用于所有字段类型的通用参数。都是可选的。它们在参考资料中得到了完整的解释,但这里是最常用的快速总结:

  • null
    如果True,Django 将像NULL在数据库中一样存储空值。默认为False。

  • blank
    如果True,则允许该字段为空。默认为False。
    请注意,这与null. null纯粹与数据库相关,而 blank与验证相关。如果字段具有 blank=True,则表单验证将允许输入空值。如果字段具有blank=False,则该字段将是必需的。

  • choices
    一个序列的2元组,作为该领域的选择使用。如果给出了这个,默认的表单小部件将是一个选择框而不是标准文本字段,并将选择限制为给定的选择。

选择列表如下所示:

YEAR_IN_SCHOOL_CHOICES = [
    ('FR', 'Freshman'),
    ('SO', 'Sophomore'),
    ('JR', 'Junior'),
    ('SR', 'Senior'),
    ('GR', 'Graduate'),
]

关系

显然,关系数据库的强大之处在于将表相互关联。Django 提供了定义三种最常见的数据库关系类型的方法:多对一、多对多和一对一。

多对一关系

要定义多对一关系,请使用django.db.models.ForeignKey。您可以像使用任何其他Field类型一样使用它:通过将其作为模型的类属性包含在内。

ForeignKey 需要一个位置参数:与模型相关的类。

例如,如果一个Car模型有一个Manufacturer——也就是说,一个 Manufacturer制造了多辆汽车,但每辆车Car只有一辆 Manufacturer——使用以下定义:

from django.db import models

class Manufacturer(models.Model):
    # ...
    pass

class Car(models.Model):
    manufacturer = models.ForeignKey(Manufacturer, on_delete=models.CASCADE)
    # ...

您还可以创建递归关系(与自身具有多对一关系的对象)以及与尚未定义的模型的关系;有关详细信息,请参阅模型字段参考。

建议(但不是必需)ForeignKey字段的名称 (manufacturer在上面的示例中)是模型的名称,小写。您可以随意调用该字段。例如:

class Car(models.Model):
    company_that_makes_it = models.ForeignKey(
        Manufacturer,
        on_delete=models.CASCADE,
    )
    # ...

多对多关系

要定义多对多关系,请使用 ManyToManyField。您可以像使用任何其他Field类型一样使用它 :通过将其作为模型的类属性包含在内。
ManyToManyField 需要一个位置参数:与模型相关的类。
例如,如果 aPizza有多个Topping对象——也就是说,a Topping可以在多个比萨饼上并且每个Pizza都有多个浇头——你可以这样表示:

from django.db import models

class Topping(models.Model):
    # ...
    pass

class Pizza(models.Model):
    # ...
    toppings = models.ManyToManyField(Topping)

跨文件模型

将模型与另一个应用程序中的模型相关联是完全可以的。为此,请在定义模型的文件顶部导入相关模型。然后,在需要的地方引用其他模型类。例如:

from django.db import models
from geography.models import ZipCode

class Restaurant(models.Model):
    # ...
    zip_code = models.ForeignKey(
        ZipCode,
        on_delete=models.SET_NULL,
        blank=True,
        null=True,
    )

模型属性

objects
模型最重要的属性是 Manager. 它是向 Django 模型提供数据库查询操作的接口,用于 从数据库中检索实例。如果Manager未定义自定义,则默认名称为 objects. 管理器只能通过模型​​类访问,不能通过模型​​实例访问。

模型方法

在模型上定义自定义方法以向对象添加自定义“行级”功能。虽然Manager方法有尽而意“表范围”的东西,模型方法应该作用于特定的模型实例。

这是一种将业务逻辑保持在一个地方——模型——的有价值的技术。

例如,这个模型有一些自定义方法:

from django.db import models

class Person(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    birth_date = models.DateField()

    def baby_boomer_status(self):
        "Returns the person's baby-boomer status."
        import datetime
        if self.birth_date < datetime.date(1945, 8, 1):
            return "Pre-boomer"
        elif self.birth_date < datetime.date(1965, 1, 1):
            return "Baby boomer"
        else:
            return "Post-boomer"

    @property
    def full_name(self):
        "Returns the person's full name."
        return '%s %s' % (self.first_name, self.last_name)

本示例中的最后一个方法是属性

该模型实例参考具有的完整列表,自动给每个模型的方法。您可以覆盖其中的大部分 - 请参阅下面的覆盖预定义模型方法- 但您几乎总是想要定义一些:

__str__()
一个 Python 的“魔法方法”,它返回任何对象的字符串表示。这就是 Python 和 Django 将在模型实例需要强制转换并显示为纯字符串时使用的方法。最值得注意的是,当您在交互式控制台或管理中显示对象时会发生这种情况。

你总是想定义这个方法;默认值根本不是很有帮助。

get_absolute_url()
这告诉 Django 如何计算对象的 URL。Django 在它的管理界面中使用它,任何时候它需要找出一个对象的 URL。

任何具有唯一标识它的 URL 的对象都应该定义此方法。

超类方法

重要的是要记住调用超类方法——这就是业务——以确保对象仍然保存到数据库中。如果您忘记调用超类方法,则不会发生默认行为,也不会触及数据库。
super().save(*args, **kwargs)

执行自定义 SQL

另一种常见模式是在模型方法和模块级方法中编写自定义 SQL 语句。

模型继承

Django 中模型继承的工作方式与 Python 中普通类继承的工作方式几乎相同,但仍应遵循页面开头的基础知识。这意味着基类应该子类化 django.db.models.Model.

您必须做出的唯一决定是,您是否希望父模型本身成为模型(具有自己的数据库表),或者父模型是否只是仅通过子模型可见的公共信息的持有者。

在 Django 中有三种可能的继承风格。

  • 通常,您只想使用父类来保存您不想为每个子模型输入的信息。这个类不会被单独使用,所以抽象基类是你所追求的。
  • 如果您对现有模型(可能完全来自另一个应用程序)进行子类化,并希望每个模型都有自己的数据库表, 多表继承是可行的方法。
  • 最后,如果您只想修改模型的 Python 级行为,而不以任何方式更改模型字段,则可以使用 Proxy models。

代理模型

使用多表继承时,将为模型的每个子类创建一个新的数据库表。这通常是期望的行为,因为子类需要一个地方来存储基类中不存在的任何附加数据字段。然而,有时您只想更改模型的 Python 行为——也许是更改默认管理器,或添加新方法

这就是代理模型继承的用途:为原始模型创建代理。您可以创建、删除和更新代理模型的实例,并且所有数据都将被保存,就像您使用原始(非代理)模型一样。不同之处在于您可以更改默认模型排序或代理中的默认管理器等内容,而无需更改原始模型。

代理模型像普通模型一样声明。您可以通过将类的proxy的Meta属性设置为True 来告诉 Django 它是一个代理模型。

例如,假设您想向Person模型添加一个方法。你可以这样做:

from django.db import models 

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)

class MyPerson(Person):
    class Meta:
        proxy = True

    def do_something(self):
        # ...
        pass

MyPerson 类在与其父 Person 类相同的数据库表上运行。 特别是,任何新的 Person 实例也可以通过 MyPerson 访问,反之亦然:

>>> p = Person.objects.create(first_name="foobar")
>>> MyPerson.objects.get(first_name="foobar")
<MyPerson: foobar>

您还可以使用代理模型在模型上定义不同的默认排序。您可能并不总是希望对Person模型进行排序,而是last_name在使用代理时按属性定期排序:

class OrderedPerson(Person):
    class Meta:
        ordering = ["last_name"]
        proxy = True

现在普通Person查询将是无序的,OrderedPerson查询将按 排序last_name。

代理模型以与常规模型相同的方式继承Meta属性。

在包中组织模型

manage.py startapp 命令创建一个包含 models.py 文件的应用程序结构。 如果您有许多模型,将它们组织在单独的文件中可能会很有用

为此,请创建一个模型包。 删除 models.py 并使用 __init__.py 文件和用于存储模型的文件创建一个 myapp/models/ 目录。 您必须在 __init__.py 文件中导入模型。

例如,如果您在models目录中有organic.pysynthetic.py

myapp/models/__init__.py

from .organic import Person
from .synthetic import Robot

显式导入每个模型而不是使用 from .models import * 的优点是不会使命名空间混乱使代码更具可读性,并使代码分析工具保持有用

热门文章

暂无图片
编程学习 ·

那些年让我们目瞪口呆的bug

程序员一生与bug奋战&#xff0c;可谓是杀敌无数&#xff0c;见怪不怪了&#xff01;在某知识社交平台中&#xff0c;一个“有哪些让程序员目瞪口呆的bug”的话题引来了6700多万的阅读&#xff0c;可见程序员们对一个话题的敏感度有多高。 1、麻省理工“只能发500英里的邮件” …
暂无图片
编程学习 ·

redis的下载与安装

下载redis wget http://download.redis.io/releases/redis-5.0.0.tar.gz解压redis tar -zxvf redis-5.0.0.tar.gz编译 make安装 make install快链方便进入redis ln -s redis-5.0.0 redis
暂无图片
编程学习 ·

《大话数据结构》第三章学习笔记--线性表(一)

线性表的定义 线性表&#xff1a;零个或多个数据元素的有限序列。 线性表元素的个数n定义为线性表的长度。n为0时&#xff0c;为空表。 在比较复杂的线性表中&#xff0c;一个数据元素可以由若干个数据项组成。 线性表的存储结构 顺序存储结构 可以用C语言中的一维数组来…
暂无图片
编程学习 ·

对象的扩展

文章目录对象的扩展属性的简洁表示法属性名表达式方法的name属性属性的可枚举性和遍历可枚举性属性的遍历super关键字对象的扩展运算符解构赋值扩展运算符AggregateError错误对象对象的扩展 属性的简洁表示法 const foo bar; const baz {foo}; baz // {foo: "bar"…
暂无图片
编程学习 ·

让程序员最头疼的5种编程语言

世界上的编程语言&#xff0c;按照其应用领域&#xff0c;可以粗略地分成三类。 有的语言是多面手&#xff0c;在很多不同的领域都能派上用场。大家学过的编程语言很多都属于这一类&#xff0c;比如说 C&#xff0c;Java&#xff0c; Python。 有的语言专注于某一特定的领域&…
暂无图片
编程学习 ·

写论文注意事项

参考链接 给研究生修改了一篇论文后&#xff0c;该985博导几近崩溃…… 重点分析 摘要与结论几乎重合 这一条是我见过研究生论文中最常出现的事情&#xff0c;很多情况下&#xff0c;他们论文中摘要部分与结论部分重复率超过70%。对于摘要而言&#xff0c;首先要用一小句话引…
暂无图片
编程学习 ·

安卓 串口开发

上图&#xff1a; 上码&#xff1a; 在APP grable添加 // 串口 需要配合在项目build.gradle中的repositories添加 maven {url "https://jitpack.io" }implementation com.github.licheedev.Android-SerialPort-API:serialport:1.0.1implementation com.jakewhart…
暂无图片
编程学习 ·

2021-2027年中国铪市场调研与发展趋势分析报告

2021-2027年中国铪市场调研与发展趋势分析报告 本报告研究中国市场铪的生产、消费及进出口情况&#xff0c;重点关注在中国市场扮演重要角色的全球及本土铪生产商&#xff0c;呈现这些厂商在中国市场的铪销量、收入、价格、毛利率、市场份额等关键指标。此外&#xff0c;针对…
暂无图片
编程学习 ·

Aggressive cows题目翻译

描述&#xff1a; Farmer John has built a new long barn, with N (2 < N < 100,000) stalls.&#xff08;John农民已经新建了一个长畜棚带有N&#xff08;2<N<100000&#xff09;个牛棚&#xff09; The stalls are located along a straight line at positions…
暂无图片
编程学习 ·

剖析组建PMO的6个大坑︱PMO深度实践

随着事业环境因素的不断纷繁演进&#xff0c;项目时代正在悄悄来临。设立项目经理转岗、要求PMP等项目管理证书已是基操&#xff0c;越来越多的组织开始组建PMO团队&#xff0c;大有曾经公司纷纷建造中台的气质&#xff08;当然两者的本质并不相同&#xff0c;只是说明这个趋势…
暂无图片
编程学习 ·

Flowable入门系列文章118 - 进程实例 07

1、获取流程实例的变量 GET运行时/进程实例/ {processInstanceId} /变量/ {变量名} 表1.获取流程实例的变量 - URL参数 参数需要值描述processInstanceId是串将流程实例的id添加到变量中。变量名是串要获取的变量的名称。 表2.获取流程实例的变量 - 响应代码 响应码描述200指…
暂无图片
编程学习 ·

微信每天自动给女[男]朋友发早安和土味情话

微信通知&#xff0c;每天给女朋友发早安、情话、诗句、天气信息等~ 前言 之前逛GitHub的时候发现了一个自动签到的小工具&#xff0c;b站、掘金等都可以&#xff0c;我看了下源码发现也是很简洁&#xff0c;也尝试用了一下&#xff0c;配置也都很简单&#xff0c;主要是他有一…
暂无图片
编程学习 ·

C语言二分查找详解

二分查找是一种知名度很高的查找算法&#xff0c;在对有序数列进行查找时效率远高于传统的顺序查找。 下面这张动图对比了二者的效率差距。 二分查找的基本思想就是通过把目标数和当前数列的中间数进行比较&#xff0c;从而确定目标数是在中间数的左边还是右边&#xff0c;将查…
暂无图片
编程学习 ·

项目经理,你有什么优势吗?

大侠被一个问题问住了&#xff1a;你和别人比&#xff0c;你的优势是什么呢? 大侠听到这个问题后&#xff0c;脱口而出道&#xff1a;“项目管理能力和经验啊。” 听者抬头看了一下大侠&#xff0c;显然听者对大侠的这个回答不是很满意&#xff0c;但也没有继续追问。 大侠回家…
暂无图片
编程学习 ·

nginx的负载均衡和故障转移

#注&#xff1a;proxy_temp_path和proxy_cache_path指定的路径必须在同一分区 proxy_temp_path /data0/proxy_temp_dir; #设置Web缓存区名称为cache_one&#xff0c;内存缓存空间大小为200MB&#xff0c;1天没有被访问的内容自动清除&#xff0c;硬盘缓存空间大小为30GB。 pro…
暂无图片
编程学习 ·

业务逻辑漏洞

身份认证安全 绕过身份认证的几种方法 暴力破解 测试方法∶在没有验证码限制或者一次验证码可以多次使用的地方&#xff0c;可以分为以下几种情况︰ (1)爆破用户名。当输入的用户名不存在时&#xff0c;会显示请输入正确用户名&#xff0c;或者用户名不存在 (2)已知用户名。…