00x: Django models.Model详解

本文深入讲解Django框架中Model的概念,包括字段定义、数据库关系、元数据设置等关键知识点。

Models
model是对于信息的一种模型封装与定义。它包含了你要存储的必要字段和操作数据的方法。一句话概括就是,每个模型映射了一张数据表。
基本概念:

每个model都是继承于django.db.models.Model 的Python类。

model的每一个属性对应数据表中的一个字段。

通过所有的这些,Django提供了一个自动化生成访问数据库的API。

简单实例
这个例子定义了Person ,并给它赋予了first_name 和last_name:
在这里插入图片描述
其中first_name 和last_name 是model的字段。如你所见,每一个字段被定义为class类的一个属性,而每个属性对应着数据库的一列。

上面的创建Person ,model模型的过程用SQL语句翻译过来如下:
在这里插入图片描述
下面是一些需要注意的问题:

数据表的名字,myapp_person,自动继承一些model的metadata设定,但是同时支持自定义。

id字段是自动添加的,但是它同样可以自定义。

CREATE TABLE这个SQL语句在这个例子中由PostgreSQL来实现,

使用models
一旦你定义好了你的模型,你需要告诉Django你将要使用这些models。这就需要秀修改工程目录下的settings.py文件。假设你的model定义在了app名为myapp的models.py 文件中,为了使得Django识别出你要使用这个model,你就需要在settings.py中设定如下:
在这里插入图片描述
当你添加新的APP到INSTALLED_APPS中时。需要运行命令python manage.py migrate使设置生效。可供选择的是为了使用git等代码管理软件,你可以先运行python manage.py makemigrations。

字段
model最重要的部分而且也是model所需的基础部分是它定义的数据库字段的集合。字段由类的属性来定义。需要注意一点,不要使用和models API冲突的名字来命名字段例如clean,save或者delete。

例子:

在这里插入图片描述
字段类型
你模型中的每一个字段应该是一个Field类的实例。Django使用字段类来决定一些事:

列的类型,就是告诉数据库要存储的数据类型是什么。

默认的HTML插件 ,用以渲染表单字段(例如,)

基本的验证需求,在Django的admin中和自动生成的表单中使用。

Django自带了很多内建的字段类型。若Django没有你想要的类型,你可以自己实现。

字段选项
每一个字段使用一个确定的字段声明参数集合。例如,CharField(还有它的子类)需要一个max_length参数来声明数据库用于存储字段VARVHAR的个数。

同样的,还有其他的一些选项可用来设置字段,它们都是可选的。下面介绍几个比较常用的设置选项:

null:
若为True,Django会把空数据使用NULL存储在数据库中。默认是False。
blank:
若为True,该字段允许为空。默认是False。
注意它和null的不同。null是纯粹和数据库相关的,而’blank’则是和验证相关的。若一个字段的blank=True,表单的验证将会允许实例带一个空值。反之则不行。
choices:
一个可迭代的元祖,用来作为字段内容的选择。若这个给定,默认的表单插件将会变成一个单选框而不是简单的文本字段,并且单选框中的选项数目由给定的choices来限定。
一个标准的choices列表和下面的形式类似:
在这里插入图片描述
每个元组中的第一个元素是要存储在数据库中的内容。第二个元素用于在显示的控件上展示。

给定一个model的实例,用于显示的choices的值可以通过使用get_FOO_display()方法来获取,例如:
在这里插入图片描述
在这里插入图片描述

default:
这个选项用于设置该字段的默认值。可以是一个值或者可以是一个可以调用的对象。若是可调用的对象,它会在每次新对象创建的时候调用。
help_text:
额外的帮助文本用于显示在widget上。它对文档的生成很有用。
primary_key:
若为True,该字段会作为这个model的主键。如果你没有为其他字段声明primary_key=True,Django会自动地添加一个IntegerField字段作为主键。所以如果没有特殊需求,这个选项可以不做设置。
主键的字段是只读的。如果你改变了现有对象的主键的值然后保存了这个对象,一个新的对象就会和旧的对象并行创建。啥意思呢?如下面的例子所示:
在这里插入图片描述
在这里插入图片描述
unique:
若为True,该字段必须是整张表中独一无二的

自动主键字段
默认情况下,Django给每个模型以下字段:
在这里插入图片描述
这是一个自动添加的自增主键。
如果你想声明一个典型的主键,只需要在对应的字段选项中设置primary_key=True。若Django看到你显式声明了自定义的主键,那么Django就不会为你创建一个自增的id字段。
每个模型需要明确一个字段作为主键。

verbose字段
除了ForeignKey,ManyToManyField和OneToOneField,每个字段都有一个可选的设置参数:详细。若这个选项未给定,Django会使用属性名来定义,用下划线分隔。
下面的例子中,verbose的名称是”person’s first name”
在这里插入图片描述

下面的例子中,verbose的值为”first name”:在这里插入图片描述
ForeignKey,ManyToManyField和OneToOneField需要第一个参数为model类对象,所以如果要使用verbose_name,需要显式地声明:

在这里插入图片描述
一个惯例就是verbose_name的第一个字母一般不写成大写的形式。Django将会自动地将需要首字母大写的地方大写。

数据库关系
Django提供了用来描述三种数据库关系的方法,分别是:many-to-one,many-to-many和one-to-one。

Many-to-one
使用django.db.models.ForeignKey来定义Many-to-one这种关系。这个类的使用和其他字段的定义一样,也是作为一个属性存在。
ForeignKey需要一个位置指示参数:当前model相关联的class类名。
例如,Car 和Manufacturer(制造商)。每个Manufacturer都会制造很多Car,但是每辆Car只属于一家Manufacturer,这样的关系就称为多对一关系。基于此例子,代码可以编写如下:
在这里插入图片描述
关于ForeignKey更加详尽的定义链接如下。

Many-to-many
举个例子,每个Pizza对象都有多个Topping对象,而多个Topping对象则可以在多个Pizza饼上。代码如下:
在这里插入图片描述
————(复杂的多对多情况遇到的时候再补充)—————–

One-to-one
例如,如果你构建了一个名为places的数据库,你应该在数据库中构建相对标准的东西例如地址,电话号码等。然后,如果你想在places的基础上创建一个restaurants 的数据表,这时你就可以直接使用places 所定义好的部分,使用的方式就是一种one-to-one的模式。

跨APP的model调用
如果当前app下models.py 文件中的代码想要调用另外一个app中models.py中的model,这也是可以的。做法就是在当前文件中以导入类的方式导入你想要使用的外部的model,然后直接使用即可:
在这里插入图片描述
字段的名称限定
Django对于字段的限制有两个:

  • 字段的名称不能为Python的关键字,这个比较好理解,举例如下:
    在这里插入图片描述
    字段的名称不能包含超过两个下划线,因为这会与Django查找语法起冲突。
    在这里插入图片描述
    SQL的一些保留字如`join,where,select则是可以在model的字段名称中使用的,因为Django在每次SQL查询中避免了可能发生的冲突。

自定义字段类型
如果现有的字段无法满足你的需求,你也可以自定义字段。具体的细节参考此链接。

Meta选项
通过使用内部类Meta来设置model的元数据,例子如下:
在这里插入图片描述
Model的元数据是“任何非字段的数据”,例如ordering的选项,数据表名字(db_table),或者人类可读的单复数名称(verbose_name和verbose_name_plural)。这些都不是Model所必需的,是可选项。
更多关于Meta的选项点击此链接。

Model属性
objects:
model最重要的属性是Manager。它是提供给Django的数据库查询操作的接口,用于从数据库中获取model实例。若非特别声明Manager,它默认的名字为objects。Manager只能通过model类进行访问,不能通过model实例进行访问。

Model方法
为model的对象操作定义一般的“row-level”功能。而Manager方法是对于整张表操作的方法。model的方法应该作用于某一特定的model实例上。
对于使得业务逻辑的统一来说这是一项很有价值的技术。
例如,下面的model有一些常用方法:
在这里插入图片描述
本例中的最后一个方法是一个property。
model实例有很多方法的接口,你可以通过重写这些方法来实现自己想要的功能:
str():
Python的”魔力函数“,该函数返回一个表示当前对象的字符串。适用于Python或者Django用于将实例显示为纯字符串的形式,这样的情形往往会出现在交互的命令行窗口或者在admin页面中。
get_absolute_url():
该函数告诉Django如何计算一个对象的url。Django
在admin接口中使用该函数,在需要的时候返回对象的url。

覆写预定义的模型方法
还有一些其他方法封装了一些你可能会使用到的数据库操作。尤其是save()和delete()方法比较常用。
你可以自由覆写这些方法来获得自己想要的数据库操作。
一个典型的使用情景是如果你想要在保存对象到数据库的时候做一些事情,就可以覆写实现。以save()函数为例:
在这里插入图片描述
不要忘记在覆写的时候调用父类的方法super().save(*args,**kwargs),这样可以确保对象可以存储到数据库中。如果你忘记了调用父类的方法,那么所有的操作都不会数据库中生效。

在shell中对数据库进行操作
Django提供了一个命令行工具,可以将当前项目下的环境,迁移到当前工作环境下。

在建立了model之后,可以在shell中对model进行操作,执行以下语句,进入shell:
python manage.py shell
执行后,进入python命令行模式,此时就可以在这里对你建立的model进行操作了。
假设我们建立了两个model,定义如下:

在这里插入图片描述
数据的插入
在这里插入图片描述
以上代码执行后,会在mysql数据库的myapp_grades数据表中插入一条数据。

数据的修改
在这里插入图片描述

数据的删除
在这里插入图片描述

关联对象
在这里插入图片描述

关联对象 下,对于获取关联对象的机集合,有两个主要任务:

获得一条Grades数据所对应的所有学生Student
获得Student所对应的班级Grade

Model继承
Django中Model的继承方式几乎和Python中类的继承方式几乎一样。所有的model都继承于实例django.db.models.Model。
你需要做的决定仅仅是你的父类model的角色:是作为一个抽象类,给子类提供一个通用部分的描述?还是直接作为实例,拥有自己的数据表?以下是三种最常用的类继承模式:

通常情况下,我们只想使用父类来保存一些你不想在每个子类中都敲一遍的通用信息。该类不会真正对数据库操作,也就是所谓的抽象基类。
如果你继承了一个现存的模型(可能来自于另外一个app实例)并且想要每个model都有自己的数据表,Multi-table inheritance就是这样做的。
最后,如果你只是想要修改Python语言级别的model行为而不修改models的字段,你可以使用Proxy models
抽象基类
抽象基类在你想要在你的模型中加入一些信息的时候很有用。在元数据中将基类的参数abstract=True,这样,该model就不会被用来创建任何数据表。当它被其他model作为基类时,它的字段将会作为继承它基类的字段。子类中的字段名不能和基类中的字段名一样,否则会报错。下面是一个例子:
在这里插入图片描述
Student模型有三个字段,分别是name,age和home_group。
CommonInfo模型不能被用作是一个正常的Django模型,因为他是一个抽象基类,它不会生成数据库表或者有manager,不能被直接实例化或者保存。

Meta继承
当一个抽象基类被创建的时候,Django会声明一些Meta 内部类,若子类没有声明它自己的Meta类,它就会继承父Meta。如果子类想要拓展父Meta类,需要先继承,再拓展:
在这里插入图片描述
Django对于抽象基类Meta类做了调整:在使用Meta属性的时候,会设置abstract=False 。这意味着抽象基类的子类不会自动变成抽象类,除非你自己手动将其设置为True,让其成为抽象类。

<think> 我们正在讨论的是Django模型中的`__str__`方法中的return语句,用户的问题集中在return语句的作用上。 根据引用[3]中的示例,在Django模型中定义了两个模型类Publisher和Book,每个类中都有一个`__str__`方法,该方法返回一个字符串。 因此,用户所问的return语句应该是指模型类中的`__str__`方法中的return。 作用: 1.Django的管理后台(admin site)中,当我们查看一个对象列表或者某个对象的详细信息时,显示的对象名称就是通过`__str__`方法返回的字符串。 2.Django的shell或者普通Python代码中,当我们打印一个模型实例时(如`print(publisher_instance)`),也会显示这个字符串。 3. 它使得模型实例在需要字符串表示的时候有一个可读性较好的形式,而不是默认的`<Publisher: Publisher object (1)>`这样的形式。 示例说明: 在引用[3]中: class Publisher(models.Model): name = models.CharField(max_length=30) # ... 其他字段 ... def __str__(self): return self.name 这里,当我们创建一个Publisher对象,比如`p = Publisher(name='ABC Publishing')`,那么在打印p(或者在一些需要字符串表示的上下文中)时,就会显示'ABC Publishing'。 另外,引用[5]中提到了模型的一些查询方法,比如get()返回一个对象,而当我们直接查看这个对象时,也是通过`__str__`方法显示的。 注意:在Python中,`__str__`方法是对象的一个特殊方法,用于返回一个非正式的、可读性好的字符串表示。而Django模型继承自`models.Model`,所以我们可以重写这个方法。 因此,在Django模型中,return语句在`__str__`方法中的作用就是返回该模型实例的易读字符串表示。 相关问题: 1. 如果不在Django模型中定义`__str__`方法会怎样? 2. 除了`__str__`方法,Django模型还有哪些常用的特殊方法? 3. 如何自定义Django管理后台中对象的显示方式? 4. 在`__str__`方法中可以返回非字符串类型的值吗? 5. 在`__str__`方法中访问关联字段需要注意什么? </think> 在 Django 模型中,`return` 语句主要用于 `__str__()` 方法中,其核心作用是**定义模型对象的可读字符串表示**。以下是具体作用和意义: ### 核心功能详解 1. **对象可读化**   在 Django Admin、Shell 或模板中显示对象时,自动调用 `__str__()` 方法   替代默认的 `<ModelName: object (id)>` 显示   示例:`<Publisher: 清华大学出版社>` 代替 `<Publisher: object (1)>`[^3] 2. **管理界面优化** ```python class Publisher(models.Model): name = models.CharField(max_length=30) def __str__(self): return self.name # 在Admin列表页直接显示出版社名称 ```   → 在 Django Admin 后台的对象列表页和详情页显示人性化内容 3. **调试与日志**   使用 `print(obj)` 或日志记录时输出有意义的信息   示例:调试时直接看到 `Book: Python编程入门` 而非内存地址 4. **关系对象显示**   外键关联对象自动调用其 `__str__()` ```python class Book(models.Model): publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE) # 显示时会自动调用 Publisher.__str__() ``` ### 技术要点 | 场景 | 返回值要求 | 示例代码 | |---------------------|----------------------------|-----------------------------| | 简单模型 | 核心字段值 | `return self.title` | | 复合标识 | 多字段组合 | `return f"{self.id}-{self.name}"` | | 关联模型 | 关联对象的字符串表示 | `return self.author.name` | | 避免错误 | 必须返回字符串类型 | ❌ `return self.id` (应转换为str) | ### 最佳实践建议 1. **必选实现** Django 官方强烈建议为每个模型定义 `__str__()` 方法[^2] 2. **内容简洁明确** ```python # 推荐:关键标识字段 def __str__(self): return self.name # 避免:返回过长或复杂数据 def __str__(self): return self.content[:100] # 可能截断重要信息 ``` 3. **关联对象处理** ```python def __str__(self): return f"{self.publisher.name} | {self.title}" ``` 4. **多语言支持** 如需国际化,使用 `django.utils.translation.gettext_lazy`: ```python from django.utils.translation import gettext_lazy as _ def __str__(self): return _("Book: %(title)s") % {'title': self.title} ``` ### 与其他方法对比 | 方法 | 触发场景 | 常见用途 | |---------------|-----------------------|-----------------------| | `__str__()` | 人性化显示 | Admin/Shell/模板 | | `__repr__()` | 开发调试 | 日志/错误跟踪 | | `get_absolute_url()` | 对象详情页 | 重定向/CRUD操作 | > 在引用[3]的示例中,`return self.name` 确保了出版社和书籍对象在系统中始终显示可读名称,极大提升开发体验[^3]。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值