文章目录
模型
模型准确且唯一的描述了数据。它包含您存储的数据的重要字段和行为。一般来说,每一个模型都映射一张数据库表。
- 每个模型都是一个Python的类,这些类继承于django.db.models.Model
- 每个模型类的属性都相当于一个数据库的字段。
快速上手定义一个模型
这个样例定义了一个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_name和last_name是模型的字段,每个字段都被指定为一个类属性,并且每个属性映射为一个数据表列。
上面的Person模型会创建如下一张数据库表:
create table my_model_person
(
id int not null primary key generated by default as identity,
first_name varchar(30) not null,
last_name varchar(30) not null
);
- 该表的名称 my_model_person 是自动从app名提炼出来的,my_model是该模型的app。
- id是dj自动添加的,可以手动添加。
使用模型
一旦你定义了你的模型,你需要告诉Django你准备使用这些模型了。需要修改设置文件中的INSTALLED_APPS,在这个设置中添加包含models.py文件的模块名称
INSTALLED_APPS = [
...
"myapp"
...
]
如果使用的不是默认的是Mysql数据库还需要在设置中修改DATABASES
DATABASES = {
'default': {
# django数据库引擎
'ENGINE': 'django.db.backends.mysql',
# 数据库名
'NAME': 'you_database_name',
# 用户名
'USER': 'root',
# 登录密码
'PASSWORD': '123456',
# 数据库ip
'HOST': 'localhost',
# 端口
'POST': '3306'
}
}
添加结束后进行数据库的迁移
# 检查app下migrations和models是否有更新
python manage.py makemigrations
# 执行修改
python manage.py migrate
字段
模型中最重要且唯一必要的是数据库的字段定义。字段在类属性中定义。定义字段名时要避免使用与模型API
冲突的名称,例如:
clean,save,delete等。
from django.db import models
class Musician(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
instrument = models.CharField(max_length=100)
class Album(models.Model):
artist = models.ForeignKey(Musician, on_delete=models.CASCADE)
name = models.CharField(max_length=100)
release_date = models.DateField()
num_stars = models.IntegerField()
模型中每一个字段都对应时某个Field类的实例,Django利用这些字段来实现对数据库的操作:
- 字段类型用以指定数据库数据类型
- 基本的有效性验证功能,用于Django后台和自动生成的表单
字段选项
每一种字段都需要指定一些特定的参数。例如 CharField
需要接受一个max_length
参数,用以指定数据库存储VARCHAR
数据时用的字节数
一些可选参数是通用的,可用于任何类型的字段
- null
- 如果设置为True,则该字段可为空。默认为False。
- default
- 该字段的默认值。可以是一个值或是个可调用的对象,如果是个可调用的对象,每次实例化模型的时候都会调用该对象
- unique
- 如果设置为True,则该字段的值在整个表中必须保持唯一
choices
- 一些列二元组,用作此字段的选项。如果提供了二元组则会限制存入的数据。
例如
from django.db import models
class Person(models.Model):
SHIRT_SIZES = [
('S', "Small"),
('M', "Medium"),
('L', "Large")
]
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
shirt_size = models.CharField(max_length=1, choices=SHIRT_SIZES, null=True)
打开交互测试环境:python manage.py shell
from my_model.models import Person
p = Person(first_name="z",last_name="zj",shirt_size="M")
p.save()
p.shirt_size
'M'
p.get_shirt_size_display()
'Medium'
primary_key
如果设置为True,将该字段设置为该模型的主键
主键为只可读
,如果你修改一个记录的主键并保存,这等同于你创建了一个新的记录。
class Fruit(models.Model):
name = models.CharField(max_length=100, primary_key=True)
from my_model.models import Fruit
fruit = Fruit(name="1")
fruit.save()
fruit.name
'1'
fruit.name = "2"
fruit.save()
fruit.name
'2'
Fruit.objects.values_list("name",flat=True)
<QuerySet ['1', '2']>
自增主键
class Animal(models.Model):
id = models.BigAutoField(primary_key=True)
name = models.CharField(max_length=100)
from my_model.models import Animal
# 指定id
a = Animal(id=1,name="dog")
a.name
'dog'
# 不指定id
a = Animal(name="cat")
a.save()
# 从表中拿到所有记录对象
Animal.objects.all()
<QuerySet [<Animal: Animal object (1)>, <Animal: Animal object (2)>]>
# 从表中拿到所有name的值
Animal.objects.values_list("name")
<QuerySet [('dog',), ('cat',)]>
Animal.objects.values_list("name",flat=True)
<QuerySet ['dog', 'cat']>
# 从表中拿到所有id的值
Animal.objects.values_list("id",flat=True)
# 自增没有问题
<QuerySet [1, 2]>
字段备注名
first_name = models.CharField("person's first name",max_length=30)
关联关系
关系型数据库的强大之处在于各个表之间的关联关系。Django提供了定义三种最常见的数据库关联方法:多对一,多对多,一对一
多对一关联
定义一个多对一的关联关系,使用 ForeignKey
class Musician(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
instrument = models.CharField(max_length=100)
class Album(models.Model):
artist = models.ForeignKey(Musician, on_delete=models.CASCADE)
name = models.CharField(max_length=100)
release_date = models.DateField()
num_stars = models.IntegerField()
创建
# 成功保存 create会帮我们直接保存数据
from my_model.models import Musician,Album
m = Musician.objects.create(first_name="1",last_name="2",instrument="3")
a = Album.objects.create(name="4",release_date="2022-10-10",num_stars=5,artist=m)
# 以下操作报错,应为m没有保存就直接作为了a的参数传入
m = Musician(first_name="1",last_name="2",instrument="3")
a = Album(name="4",release_date="2022-10-10",num_stars=5,artist=m)
a.save()
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "C:\Users\g1712\.conda\envs\attend-classclass-begins\lib\site-packages\django\db\models\base.py", line 778, in save
self._prepare_related_fields_for_save(operation_name="save")
File "C:\Users\g1712\.conda\envs\attend-classclass-begins\lib\site-packages\django\db\models\base.py", line 1093, in _prepare_related_fields_for_save
raise ValueError(
ValueError: save() prohibited to prevent data loss due to unsaved related object 'artist'.
# 也可以这样写
m = Musician(first_name="1",last_name="2",instrument="3")
m.save()
a = Album(name="4",release_date="2022-10-10",num_stars=5,artist=m)
a.save()
m = Musician.objects.create(first_name="1",last_name="2",instrument="3")
查询
正查
from my_model.models import Album,Musician
a = Album.objects.first()
m = a.artist
m
<Musician: Musician object (1)>
m.first_name
'1'
反查
需要在模型ForeignKey字段内添加related_name
参数来设置反查的名称 如下模型
class Musician(models.Model):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
instrument = models.CharField(max_length=100)
class Album(models.Model):
artist = models.ForeignKey(Musician, on_delete=models.CASCADE, related_name="album")
name = models.CharField(max_length=100)
release_date = models.DateField()
num_stars = models.IntegerField()
m = Musician.objects.all()
m
<QuerySet [<Musician: Musician object (1)>, <Musician: Musician object (2)>, <Musician: Musician object (3)>]>
m[0].album
<django.db.models.fields.related_descriptors.create_reverse_many_to_one_manager.<locals>.RelatedManager object at 0x0000025785C976A0>
m[0].album.all()
<QuerySet [<Album: Album object (1)>]>
m[0].album.first()
<Album: Album object (1)>
m[0].album.first().name
'4'
自关联
公司成员都有上级领导,在prent_id中记录的就是上级领导的id
class Member(models.Model):
member_id = models.AutoField(primary_key=True)
prent_id = models.ForeignKey('self', db_column='prent_id', to_field='member_id', on_delete=models.CASCADE)
多对多
披萨、配料对应表
class Pizza(models.Model):
pizza_id = models.AutoField(primary_key=True)
name = models.CharField()
class Topping(models.Model):
topping_id = models.AutoField(primary_key=True)
name = models.CharField()
class PizzaToppingMapping(models.Model):
pizza_topping_mapping_id = models.AutoField(primary_key=True)
pizza_id = models.ForeignKey(Pizza, on_delete=models.CASCADE)
topping_id = models.ForeignKey(Topping, on_delete=models.CASCADE)
创建
from my_model.models import Pizza,Topping,PizzaToppingMapping
# 添加
p = Pizza.objects.create(name="奥尔良鸡翅烤肉披萨")
t = Topping.objects.create(name="奥尔良鸡翅")
t1 = Topping.objects.create(name="烤肉")
t2 = Topping.objects.create(name="芝士")
pt = PizzaToppingMapping.objects.create(pizza_id=p,topping_id=t)
pt = PizzaToppingMapping.objects.create(pizza_id=p,topping_id=t1)
查询
做查询ForeignKey
字段时需添加 related_name="mapping"
如下
class Pizza(models.Model):
pizza_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=20)
class Topping(models.Model):
topping_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=20)
class PizzaToppingMapping(models.Model):
pizza_topping_mapping_id = models.AutoField(primary_key=True)
pizza_id = models.ForeignKey(Pizza, on_delete=models.CASCADE, related_name="mapping")
topping_id = models.ForeignKey(Topping, on_delete=models.CASCADE, related_name="mapping")
topping 查 pizza
from my_model.models import Pizza,Topping,PizzaToppingMapping
t = Topping.objects.first()
t
<Topping: Topping object (1)>
t.mapping.all()
<QuerySet [<PizzaToppingMapping: PizzaToppingMapping object (1)>]>
t.mapping.first()
<PizzaToppingMapping: PizzaToppingMapping object (1)>
t.mapping.first().pizza_id
<Pizza: Pizza object (1)>
t.mapping.first().pizza_id.name
'奥尔良鸡翅烤肉披萨'
pizza 查 topping
p = Pizza.objects.first()
p
<Pizza: Pizza object (1)>
p.mapping.all()
<QuerySet [<PizzaToppingMapping: PizzaToppingMapping object (1)>, <PizzaToppingMapping: PizzaToppingMapping object (2)>]>
mapping_list = p.mapping.all()
for i in mapping_list:
print(i.topping_id.name)
奥尔良鸡翅
烤肉
Meta
模型的元数据即“所有不是字段的东西”,比如排序选项(ordering),数据库表名(db_table)。
这些都不是必须的,是可选的。
class Animal(models.Model):
animal_id = models.AutoField(primary_key=True)
create_time = models.DateTimeField(auto_now_add=True, null=True)
update_time = models.DateTimeField(auto_now=True, null=True)
is_delete = models.SmallIntegerField(default=0)
class Meta:
# 排序 升序 降序的话(-create_time)
ordering = ["create_time"]
# 指定表名
db_table = "animal"
模型方法
在模型中添加自定义方法,会给你的对象提供“行级”操作能力。与之对应的是类Manager的方法在提供的“表级”的操作,模型方法应在某个对象实例上生效。
class Animal(models.Model):
animal_id = models.AutoField(primary_key=True)
create_time = models.DateTimeField(auto_now_add=True, null=True)
update_time = models.DateTimeField(auto_now=True, null=True)
is_delete = models.SmallIntegerField(default=0)
class Meta:
# 排序 升序 降序的话(-create_time)
ordering = ["create_time"]
# 指定表名
db_table = "animal"
def print_cat(self):
return "cat"
重写之前定义的模型方法
还有一个模型方法的集合,包括了一些你可能自定义的数据库行为,如 save()和delete()。
class Animal(models.Model):
animal_id = models.AutoField(primary_key=True)
create_time = models.DateTimeField(auto_now_add=True, null=True)
update_time = models.DateTimeField(auto_now=True, null=True)
is_delete = models.SmallIntegerField(default=0)
class Meta:
# 排序 升序 降序的话(-create_time)
ordering = ["create_time"]
# 指定表名
db_table = "animal"
def save(self, *args, **kwargs):
"""你添加的逻辑"""
do_something()
super().save(*args, **kwargs)
do_something_else()
你也可以阻止保存
class Animal(models.Model):
animal_id = models.AutoField(primary_key=True)
create_time = models.DateTimeField(auto_now_add=True, null=True)
update_time = models.DateTimeField(auto_now=True, null=True)
is_delete = models.SmallIntegerField(default=0)
class Meta:
# 排序 升序 降序的话(-create_time)
ordering = ["create_time"]
# 指定表名
db_table = "animal"
def save(self, *args, **kwargs):
"""你添加的逻辑"""
if self.animal_id == 5:
return "xxx"
else:
super().save(*args, **kwargs)
模型继承
模型继承在DJ中与普通类继承在Python中的工作方式几乎完全相同。
我们只需要决定父类模型是否可以被继承(是否可以被作为父类)
- 父类作为子类共工信息的载体,减少重复代码的敲击工作。这样的父类基本上不会单独使用,我们称其为抽象类。
抽象基类
抽象基类在你要将公告信息放入很多模型的时候会很有用。在 Meta
类中填入 abstract=True
。该模型不会创建任何数据表。如下:
class Animal(models.Model):
create_time = models.DateTimeField(auto_now_add=True, null=True)
update_time = models.DateTimeField(auto_now=True, null=True)
is_delete = models.SmallIntegerField(default=0)
class Meta:
abstract = True
# 排序 升序 降序的话(-create_time)
ordering = ["-create_time"]
class Dog(Animal):
dog_id = models.AutoField(primary_key=True)
class Meta:
# 指定表名
db_table = "dog"
Animal模型拥有三个基础字段 create_time
update_time
is_delete
那么当 Dog模型继承Animal模型的时候同样这三个字段也就拥有了 ,包括Meta的内容