Django模型层(1)模型介绍

模型

模型准确且唯一的描述了数据。它包含您存储的数据的重要字段和行为。一般来说,每一个模型都映射一张数据库表。

  • 每个模型都是一个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的内容

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值