Python3 Django的Model详解

Python3 Django的Model详解


本文由 Luzhuo 编写,转发请保留该信息.
原文: http://blog.csdn.net/Rozol/article/details/79526259


以下代码以Python3.6.1为例
Less is more!
Python 3.6.1
Django 1.8.2 (注: 由于2.0.2不支持mysql, 改用该版本)
MySQL 5.0.27
PyMySQL 0.8.0 (注: Django2推荐使用mysqlclient 1.3.7+, 该库要求python5.5-5.7 and Python2.7, 3.4+)(我装的是5.0的MySQL, 所以就没装推荐的)
项目名: Django_model 应用名: booktest

准备

  • 更换成mysql数据库, 首先需要准备好数据库
    • 安装数据库: 略
    • 进入数据库: mysql -uroot -p
    • 创建数据库: CREATE DATABASE test1 CHARSET=utf8;

更换数据库

  • 虚拟环境中安装数据库MySQL: pip install pymysql

    • Django_model[项目名]/Django_model/__init__py中书写:

        import pymysql
        pymysql.install_as_MySQLdb()
      
  • 修改settings.py文件

     DATABASES = {
         'default': {
             'ENGINE': 'django.db.backends.mysql',   # postgresql / mysql / sqlite3 / oracle
             'NAME': 'model',  # 数据库名
             'USER': 'root',
             'PASSWORD': 'root',
             'HOST': 'localhost',  # 本地:localhost
             'PORT': '3306',  # 默认端口:3306
         }
     }
    

Model使用流程

  • 创建应用python manage.py startapp [应用名]
  • settings.py中的 INSTALLED_APPS = [] 添加应用
  • models.py定义模型类
  • 生成迁移python manage.py makemigrations
  • 执行迁移python manage.py migrate
  • 使用模型

字段

from django.db import models

'''
A. 属性的类型决定了:
    1. 数据库中字段的类型
    2. 管理表单时使用的html控件
    3. 管理中的数据验证
B. Django会自动生成自增长id
'''
'''
字段类型:
    AutoField: 无需指定, 自增长id
    BooleanField: Boolean类型, 默认Flase; 表单控件: CheckboxInput
        NullBooleanField; Boolean类型, 支持None, True, False
    CharField(max_length=字符长度20): 字符串; 表单控件: TextInput
        TextField: 大文本; 表单控件: Textarea
    IntegerField:整数
    FloatField: 浮点数
        DecimalField(max_digits=位数总数None, decimal_places=小数点后的数字位数None): Decimal的十进制浮点数
    DateTimeField([auto_now=修改时间戳False, auto_now_add=创建时间戳False]): datetime.datetime实例的日期和时间; 表单控件: TextInput + 日历控件
        DateField: datetime.date实例的日期
        TimeField: datetime.time实例的时间
    FileField: 上传文件(非路径)
        ImageField:上传image
'''
'''
字段选项:
    null: True:允许None; 默认:False
    blank: True:允许空白; 默认:False
    db_column: 字段名; 默认:属性名
    db_index: True:创建索引; 默认:False
    default: 默认值
    primary_key: True:主键
    unique: True:值唯一
'''
'''
关系:
    ForeignKey: 一对多, 将该属性定义到多的那一端
    OneToOneField: 一对一, 将该属性定义到任一端
    ManyToManyField: 多对多, 将该属性定义到两端
    递归关联(自连接/自关联): 一对多, 用一张表存储所有信息

访问:
    BookshelfInfo
    BookInfo
        bookshelf = models.ForeignKey(Bookshelf)
        
    用一访问多:
        对象.模型类_set
        bookshelf.bookinfo_set
    用一访问一:
        对象.模型类
        book.bookshelfinfo
    访问id:
        对象.属性_id
        book.bookshelf_id

    使用例子:
        bookshelf = Bookshelf.objects.get(pk=1)  # 查询指定书架
        bookshelf.bookinfo_set.all()  # 获取该书架所有的书信息
'''


class Bookshelf(models.Model):
    shelf_type = models.CharField(max_length=10, db_column='shelfType')
    shelf_id = models.IntegerField(db_column='shelfId')

    def __str__(self):
        return self.shelf_type


class BookInfo(models.Model):
    book_name = models.CharField(max_length=20, db_column='bookName')
    book_time = models.DateTimeField(db_column='bookTime')
    book_type = models.ForeignKey(Bookshelf, db_column='bookType', on_delete=models.CASCADE)
    is_delete = models.BooleanField(db_column='isDelete')

    # 元选项
    class Meta:
        db_table = 'bookinfo'  # 表名; 默认: 应用名_表名
        ordering = ['id']  # 排序(正序), 倒序:'-id', 随机:'?id'

    def __str__(self):
        return self.book_name


# 嵌套关联(自连接/自关联): 一张表存储所有地区(省市区)信息
class AreaInfo(models.Model):
    area_title = models.CharField(max_length=20)
    area_parent = models.ForeignKey('self', null=True, blank=True, on_delete=models.CASCADE)

   def __str__(self):
       return self.area_title
   '''
   数据样式:
       id=1, title='浙江省', parent=null
       id=2, title='杭州市', parent=1
       id=3, title='上城区', parent=2
   使用:
        from booktest.models import AreaInfo
        area = AreaInfo.objects.get(pk=220100)  # 220100, 长春市, 220000(连云港市)
        area.area_parent  # 上级对象:  (220000, 吉林省, null)
        area.areainfo_set.all()  # 下级对象: [, (220102, 南关区, 220100),  ...]
   '''

: 报 django.db.utils.NotSupportedError: Renaming the 'AppRecorder_categoryshelf' table while in a transaction is not supported on SQLite because it would break referential integrity. Try adding 'atomic = False' to the Migration class 异常, 说明 SQLite 数据库不支持表名重命名的操作.

管理器Manager

  • 管理器是模型类的属性, 用于对象与数据表之间的映射关系, 是我们用Django与数据库之间操作的接口, 一个模型可以有多个管理器(至少一个)

  • 支持指定管理器(在模型中指定)

     class BookInfo(models.Model):
         # ...
     
         # 指定管理器, 默认:objects
         books = models.Manager()
    
  • 自定义管理器(用于做一些额外的操作)(在模型中指定)

    class BookInfoManager(models.Manager):
    
        # 在创建时修改
        def create(self, bookname):
            b = BookInfo()
            b.book_name = bookname
            b.book_time = datetime.today()
            b.book_type = Bookshelf.objects.get(pk=1)
            b.is_delete = False
            return b
    
        # 修改查询结果
        def get_queryset(self):
            return super().get_queryset().filter(is_delete=False)
    
    class BookInfo(models.Model):
    	# ...
    	
    	# 一个模型可以使用多个管理器
        # 指定管理器, 默认:objects
        # 方式一: 使用指定管理器(同时多个自定义管理器也是可以的)
        books = models.Manager()
        # 方式二: 使用自定义管理器
        books1 = BookInfoManager()
    
  • 测试:python manage.py shell

     from booktest.models import BookInfo
     # 使用默认管理器(指定管理器之后, 默认管理器就不存在)
     # Bookshelf.objects.all()
     # 使用指定管理器
     BookInfo.books.all()
     # 使用自定义管理器
     BookInfo.books1.all()
     BookInfo.books1.create('456').save()
    

查询集

# --- 查询集 ---
'''
惰性执行: 创建查询集, 不会访问数据库, 调用数据时才会访问
查询集缓存: 查询过的结果集会进行缓存(不访问数据库), 所以查询集可重用(这点不同于Java)
    --- 全部缓存 ---
    例子: list = BookInfo.books1.all()  # 不访问数据库
          print([book.book_name for book in list])  # 访问数据库, 并缓存
          print([book.book_name for book in list])  # 访问查询集缓存
    --- 部分缓存 ---
    例子: list = BookInfo.books1.all()  # 不访问数据库
          print([book.book_name for book in list[0:2]])  # 访问数据库, 并缓存
          print([book.book_name for book in list[1:3]])  # 访问查询集缓存, 不在缓存去访问数据库, 不在缓存的那部分数据不缓存

      
过滤器:(支持链式调用)
    --- 多个值 ---
    all(): 查询所有
    filter(is_delete=True): 通过满足
    exclude(is_delete=True): 通过不满足
    order_by(): 排序
    values(): [{对象}, {对象}]
    使用例子: BookInfo.books1.all()
    --- 单个值 ---
    get(pk=1): 单个满足条件的数据, 没找到DoesNotExist异常, 找到多个MultipleObjectsReturned异常
    count(): 总条数
    first():第一条数据
    last(): 最后一条数据
    exists(): 是否有数据, True:有
    --- 下标限制(不支持-) ---
    [0] / [1:3]
    使用例子: BookInfo.books1.all()[1:3]


字段查询:
    语法: 属性名__比较运算符=值(无需转义)
    外键: 属性名_id
    --- 比较运算符 ---
    exact: ==, 区分大小写(不区分iexact)
    contains: 是否包含, 区分大小写(不区分icontains)
    startswith / endswith: 开头/结尾, 区分大小写(不区分istarswith / iendswith)
    isnull / isnotnull: 是否为null
    gt / gte / lt / lte: > / >= / < / <=
    例子:  BookInfo.books.filter(book_type_id__exact=1)

    in: 是否在该[]范围内
        例子: filter(pk__in=[1, 2, 3, 4, 5])
    year / month / day / week_day / hour / minute / second / gt: 年 / 月 / 日 / 周 / 时 / 分 / 秒 / 
        例子: BookInfo.books.filter(book_time__year=1980)
        例子: BookInfo.books.filter(book_time__gt=date(1980, 12, 31))  # >(1980,12,31), (date是datetime里的函数)
    pk: 主键(primary key)
        例子: BookInfo.books.filter(pk__lte=2)

    --- 关联查询 ---
    # 语法: 模型名__属性名__比较运算符
    Bookshelf.objects.filter(bookinfo__book_name__in=[123, 456, 789])  # 查询书架上有"书名包含123,456,789"的所有书架
    
    --- 聚合函数 ---
    函数: Avg / Count / Max / Min / Sum
    例子:
        from django.db.models import Max
        max_date = BookInfo.books.all().aggregate(Max('book_time'))  # aggregate(Max(xxx))


F对象(用于字段与字段的比较)
    语法:
        字段名1__比较运算符=F('字段名2')
        字段名=F('关联模型名__关联字段名')

    例子:
        from django.db.models import F
        BookInfo.books.filter(id__exact=F('book_type_id'))  # 对比同表字段
        Bookshelf.objects.filter(id=F('bookinfo__id'))  # 对比关联表字段
        BookInfo.books.filter(book_time__lt=F('book_time') + timedelta(days=1))  # 直接运算


Q对象(or查询)
    语法:
        Q(字段__比较运算符=值)
        取反: ~Q(字段__比较运算符=值)

    与逻辑运算符一起使用: &(and) / |(or)
    语法: Q(字段1__比较运算符1=值1) 逻辑运算符 Q(字段2__比较运算符2=值2)
    
    例子:
        from django.db.models import Q
            list.filter(Q(pk__exact=1))  # id==1
            list.filter(~Q(pk__exact=2))  # id=/=1
            list.filter(Q(pk__exact=1) | Q(pk__exact=2))  # id=1or2
'''

事务

from django.db import transaction
from django.shortcuts import redirect

# 事务
@transaction.atomic()
def order_handle(request):
    # 事务回滚点, 操作失败可回到此点
    tran_id = transaction.savepoint()
    try:
        # ...

        # 提交事务
        transaction.savepoint_commit(tran_id)
    except Exception as e:
        print(e)
        # 回滚事务
        transaction.savepoint_rollback(tran_id)
    return redirect('xxx')

其他

省市区数据部分数据

create table booktest_areainfo(
id int primary key,
area_title varchar(20),
area_parent_id int,
foreign key(area_parent_id) references booktest_areainfo(id)
);


insert into booktest_areainfo values('110000','北京市', null);  
insert into booktest_areainfo values('120000','天津市', null);  
insert into booktest_areainfo values('110100','市辖区','110000');  
insert into booktest_areainfo values('110200','县','110000');  
insert into booktest_areainfo values('120100','市辖区','120000');  

你可能感兴趣的:(Python)