Django:学习笔记(6)——模型
Django:学习笔记(6)——模型
快速上手
模型到底是什么呢?我们可以想,如果一张数据表的各个字段可以自动映射到一个类的各个属性,则每条记录对应这个类的一个对象。那我们通过类方法来操作对象(即表记录)就会很容易了。这也大大简化了我们对SQL语句的依赖。
在Django中,这种类统称为模型,我们只管创建模型,Django会自动为我们创建响应的数据表。
比如,我们创建一个Peron模型:
from django.db import models class Person(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
first_name
和 last_name
是模型的字段。每个字段都被指定为一个类属性,并且每个属性映射为一个数据库列。
上面的 Person
模型会创建一个如下的数据库表:
CREATE TABLE myapp_person (
"id" serial NOT NULL PRIMARY KEY,
"first_name" varchar(30) NOT NULL,
"last_name" varchar(30) NOT NULL
);
在创建完模型后,切莫执行数据迁移命令,来将模型变动同步到数据库。
关于字段
在创建模型是,我们需要声明各个属性映射的字段。
常见的字段类型如下:
常见的字段选项如下:
- null:设置为true,表示该字段默认为NULL。
- blank:设置为true,表示该字段允许为空。
- choices:该参数接受一个可迭代的列表或元组。如果指定了该参数,在实例化该模型时,该字段只能取选项列表中的值。
- 一个选项列表:
YEAR_IN_SCHOOL_CHOICES = (
('FR', 'Freshman'),
('SO', 'Sophomore'),
('JR', 'Junior'),
('SR', 'Senior'),
('GR', 'Graduate'),
) 每个二元组的第一个值会储存在数据库中,而第二个值将只会用于显示作用。
- 一个选项列表:
- unique:为true,表示该字段值整个表唯一。
- primary_key:为true,表示改字段为该模型的主键。
- default:该字段的默认值。
关于主键
我们创建模型时,没有定义di属性,但是在创表的SQL语句中出现了ID,这是因为默认情况下,Django会给每一个模型添加下面字段。
id = models.AutoField(primary_key=True)
这是一个自增的主键。任何一个模型都必须有一个主键。在你想要设置为主键的字段上设置 primary_key=True
选项。如果 Django 看到你显式的设置了 Field.primary_key
,将不会自动在表(模型)中添加 id
列。
主键字段是只可读得,如果你修改了一个模型实例的主键值并保存,就等同于创建了一个新的模型实例。
from django.db import models class Fruit(models.Model):
name = models.CharField(max_length=100, primary_key=True) >>> fruit = Fruit.objects.create(name='Apple')
>>> fruit.name = 'Pear'
>>> fruit.save()
>>> Fruit.objects.values_list('name', flat=True)
<QuerySet ['Apple', 'Pear']>
关联关系
关系型数据库的强大之处在于个表之间的关联关系,无非是多对一、多对多、一对一。在Django中,表之间的关联关系,在这里当然体现为模型之间的关联关系。
多对一关系
比如A汽车制造厂,制造了多辆汽车,他们之间是多对一关系,即多量汽车都是同一个汽车制造厂制造。那么A汽车、B汽车等汽车一定要有一个外键指向A汽车制造厂的ID。
from django.db import models # Create your models here. class Manufacturer(models.Model):
#....
pass class Car(models.Model):
#....
manufacturer = models.ForeignKey(Manufacturer,on_delete=models.CASCADE)
建议设置ForeignKey字段名为要关联的模型名,正如代码所示,但是你也可以设置为你自己想要的名称。
我们来分析一下,在数据库层面是如何处理多对一关系的。
不出所料,每一个汽车有一个外键,指向了其 制造厂。
多对多关系
A、B汽车制造厂都参与制造了A\B\C\...等汽车,一辆车由多个汽车制造厂联合制造,一个汽车制造厂参与制造了多亮汽车。此时汽车制造厂与汽车之间形成了多对多关系。
from django.db import models # Create your models here. class Manufacturer(models.Model):
#....
pass class Car(models.Model):
#....
manufacturers = models.ManyToManyField(Manufacturer)
建议设置ManyToManyField字段名为一个复数名词,表示要关联的模型对象的集合。对于多对多关联关系的两个模型,可以在任何一个模型中添加ManyToManyField字段,但只能选择一个模型设置该字段,即不能在两个模型中添加该字段。
我们来分析一下,数据库层面是如何处理这样多对多关系的。
首先,建立了三张表,最主要是的中间这张表,他记录了汽车与制造商的关联关系。也就是说只要在第二种表中传入汽车的id就能获取所关联制造厂的所有id,同样传入汽车制造厂的id就能获取其制造的所有汽车的id。
一对一关系
一对一关系是指关系数据库中两个表之间的一种关系,该关系中第一个表中的单个行只可以与第二个表中的一个行相关,且第二个表中的一个行也只可以与第一个表中的一个行相关。我们现在以饭店和它的地皮为例:
from django.db import models class Place(models.Model):
name = models.CharField(max_length=50)
address = models.CharField(max_length=80) def __str__(self):
return "%s the place" % self.name class Restaurant(models.Model):
place = models.OneToOneField(
Place,
on_delete=models.CASCADE,
primary_key=True,
)
serves_hot_dogs = models.BooleanField(default=False)
serves_pizza = models.BooleanField(default=False) def __str__(self):
return "%s the restaurant" % self.place.name
一个饭店对应一个地点,它们构成一对一关系。
# 现在我们创建几个地方
>>> p1 = Place(name='Demon Dogs', address='944 W. Fullerton')
>>> p1.save()
>>> p2 = Place(name='Ace Hardware', address='1013 N. Ashland')
>>> p2.save()
# 创建一个餐馆,并传入一个地方
>>> r = Restaurant(place=p1, serves_hot_dogs=True, serves_pizza=False)
>>> r.save()
# 餐厅可进入其地点
>>> r.place
<Place: Demon Dogs the place>
# 一个地方可显示其餐厅
>>> p1.restaurant
<Restaurant: Demon Dogs the restaurant>
我们来分析一下,数据库层面是如何处理这样一对一关系的。
一对一关系,数据库建立了两张表,place表有自增主键,restaurant表的主键参照place的主键。这样可以方便的从地皮找到其对应的餐厅(餐厅的id参照地皮的id),也可以方便的从餐厅找到其对应的地皮(同样地皮的id就是餐厅的id)。
Meta选项
模型的元数据Meta,指的是“除了字段外的所有内容”,例如排序方式、数据库表名、人类可读的单数或者复数名等等。所有的这些都是非必须的,甚至元数据本身对模型也是非必须的。但是,我要说但是,有些元数据选项能给予你极大的帮助,在实际使用中具有重要的作用,是实际应用的‘必须’。
创建一个元数据
想在模型中增加元数据,方法很简单,在模型类中添加一个子类,名字是固定的Meta
,然后在这个Meta类下面增加各种元数据选项或者说设置项。
from django.db import models class Ox(models.Model):
horn_length = models.IntegerField() class Meta: # 注意,是模型的子类,要缩进!
ordering = ["horn_length"]
上面的例子中,我们为模型Ox增加了两个元数据‘ordering’,分别表示排序依据,下面我们会详细介绍有哪些可用的元数据选项。
强调:每个模型都可以有自己的元数据类,每个元数据类也只对自己所在模型起作用。
更多元数据的配置项
请查看官方文档:https://docs.djangoproject.com/zh-hans/2.1/ref/models/options/
模型方法
模型,提供了一些内置的功能,同样也支持我们自定义一些新的功能。
我们建立模型、保存数据为的就是在需要的时候可以查询得到数据。Django自动为所有的模型提供了一套完善、方便、高效的API,一些重要的,我们要背下来,一些不常用的,要有印象,使用的时候可以快速查找参考手册。
保存及创建对象
>>> from blog.models import Blog
>>> b = Blog(name='Beatles Blog', tagline='All the latest Beatles news.')
>>> b.save() #或者一条语句
b = Blog.objects.create(name='Beatles Blog', tagline='All the latest Beatles news.')
注意,在保存字段中有外键的实例时,需要想将其外键对象查找出来,再进行保存:
entry = Entry.objects.get(pk=1)
cheese_blog = Blog.objects.get(name="Cheddar Talk")
entry.blog = cheese_blog
entry.save()
检索对象
想要从数据库内检索对象,你需要基于模型类,通过管理器(Manager)构造一个查询结果集(QuerySet)。
每个QuerySet代表一些数据库对象的集合。它可以包含零个、一个或多个过滤器(filters)。Filters缩小查询结果的范围。在SQL语法中,一个QuerySet相当于一个SELECT语句,而filter则相当于WHERE或者LIMIT一类的子句。
通过模型的Manager获得QuerySet,每个模型至少具有一个Manager,默认情况下,它被称作objects
,可以通过模型类直接调用它,但不能通过模型类的实例调用它,以此实现“表级别”操作和“记录级别”操作的强制分离。如下所示:
from blog.models import Entry
# 检索所有对象
all_entries = Entry.objects.all() # 检索单一数据
one_entry = Entry.objects.get(pk=1) # 数据切片
Entry.objects.all()[:5] # 返回前5个对象
Entry.objects.all()[5:10] # 返回第6个到第10个对象 # 过滤对象(只要2006年的数据)
Entry.objects.filter(pub_date__year=2006) # 过滤对象(除了2006年的数据都要)
Entry.objects.exclude(pub_date__year=2006)
删除对象
Entry.objects.filter(pub_date__year=2005).delete()
#或者
b = Entry.objects.get(pk=1)
# 下面的动作将删除该条Entry和所有的它关联的对象
b.delete()
自定义功能
当然,除了使用Django提供的模型方法,我们也可以自定义自己的方法,或者重写原有的方法。
from django.db import models class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField() def save(self, *args, **kwargs):
do_something()
super().save(*args, **kwargs) # Call the "real" save() method.
do_something_else()
结语
这篇博客的篇幅太长了,一定讲不好模型。我们会在下篇文章中重点阐述模型的更多内容。
Django:学习笔记(6)——模型的更多相关文章
- Django 学习笔记之模型高级用法
目录 1 复杂的字段类型 1.1 整数类型的区别 1.2 自增类型的区别 1.3 时间类型 1.4 FilePathField 1.5 FileField 1.6 ImageField 2 关系字段 ...
- Django学习笔记二
Django学习笔记二 模型类,字段,选项,查询,关联,聚合函数,管理器, 一 字段属性和选项 1.1 模型类属性命名限制 1)不能是python的保留关键字. 2)不允许使用连续的下划线,这是由dj ...
- Django:学习笔记(7)——模型进阶
Django:学习笔记(7)——模型进阶 模型的继承 我们在面向对象的编程中,一个很重要的的版块,就是类的继承.父类保存了所有子类共有的内容,子类通过继承它来减少冗余代码并进行灵活扩展. 在Djang ...
- Django学习笔记(16)——扩展Django自带User模型,实现用户注册与登录
一,项目题目:扩展Django自带User模型,实现用户注册与登录 我们在开发一个网站的时候,无可避免的需要设计实现网站的用户系统.此时我们需要实现包括用户注册,登录,用户认证,注销,修改密码等功能. ...
- Django 学习笔记之四 QuerySet常用方法
QuerySet是一个可遍历结构,它本质上是一个给定的模型的对象列表,是有序的. 1.建立模型: 2.数据文件(test.txt) 3.文件数据入库(默认的sqlite3) 入库之前执行 数据库同步命 ...
- Django学习笔记(三)—— 型号 model
疯狂暑期学习 Django学习笔记(三)-- 型号 model 參考:<The Django Book> 第5章 1.setting.py 配置 DATABASES = { 'defaul ...
- Django学习笔记(9)—— 开发用户注册与登录系统
一,项目题目: 开发用户注册与登录系统 该项目主要练习使用Django开发一个用户注册与登录的系统,通过这个项目然后巩固自己这段时间所学习的Django知识. 二,项目需求: 开发一个简单的用户登录与 ...
- Django学习笔记(4)——Django连接数据库
前言 在MVC或者MTV设计模式中,模型(M)代表对数据库的操作.那么如何操作数据库呢?本小节就认真学习一下.首先复习一下Django的整个实现流程 ,然后再实现一下使用数据库的整个流程,最后学习一下 ...
- Django学习笔记(13)——Django的用户认证(Auth)组件,视图层和QuerySet API
用户认证组件的学习 用户认证是通过取表单数据根数据库对应表存储的值做比对,比对成功就返回一个页面,不成功就重定向到登录页面.我们自己写的话当然也是可以的,只不过多写了几个视图,冗余代码多,当然我们也可 ...
随机推荐
- jquery ajax 的用法
jquery的ajax请求的主要参数 beforeSend:发送ajax请求之前 success:发送ajax请求成功 error:发送ajax请求错误,通常是网络失去连接.服务器出错.后台方法错误等 ...
- hdu 2105:The Center of Gravity(计算几何,求三角形重心)
The Center of Gravity Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Ot ...
- unity导弹算法 预计目标点
关于导弹的飞行算法,网上有很多教程.简单算法无非是获取目标点的当前位置,然后导弹朝目标方向移动.高深点的,就是通过计算获取碰撞点然后朝着目标移动.如果你能看懂这个高深算法的话,可以去看原帖:http: ...
- Spring_day03--Spring配置c3p0连接池和dao使用jdbcTemplate
Spring配置c3p0连接池和dao使用jdbcTemplate 1 spring配置c3p0连接池 第一步 导入jar包 第二步 创建spring配置文件,配置连接池 原始方式 (1)把代码在配置 ...
- JAVA上百实例源码网站
JAVA源码包1JAVA源码包2JAVA源码包3JAVA源码包4 JAVA开源包1 JAVA开源包2 JAVA开源包3 JAVA开源包4 JAVA开源包5 JAVA开源包6 JAVA开源包7 JAVA ...
- 【黑金原创教程】【TimeQuest】【第七章】供源时钟与其他
声明:本文为黑金动力社区(http://www.heijin.org)原创教程,如需转载请注明出处,谢谢! 黑金动力社区2013年原创教程连载计划: http://www.cnblogs.com/al ...
- 《从零开始学Swift》学习笔记(Day 69)——Swift与Objective-C混合编程之语言
原创文章,欢迎转载.转载请注明:关东升的博客 在Swift语言出现之前,开发iOS或OS X应用主要使用Objective-C语言,此外还可以使用C和C++语言,但是UI部分只能使用Objective ...
- Android 将时间戳转为代表"距现在多久之前"的字符串
public String getStandardDate(int dateTime) { StringBuffer sb = new StringBuffer(); long t = Long.pa ...
- linux shell 脚本使用
定义变量 fileName=text.txt 变量名称fileName,变量名称text.txt 使用变量 $fileName 用美元符号$开头,后面加变量名称,即可使用变量 使用用户输入参数 打印第 ...
- Sharepoint ECMAScript
前言 本文完全原创,转载请说明出处,希望对大家有用. 本篇博客是个人总结,一方面以便日后查看,另一方面希望能为其他人提供一些便利. 阅读目录 加载必要文件 (Get,Update,Delete,Add ...