 ORM字段
ORM字段
  # Django中开启事务
事务的四大特性 ACID
1> 在with代码块中写的所有SQL语句都属于同一个事务;
2> 经验之谈: 在事务中,尽量只写sql语句,业务逻辑代码写在事务外面!!否则数据量一大,逻辑一复杂,会出错!!
from django.db import transaction
try:
    with transaction.atomic():
        pass
        # -- sql1
        # -- sql2
except Exception as e:
    print(e)
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# ORM常用类型及参数
# 常用字段类型
■ AutoFiled(primary_key=True)  # -- 自增+主键
   int自增列,必须填入参数primary_key=True
   当model中如果没有自增列,则自动会创建一个列名为id的列.
    
■ CharFiled(max_length=32)
   字符类型,必须提供max_length参数,max_length表示字符长度.
   Django中的CharField对应的MySQL数据库中的varchar类型,没有设置对应char类型的字段
   但是Django允许我们自定义新的字段,我们可以自定义对应于数据库的char类型,暂略.
   ★ Ps: 一般来说,虽然CharFiled对应的是varchar,但超过了255个字符我们就会使用TextField()
         这都是经验之谈,具体为什么.可翻看官方文档.
         https://docs.djangoproject.com/zh-hans/4.1/ref/databases/#mysql-notes
  
■ TextField()
   可表示65535个字符. 若需要的比这个还多,就需要放到文件中去,写入文件的路径.
  
■ IntegerField()
   一个整数类型,范围在-2147483648 to 2147483647.
   一般不用它来存手机号(位数也不够),手机号会直接用字符串存.
    
■ DateField(auto_now=True,auto_now_add=True)  - 年月日 
   日期字段,日期格式YYYY-MM-DD,相当于Python中的datetime.date()实例
   Django的ORM中默认这两个属性都为False
   若auto_now=True: 修改记录的时间.. 
                   "若用户表里有DateField的字段,并且auto_now=True,那么该字段可以不传值.会自动传当前时间."
   若auto_now_add=True: 第一次入库的时间
    
■ DateTimeField(auto_now=True,auto_now_add=True)  - 年月日时分秒
   日期时间字段,格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ],相当于Python中的datetime.datetime()实例
    
■ BooleanField()  
   True/False,其实数据库是不支持真假的,实际在表中存的是0和1
■ EmailField()  
■ DecimalField(max_digits=8, decimal_places=2)  # 跟金额相关会用到它,金额会有小数
   存储精确的小数!!!max_digits总共长度,decimal_places小数点后保留两位. 此处是整数部分6位,小数部分2位.
■ ForeignKey()
   to: 要关联的表
   to_field: 指定关联的表的字段
   on_delete:
      Django1.x里默认 on_delete=models.CASCADE 级联更新级联删除;在Django2.x里必须指定该参数.
      可设置 on_delete=models.SET_NULL,有个前提,该外键需要设置允许为空.
      ... ...
   注意!ForeignKey可以和其他表做关联关系同时也可以和自身做关联关系.
   Ps:外键字段、外键数据
    
■ OneToOneField()
■ ManyToManyField()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# 常见字段参数
下面的是常见的字段类型都可以有的字段参数
■ blank、null
   在mysql里,默认可以为空,在Django的ORM里默认不为空 
   Django中,默认blank=False、null=False
     - null是针对数据库而言,如果null=True,表示数据库的该字段可以为空
         那么在新建一个model对象的时候是不会报错的;
     - blank是针对表单的,如果 blank=True,表示你的表单填写该字段的时候可以不填
         比如admin后台界面下增加 model 一条记录的时候. <即用户在页面操作时,该字段值可以为空.>
    
■ unique
   如果设置为unique=True 则该字段在此表中必须是唯一的
  
■ db_index
   如果db_index=True 则代表着为此字段设置索引
■ default
   为该字段设置默认值
  
■ verbose_name
   对该字段的解释,在后台管理系统里使用的.
  
■ choices
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# choices参数
针对可能列举完的数据都适用于choices参数!!
app01.models.py
from django.db import models
class User(models.Model):
    gender_choice = (
        (1, '男'),
        (2, '女'),
        (3, '未知'),
    ) 
    # -- ★★★字段类型根据(1, '男')里第一个元素来决定,这里第一个元素1是int类型!!!
    #    数据表中存的是整型数据.So,是IntegerField. 这里不传默认是3.
    gender = models.IntegerField(choices=gender_choice, default=3)
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11

app01.tests.py
from django.test import TestCase
import os
import sys
if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day56.settings")
    import django
    django.setup()
    from app01 import models
    # models.User.objects.create(gender=1)
    # models.User.objects.create(gender=2)
    # models.User.objects.create(gender=3)
    # models.User.objects.create(gender=4)
    for i in range(1, 5):
        res = models.User.objects.filter(pk=i).first()
        # -- 在获取值的时候,固定句式: get_字段名_display() 
        #    1> 存的值不在choice范围内,原样返回
        #    2> 存的值在choice范围中,返回元祖中对应的值!
        print(res.gender, res.get_gender_display())
    """
    1 男
    2 女
    3 未知
    4 4   # -- 没有对应的就取数据表中的!
    """
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 多对多的三种创建方式
基本不用全自动, 纯手动用sql查控制强!! 半自动方便..看个人喜好啦.
| 第三张表创建 | 正反向概念 | add、set等方法 | 扩展性 | |
|---|---|---|---|---|
| 全自动 | 自动 | yes | yes | 差 | 
| 纯手动 | 手动 | no | no | 优 | 
| 半自动 | 手动 | yes | no | 优 | 
第一种: 全自动
 特点
1> Django会自动创建第三张表!
2> 可以利用正反向查询概念. 还可以利用add、set、remove、clear等方法.
3> 只会创建两个表的关系字段, 不会再额外添加字段, 可扩展性差.
class Book(models.Model):
    title = models.CharField(max_length=32)
    authors = models.ManyToManyField(to="Author")
class Author(models.Model):
    name = models.CharField(max_length=32)
1
2
3
4
5
6
7
2
3
4
5
6
7
第二种: 纯手动
 特点:
1> 手动建表
2> 正反向的概念不能用. add、set、remove、clear等方法也不能用!
3> 第三张表可以根据自己的要求随意添加额外的字段.
class Book(models.Model):
    title = models.CharField(max_length=32)
    
class Author(models.Model):
    name = models.CharField(max_length=32)
class Book2Author(models.Model):
    """id  book_id  author_id"""
    # -- 提醒,给外键字段取名后面不用加 _id
    book = models.ForeignKey(to='Book', on_delete=models.CASCADE)
    author = models.ForeignKey(to='Author', on_delete=models.CASCADE)
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
第三种: 半自动
 特点:
1> 手动建表, 但要告诉orm第三张表是自己建的
2> 可以利用正反向的概念. 但add、set、remove、clear等方法不能用!
3> 第三张表可以根据自己的要求随意添加额外的字段.
 在项目后续迭代更新中, 若有需求, 可向关系表中增加字段, 给自己留条后路..
     但要告诉orm哪两个字段关联啦!
 注意: through_fields中字段的顺序!!
class Book(models.Model):
    title = models.CharField(max_length=32)
    # -- authors是虚拟字段
    # -- through参数:指定第三张表的表名!
    #    through_fields参数:指定哪两个字段关联!
    book = models.ManyToManyField(
        to="Author",
        through='Book2Author',
        # -- ★ 在Book类里, 'book'在前,'author'在后
        through_fields=('book', 'author')
    )
class Author(models.Model):
    name = models.CharField(max_length=32)
    # -- 当然多对多的关系也可以在Author表中设置外键!!
    # authors = models.ManyToManyField(
    #     to="Book",
    #     through='Book2Author',
    #     # -- ★ 在Author类里, 'author'在前,'book'在后
    #     through_fields=('author','book')
    # )
class Book2Author(models.Model):
    book = models.ForeignKey(to='Book')
    author = models.ForeignKey(to='Author')
    create_time = models.DateField()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
