Django回顾【四】之模型层

目录

一、基本使用

1、ORM框架

2、创建表

二、常用和非常用字段

三、常用和非常用字段参数

四、settings配置

五、基本操作

[5.1 增加表记录](#5.1 增加表记录)

[5.2 删除表纪录](#5.2 删除表纪录)

[5.3 更新表纪录](#5.3 更新表纪录)

[5.4 查询表纪录](#5.4 查询表纪录)

[六、 多表操作-创建关系](#六、 多表操作-创建关系)

七、基于对象的跨表查询

八、基于链表的跨表查询


一、基本使用

1、ORM框架

ORM ----> 对象-关系映射

  • 数据库中:一个个表 :user表,book表,一条条的记录
  • 程序中:一个个类,一个个对象
    • 以后数据库中一张表 ----->对应程序中一个类
    • 以后数据库中一条记录 ---->对应程序中一个对象

2、创建表

在models.py中写一个个类

python 复制代码
from django.db import models


# Create your models here.
# 写一个个类
import datetime
class Book1(models.Model):
    id = models.AutoField(primary_key=True) 
    # 自增 primary_key=True不写默认为主键
    title = models.CharField(max_length=64, db_index=True)
    # db_index=True表示索引
    price = models.DecimalField(max_digits=7, decimal_places=2)
    # DecimalField(Field) ---> 10进制小数
    # max_digits表示最大位数  decimal_places表示小数点后几位

映射到sqlite中

python 复制代码
# 执行命令
python manage.py makemigrations
python manage.py migrate

二、常用和非常用字段

python 复制代码
AutoField(Field)
    - int自增列,必须填入参数 primary_key=True

BigAutoField(AutoField)
    - bigint自增列,必须填入参数 primary_key=True
    注:当model中如果没有自增列,则自动会创建一个列名为id的列
    from django.db import models
    class UserInfo(models.Model):
        # 自动创建一个列名为id的且为自增的整数列
        username = models.CharField(max_length=32)
    class Group(models.Model):
        # 自定义自增列
        nid = models.AutoField(primary_key=True)
        name = models.CharField(max_length=32)
SmallIntegerField(IntegerField):
    - 小整数 -32768 ~ 32767

PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
    - 正小整数 0 ~ 32767
IntegerField(Field)
    - 整数列(有符号的) -2147483648 ~ 2147483647

PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField)
    - 正整数 0 ~ 2147483647

BigIntegerField(IntegerField):
    - 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807

BooleanField(Field)
    - 布尔值类型

NullBooleanField(Field):
    - 可以为空的布尔值

CharField(Field)
    - 字符类型
    - 必须提供max_length参数, max_length表示字符长度

TextField(Field)
    - 文本类型

EmailField(CharField):
    - 字符串类型,Django Admin以及ModelForm中提供验证机制

IPAddressField(Field)
    - 字符串类型,Django Admin以及ModelForm中提供验证 IPV4 机制



URLField(CharField)
    - 字符串类型,Django Admin以及ModelForm中提供验证 URL

SlugField(CharField)
    - 字符串类型,Django Admin以及ModelForm中提供验证支持 字母、数字、下划线、连接符(减号)

CommaSeparatedIntegerField(CharField)
    - 字符串类型,格式必须为逗号分割的数字

UUIDField(Field)
    - 字符串类型,Django Admin以及ModelForm中提供对UUID格式的验证

FilePathField(Field)
    - 字符串,Django Admin以及ModelForm中提供读取文件夹下文件的功能
    - 参数:
            path,                      文件夹路径
            match=None,                正则匹配
            recursive=False,           递归下面的文件夹
            allow_files=True,          允许文件
            allow_folders=False,       允许文件夹

FileField(Field)
    - 字符串,路径保存在数据库,文件上传到指定目录
    - 参数:
        upload_to = ""      上传文件的保存路径
        storage = None      存储组件,默认django.core.files.storage.FileSystemStorage

ImageField(FileField)
    - 字符串,路径保存在数据库,文件上传到指定目录
    - 参数:
        upload_to = ""      上传文件的保存路径
        storage = None      存储组件,默认django.core.files.storage.FileSystemStorage
        width_field=None,   上传图片的高度保存的数据库字段名(字符串)
        height_field=None   上传图片的宽度保存的数据库字段名(字符串)

DateTimeField(DateField)
    - 日期+时间格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]

DateField(DateTimeCheckMixin, Field)
    - 日期格式      YYYY-MM-DD

TimeField(DateTimeCheckMixin, Field)
    - 时间格式      HH:MM[:ss[.uuuuuu]]

DurationField(Field)
    - 长整数,时间间隔,数据库中按照bigint存储,ORM中获取的值为datetime.timedelta类型

FloatField(Field)
    - 浮点型

DecimalField(Field)
    - 10进制小数
    - 参数:
        max_digits,小数总长度
        decimal_places,小数位长度

BinaryField(Field)
    - 二进制类型

三、常用和非常用字段参数

python 复制代码
(1)null
 
如果为True,Django 将用NULL 来在数据库中存储空值。 默认值是 False.
 
(1)blank 后台管理---》admin中会用,我们一般用的少
 
如果为True,该字段允许不填。默认为False。
要注意,这与 null 不同。null纯粹是数据库范畴的,而 blank 是数据验证范畴的。
如果一个字段的blank=True,表单的验证将允许该字段是空值。如果字段的blank=False,该字段就是必填的。
 
(2)default
 
字段的默认值。可以是一个值或者可调用对象。如果可调用 ,每有新对象被创建它都会被调用。
 
(3)primary_key
 
如果为True,那么这个字段就是模型的主键。如果你没有指定任何一个字段的primary_key=True,
Django 就会自动添加一个IntegerField字段做为主键,所以除非你想覆盖默认的主键行为,
否则没必要设置任何一个字段的primary_key=True。
 
(4)unique
 
如果该值设置为 True, 这个数据字段的值在整张表中必须是唯一的

(5)db_index :该字段建立索引

(6)choices
由二元组组成的一个可迭代对象(例如,列表或元组),用来给字段提供选择项。 如果设置了choices ,默认的表单将是一个选择框而不是标准的文本框,<br>而且这个选择框的选项就是choices 中的选项。
get_type_book_display()


# 关于Meta中
class UserInfo(models.Model):
       nid = models.AutoField(primary_key=True,index=True)
       username = models.CharField(max_length=32)
       mobile=models.CharField(max_length=32)
       class Meta:
           # 数据库中生成的表名称 默认 app名称 + 下划线 + 类名
           db_table = "table_name"

           # 联合索引
           index_together = [
               ("username", "mobile"),
           ]

           # 联合唯一索引
           unique_together = (("username", "mobile"),)

           # admin中显示的表名称
           verbose_name='图书表'

           # verbose_name加s
           verbose_name_plural

四、settings配置

若想将模型转为mysql数据库中的表,需要在settings中配置:

配置文件中的配置

python 复制代码
# 默认配置:操作sqlite
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3', 
        'NAME': BASE_DIR / 'db.sqlite_lyj',
    }
}
python 复制代码
# 操作mysql
# 配置文件:
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'day05',
        'HOST':'127.0.0.1',
        'PORT':3306,
        'USER':'root',
        'PASSWORD':'123',
    }
}
"""
'NAME':要连接的数据库,连接前需要创建好
'HOST':连接主机,默认本机
'PORT':端口 默认3306
'USER':连接数据库的用户名
'PASSWORD':连接数据库的密码
"""

装模块:mysqlclient/pymsql模块

python 复制代码
pip3 install mysqlclient # 其他不需要任何操作 ----》有可能在mac装不上

需要找到项目名文件下的init,在里面写入:

保证它执行,放在配置文件中

python 复制代码
pip3 install pymysql --upgrade # 强制装最新
import pymysql
pymysql.install_as_MySQLdb() 

五、基本操作

  • 新增字段,在类里直接新增字段,直接执行数据库迁移命令会提示输入默认值,此时需要设置
python 复制代码
type_book = models.IntegerField(choices=((1, '技术类'), (2, '玄幻类'), (3, '科技类')), null=True)
  • 删除,直接注释掉字段,执行数据库迁移命令即可

注:不要轻易删除迁移记录

5.1 增加表记录

方式1

python 复制代码
Book.object.create()
  • 方式2
python 复制代码
book = Book(参数)
book.save()

5.2 删除表纪录

  • 方式一:查出来再删
python 复制代码
Book.objects.all().delete()
  • 方式二:可以重写类中得delete方法
python 复制代码
book = Book.objects.filter(pk=1).first()
book.delete() # Book类中有个delete方法,我们没有写---》父类的--》可以重写

5.3 更新表纪录

方式一:查出来再更新

python 复制代码
Book.objects.all().update()

方式二:

python 复制代码
book = Book.objects.filter(pk=1).first()
book.name = 'ss'
book.save()

5.4 查询表纪录

查询API

python 复制代码
<1> all():                  查询所有结果
  
<2> filter(**kwargs):       它包含了与所给筛选条件相匹配的对象
  
<3> get(**kwargs):          返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。
  
<4> exclude(**kwargs):      它包含了与所给筛选条件不匹配的对象
 
<5> order_by(*field):       对查询结果排序('-id')
  
<6> reverse():              对查询结果反向排序
  
<8> count():                返回数据库中匹配查询(QuerySet)的对象数量。
  
<9> first():                返回第一条记录
  
<10> last():                返回最后一条记录
  
<11> exists():              如果QuerySet包含数据,就返回True,否则返回False
 
<12> values(*field):        返回一个ValueQuerySet------一个特殊的QuerySet,运行后得到的并不是一系列
                            model的实例化对象,而是一个可迭代的字典序列
<13> values_list(*field):   它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
 
<14> distinct():            从返回结果中剔除重复纪录

六、 多表操作-创建关系

python 复制代码
class Book(models.Model):
    name = models.CharField(max_length=32,null=True)
    price = models.DecimalField(max_digits=5, decimal_places=2)
    publish_date = models.DateField(auto_now=True)
    publish = models.ForeignKey(to='Publish',on_delete=models.DO_NOTHING,null=True,default=1,db_constraint=False)
    # 这不是个字段
    authors=models.ManyToManyField(to='Author')
    def __str__(self):
        return self.name


class Author(models.Model):
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    author_detail = models.OneToOneField(to='AuthorDatail',unique=True,on_delete=models.CASCADE)

class AuthorDatail(models.Model):
    telephone = models.BigIntegerField()
    birthday = models.DateField()
    addr = models.CharField(max_length=64)

class Publish(models.Model):
    name = models.CharField(max_length=32)
    city = models.CharField(max_length=32)
    email = models.EmailField()

关联关系有如下几种

  1. 一对一:本质就是一对多,只不过多的字段唯一
  2. 一对多:外键关联
  3. 多对多:必须要有中间表

OneToOneField,ForeignKey 必须写on_delete,不写报错

on_delete可选的参数有哪些

  • 1 models.CASCADE 级联删除
    • 删除出版社
    • 当前出版社下所有的图书数据都会被删除
  • 2 models.SET_NULL 删除出版社
    • 当前出版社下所有的图书数据都会的publish_id字段都是置为空
python 复制代码
publish = models.ForeignKey(to='Publish',on_delete=models.SET_NULL,null=True)
  • 3 models.SET_DEFAULT
  • 删除出版社
    • 当前出版社下所有的图书数据都会的publish_id字段都设为默认值
python 复制代码
publish = models.ForeignKey(to='Publish',on_delete=models.SET_DEFAULT,default=1)
  • 4 models.SET(值/可调用对象)
  • 删除出版社
    • 当前出版社下所有的图书数据都会的publish_id字段都设为SET传入的值,如果是可调用对象,会执行可调用对象,把return的值放在这里
python 复制代码
publish = models.ForeignKey(to='Publish',on_delete=models.SET(),null=True,default=1)
  • 5 models.DO_NOTHING
  • 删除出版社
    • 当前出版社下所有的图书数据都会的publish_id字段 原封不动,由于有外检字段的约束,所以必须加上db_constraint=False
python 复制代码
publish = models.ForeignKey(to='Publish',on_delete=models.DO_NOTHING,db_constraint=False)

七、基于对象的跨表查询

假设拿到book对象

python 复制代码
book.name
book.price
book.publish_id ---->数字---》出版社id号
---》我们可以通过出版社id,再去出版社表,查出当前出版社---》很麻烦

快捷方式

python 复制代码
book.publish ---->拿到的是   publish对象---》当前图书的出版社对象
book.publish.继续往后点击

上面这种查询方式,称之为基于对象的跨表查询

python 复制代码
对象 = 对象.字段
publish = book.pulish 

有正向查询和反向查询 -----》拿到的都是对象

  • 正向:当前表中,有那个字段,类似于:book.pulish author.author_detail
    • 通过字段
  • 反向:当前表中,没有那个字段 author_detail.author
    • 通过author_detail拿到author
    • 通过表名小写

一对多的正反向

  • 正向简单
python 复制代码
publish = book.pulish
  • 反向
python 复制代码
publish对象 ---》拿到当前publish对象下所有出版过的图书 -->反向查询
puhlish.book_set.all() # 如果是反向,多条,就要用表名小写_set.all()

多对多正反向

  • 正向: 拿到当前图书所有作者
python 复制代码
book.authors.all()  # 正向 --》对象.字段.all()
  • 反向 拿到当前作者写的所有图
python 复制代码
author.book_set.all() # 反向--》多条,就要用表名小写_set.all()

在Python脚本中调用Django环境

python 复制代码
import os

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_03.settings')
import django

django.setup()
from app01.models import Book, Author, AuthorDatail, Publish

if __name__ == '__main__':
python 复制代码
import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_05.settings')
import django
django.setup()
from app01.models import Book,Author,AuthorDatail,Publish
if __name__ == '__main__':
    # res = Book.objects.all().values("title",'price')  # select title,price---》qs中套字典 有key,有value
    # res = Book.objects.all().values_list("title",'price')  # select title,price---》qs中套元组,只有value
    # print(res)

    # 一对一正反向

    # 正向:
    author = Author.objects.all().first()
    print(author.author_detail.addr)

    # 反向:
    author_detail=AuthorDatail.objects.filter(pk=3).first()
    print(author_detail.author.name)


    # 一对多
    # 正向:
    book=Book.objects.all().first()
    print(book.publish.name)

    # 反向:
    publish=Publish.objects.filter(pk=2).first()
    print(publish.book_set.all())


    # 多对多
    # 正向:
    book=Book.objects.filter(pk=3).first()
    book=Book.objects.filter(pk=2).first()
    print(book.authors.all())

    # 反向:
    author=Author.objects.all().first()
    print(author.book_set.all())

八、基于链表的跨表查询

想把作者和作者详情链接

  • 正:author到 author_detail
  • 反:author_detail到author
python 复制代码
### 通过 __ 链表
###  一对一链表- 正反向
# 拿出id为1的作者(作者表)   的地址(作者详情表)
# 正向---》字段名 author_detail
res=Author.objects.filter(pk=1).values('id','name','age','author_detail__addr')
print(res)

# 反向---》查询 作者地址是 北京 的作者名和作者年龄
# 反向--》表名小写
res=AuthorDatail.objects.filter(addr='北京').values('addr','author__name','author__age')
print(res)
python 复制代码
### 一对多正反向
# 查询北京出版社出版过的所有书籍的名字与价格(一对多)
# 反向:表名小写
res = Publish.objects.filter(name='北京出版社').values('name','book__name','book__price')
print(res)
# 正向:按字段
res = Book.objects.filter(publish__name='北京出版社').values('publish__name','name','price')
print(res)


#####查询红楼梦这本书出版社的名字#####
### 多对多关系
# 练习: 查询lqz出过的所有书籍的名字(多对多)
# 反向
res=Author.objects.filter(name='lqz').values("name","book__name")
print(res)
# 正向
res=Book.objects.filter(authors__name='lqz').values('authors__name','name')
print(res)


# 查询北京出版社出版过的所有书籍的名字以及作者的姓名

res = Publish.objects.filter(name='北京出版社').values('book__name','book__authors__name','book__authors__author_detail__addr')
print(res)

res = Book.objects.filter(publish__name='北京出版社').values('name','authors__name')
print(res)

res = Author.objects.filter(book__publish__name='北京出版社').values('book__name','name')
print(res)
相关推荐
LUCIAZZZ15 分钟前
HikariCP数据库连接池原理解析
java·jvm·数据库·spring·springboot·线程池·连接池
我在北京coding31 分钟前
300道GaussDB(WMS)题目及答案。
数据库·gaussdb
小Tomkk44 分钟前
阿里云 RDS mysql 5.7 怎么 添加白名单 并链接数据库
数据库·mysql·阿里云
行云流水剑1 小时前
【学习记录】如何使用 Python 提取 PDF 文件中的内容
python·学习·pdf
心扬2 小时前
python生成器
开发语言·python
明月醉窗台2 小时前
qt使用笔记二:main.cpp详解
数据库·笔记·qt
mouseliu2 小时前
python之二:docker部署项目
前端·python
狂小虎2 小时前
亲测解决self.transform is not exist
python·深度学习
Python智慧行囊2 小时前
Python 中 Django 中间件:原理、方法与实战应用
python·中间件·架构·django·开发