博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Django 框架之 Models
阅读量:5885 次
发布时间:2019-06-19

本文共 14244 字,大约阅读时间需要 47 分钟。

1. 数据库配置

  • Django默认支持sqlite, mysql, oracle, postgresql 数据库:
    • Django默认使用sqlite数据库,引擎名称:django.db.backends.sqlite3
    • MySQL 引擎名称:django.db.backends.mysql
  • MySQL 驱动程序:
    • MySQLdb(mysql python)
    • mysqlclient
    • MySQL
    • PyMySQL(纯python的mysql驱动程序)
# 示例: 更改数据库# settings.pyDATABASES = {    'default': {        'ENGINE': 'django.db.backends.mysql',        'NAME': 'books',    # 数据库名称        'USER': 'root',     # 数据库用户名        'PASSWORD': 'root', # 数据库密码        'HOST': '',         # 数据库主机,留空默认为localhost        'PORT': '3306',     # 数据库端口    }}# 注意:#   启动项目时,会报错: no module named MySQLdb#   这是因为django默认导入的驱动是 MySQLdb,可是MySQLdb对于py3有很大问题,所以我们需要的驱动是#   PyMySQL#解决方法:#   __init__.py 中加入以下代码:#   import pymysql#   pymysql.install_as_MySQLdb()

2. ORM(对象关系映射)

  • 表的创建:
    • 作者模型: 一个作者有姓名;
    • 作者详细模型: 把作者的详情放到详情表,包含性别, email地址和出生日期。作者详情模型和作者模型之间
      是一对一的关系(one-to-noe),在大多数情况下,我们没有必要将他们拆分成两张表,这里只是引出一对一的概念。
    • 出版商模型: 出版商有名称,地址,所在城市,省,国家和网站;
    • 书籍模型: 书籍有书名和出版日期,一本书可能会有多个作者,一个作者也可以写多本书,所以作者和数据的关系
      就是多对多的关联关系(many-to-many),一本书只应该由一个出版商出版,所以出版商和书籍是一对多关联关系
      (one-to-many),也被称作外键。
# 实体类# 项目名(orm)/app01/models.pyfrom django.db import modelsclass Publisher(models.Model):    name = models.CharField(max_length=30, verbose_name='名称')    address = models.CharField('地址', max_length=50)    city = models.CharField('城市', max_length=60)    state_province = models.CharField(max_length=30)    country = models.CharField(max_length=50)    website = models.URLField()    class Meta:        verbose_name = '出版商'        verbose_name_plural = verbose_name    def __str__(self):        return self.nameclass Author(models.Model):    name = models.CharField(max_length=30)    def __str__(self):        return self.nameclass AuthroDetail(models.Model):    sex = models.BooleanField(max_length=1, choices=((0, '男'), (1, '女'),))    email = models.EmailField()    address = models.CharField(max_length=50)    birthday = models.DateField()    author = models.OneToOneField(Author, on_delete=models.CASCADE)class Book(models.Model):    title = models.CharField(max_length=100)    authors = models.ManyToManyField(Author)    publisher = models.ForeignKey(Publisher, null=True, on_delete=models.SET_NULL)    publication_date = models.DateField()    price = models.DecimalField(max_digits=5, decimal_places=2, default=10)    def __str__(self):        return self.title# 创建表# iTerm 中进入 项目名(orm) 下python3 manage.py makemigrationspython3 manage.py migrate# 备注:# 1. on_delete 属性说明#       CASCADE: 级联删除#       PROTECT: 保护模式,如果采用该选项,删除的时候,会抛出 ProtectedError 错误;#       SET_NULL: 置空模式,删除的时候, 外键自动被设置为空, 前提就是 blank=True, null=True;#       SET_DEFAULT: 删除的时候,外键自动设置为默认值。定义外键的时候,需要加上一个默认值;#       SET(): 自定义一个值,该值当然只能是对应的实体;# 2. 每个数据模型都是 django.db.models.Model 的子类, 它的父类Model包含了所有必要的和数据库交互的方法,#   并提供了一个简洁漂亮的定义数据库字段的语法;

2.1 模型常用的字段类型参数

# CharField    # 字符串字段,用于较短的字符串    # CharField 要求必须有一个参数 maxlength, 用于从数据库层和Django校验层限制该字段所允许的最大字符数# InterField: 用于保存一个整数# FloatField: 一个浮点数, 必须提供两个参数:    # max_digits: 总位数(不包括小数点和符号)    # decimal_places: 小数点位数    # 例如,要保存最大值为 999(小数点后保存2位)    #   models.FloatField(..., max_digits=5, decimal_palces=2)# AutoField    # 一个 IntegerField, 添加记录时,会自动增长,通常不需要直接使用这个字段    # 自定义一个主键: my_id=models.AutoField(primary_key=True)    # 如果不指定主键的话,系统会自动添加一个主键字段到你的 model# BooleanField    # admin 用 checkbox 来表示此类字段# TextField    # 一个容量很大的文本字段    # admin 用一个 

2.2 Field 重要参数

null: 数据库中字段是否可以是空blank: django 的 Admin 中添加数据时,是否允许空值default: 设定缺省值editable: 如果为假, admin 模式下将不能改写, 缺省为真;primary_key: 设置主键, 如果没有设置,Django 创建表时,会自动加上;unique: 数据唯一;verbose_name: Admin 中字段的显示名称;validator_list: 有效性检查, 非有效产生 django.core.validators.ValidationError 错误db_column, db_index: 如果为真,将为此字段创建索引choices: 一个用来选择值的二维数组,第一个值是实际存储的值, 第二个用来备选;

3. 表的操作

3.1 增(create, save)

from app01.models import *    # create 方式一: Author.objects.create(name='Jame')    # create 方式二: Author.objects.create(**{'name':'Jame'})    # 以字典的方式插入,前面需要添加两个星号    # save 方式一:        author = Author(name='Jame')        author.save()    # save 方式二:        author=Author()        author.name='Jame'        author.save()# 如何处理外键关系的字段,如一对多的publisher和多对多的authors# 一对多(ForeignKey):    # 方式一: 由于绑定一对多的字段,例如publisher,存到数据库中的字段为 publisher_id,    # 所以我们可以直接给这个字段设定对应值:    Book.objects.create(title='Python 入门',                        publisher_id=2,                        publication_date='2015-4-18',                        price=98)    # 方式二:    #      首先,获取绑定的 Publisher对象    pub_obj = Publisher(name='河北教育出版社',address='保定',city='保定',              state_province='河北',country='China',website='http://www.edu.com')    或    pub_obj=Publisher.objects.get(id=1)    # 将 publisher_id=2 改为 publisher=pub_obj# 多对多(ManyToManyField):    author1 = models.Author.objects.get(id=1)    author2 = models.Author.objects.filter(name='zhangsan')[0]    book = models.Book.objects.get(id=1)    book.author.add(author1, author2)       # book.author 表示book绑定的 author 对象集合    # 等同于    ----------- 正向查询(从拥有外键的表开始查找)    book.author.add(*[author1, author2])    book.author.remove(*[author1, author2])    ----------- 反向查询    book=models.Book.objects.filter(id__gt=1)       # id__gt 表示 id大于    authors=models.Author.objects.filter(id=1)[0]    authors.book_set.add(*book)         # Author 类里面没有与 book 相关的属性    authors.book_set.remove(*book)# 注意: 如果第三张表是通过 models.ManyToManyField() 自动创建的, 那么绑定关系只有上面一种方式#      如果第三张表是自己创建的:    class Book2Author(models.Model):        author = models.ForeignKey("Author")        book = models.ForeignKey("Book")        # 绑定联合唯一索引        class Meta:            unique_together=["author", "book"]    # 保存数据    s = models.Book2Author.objects.create(author_id = 1, Book_id = 2)    s.save()

3.2 删除(delete)

# 单表:Book.objects.filter(id=1).delete()# 备注: 表面上删除了一条信息,实际却删除了三条,因为我们删除的这本书在 Book_authors 表中有两条#  相关信息,这种删除方式就是 django 默认的级联删除。# 多对多关系: remove() 和 clear() 方法# 正向book = models.Book.objects.filter(id=1)# 删除第三张表中和id=1关联的所有关联信息book.author.clear()     # 清除与book中 id=1 关联的所有数据book.author.remove(*[1, 2, 3, 4])# 反向author = models.Author.objects.filter(id=1)author.book_set.clear()     # 清除与book中 id=1 关联的所有数据

3.3 修改(update 和 save)

# 单表:# 方式一: update 方法直接设定对应属性    Book.objects.filter(id=2).update(title='Python')    # 不能用 get(id=2)    # SQL    #   UPDATE 'app01_book' SET 'title' = 'Python' WHERE 'app01_book'.'id'=2; args=('Python', 2)    # 不能用get的原因是: update 是 QuerySet对象的方法, get返回的是一个model对象,它没有 update 方法,    # 而 filter 返回的是一个 QuerySet 对象;# 方式二: save 方法会将所有属性重新设定一遍, 效率低    obj=models.Book.objects.filter(id=2)[0]    obj.title='Python'    obj.save()# SQL:# SELECT 'app01_book'.'id','app01_book'.'title','app01_book'.'price','app01_book'.'color',# 'app01_book'.'page_num','app01_book'.'publisher_id' FROM 'app01_book'# WHERE 'app01_book'.'id'=3 LIMIT 1;# UPDATE 'app01_book' SET 'title'='Python','price'=22,'color'='red','page_num'=223,# 'publisher_id'=1 WHERE 'app01_book'.'id'=3;

3.3.1 控制台输出SQL语句

# setting 加上日志记录部分LOGGING = {    'version': 1,    'disable_existing_loggers': False,    'handlers': {        'console':{            'level': 'DEBUG',            'class': 'logging.StreamHandler',        },    },    'loggers': {        'django.db.backends': {            'handlers': ['console'],            'propagate': True,            'level': 'DEBUG',        },    }}

3.4 查询(filter, valued等)

  1. 查询相关API:
    • filter(**kwargs): 包含了与所给筛选条件相匹配的对象;
    • all(): 查询所有结果;
    • get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的
      对象超过一个或者没有都会抛出错误。
  2. 对查询的结果进行再处理(例如,objects.filter.values())
    • values(*field): 返回一个ValueQuerySet,一个特殊的QuerySet,运行后得到的并不是一系列
      model的实例化对象,而是一个可迭代的字典序列;
    • exclude(**kwargs): 包含了与所给筛选条件不匹配的对象;
    • order_by(*field): 对查询结果排序;
    • reverse(): 对查询结果反向排序;
    • distinct(): 从返回结果中剔除重复记录;
    • values_list(*field): 返回一个元组序列;
    • count(): 返回数据库中匹配查询(QuerySet)的对象数量;
    • first(): 返回第一条记录;
    • last(): 返回最后一条记录;
    • exists(): 如果QuerySet包含数据,就返回 True, 否则返回 False。
# 补充:# 扩展查询,有时候Django的查询API不能方便的设置查询条件,提供了另外的扩展查询方法extra:# extra(select=None, where=None, params=None, tables=None, order_by=None, select_params=None)1) q = Entry.objects.extra(select={'is_recent': "pub_date > '2006-12-29'"})   q = q.extra(order_by=['-is_recent'])     # 负号表示逆序2) Blog.objects.extra(    select = SortedDict([('a', '%s'), ('b', '%s')]),    select_params=('one', 'two'))3) Entry.objects.extra(where=['headline=%s'], params=['Lennon'])

3.4.1 QuerySet

  1. 惰性机制: Publisher.objects.all()或者.filter()等都只是返回一个QuerySet(查询结果集对象),
    它并不会马上执行SQL, 而是当调用QuerySet的时候才执行。
  2. QuerySet的特点:
    • 可迭代的
    • 可切片
# 示例:objs = models.Book.objects.all()    #[obj1, obj2, obj3...]# 可迭代    for obj in objs:        # 每一个obj,就是一个行对象        print('obj:',obj)# 可切片    print(objs[1])    print(objs[1:4])    print(objs[::-1])# QuerySet 是具有cache的    # 当遍历QuerySet时,所有匹配的记录会从数据库获取,然后转换成Django的model,这被称为执行(evaluation)    # 这些model会保存在QuerySet内置的cache中,如果再次遍历这个QuerySet,不需要再去数据库查询    objs=models.Book.Objects.filter(id=3)    for i in objs:        prin(i)    # SQL 语句只运行一次    for i in objs:        print(i)# 当QuerySet非常巨大时,cache会成为问题    # 处理成千上万的记录时,将它们一次装入内存是很浪费的。更糟糕的是,巨大的QuerySet可能会锁住系统    # 进程,让你的程序濒临崩溃。要避免在遍历数据的同时产生QuerySet cache, 可以使用 iterator()    # 方法来获取数据,处理完数据就将其丢弃    objs=Book.objects.all().iterator()      # 迭代器对象    for obj in objs:        print(obj.name)    # 当然,使用iterator()方法来防止生成cache, 意味着遍历同一个QuerySet时,会重复执行查询。所以使用    # iterator()的时候要当心,确保代码在操作一个大的QuerySet时,没有重复执行查询。

3.4.2 单表条件查询 多表条件关联查询

# 示例:了不起的双下划线(__)之单表条件查询models.Tb1.objects.filter(id__lt=10, id__gt=1)      # 获取id大于1, 且小于10的值models.Tb1.objects.filter(id__in=[11, 22, 33])      # 获取id等于11, 22, 33的数据models.Tb1.objects.exclude(id__in=[11, 22, 33])     # not inmodels.Tb1.objects.filter(name__contains="ven")models.Tb1.objects.filter(name__icontains="ven")    # icontains 表示大小写不敏感models.Tb1.objects.filter(id__range=[1, 2])         # 范围 between andstartswith, istartswith,  endswith,  iendswith# 示例: 多表条件关联查询# 正向条件查询models.Book.objects.filter(title="Python").values("id")# 一对多models.Book.objects.filter(title="Python").values("publisher__city")# 多对多models.Book.objects.filter(title="Python").values("author__name")models.Book.objects.filter(author__name="zhangsan").values("title")

3.4.3 聚合查询和分组查询

# aggregate(*args, **kwargs):from django.db.models import Avg, Min, Sum, Max# 查询图书价格的平均值Book.objects.all().aggregate(Avg('price'))      # {'price__avg': 20}# 查询图书价格的最大值,最小值Book.objects.all().aggregate(Avg('price'), Max('price'), Min('price'))# 输出: {'price__avg': 20, 'price__max':Decimal('81.20'), 'price__min': Decimal('12.99')}# aggregate() 是 QuerySet 的一个终止子句,意思是说, 它返回一个包含一些键值对的字典。键的名称是聚合值# 的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。如果你想要为聚合值指定# 一个名称,可以向聚合子句提供Book.objects.all().aggregate(average_price=Avg('price'))# annotate(*args, **kwargs)    分组查询# 查询各个作者出的书的总价格,这里就涉及到分组了, 分组条件是 authors__nameBook.objects.values("authors__name").annotte(Sum("price"))# 查询各个出版社最便宜的书价是多少Book.objects.values("publisher__name").annotate(Min("price"))

3.4.4 F 查询和 Q 查询

# 示例一: F 查询# F 使用查询条件的值,专门取对象中某列值的操作, 例如,将书的价格增加 10from django.db.models import Fmodels.Book.objects.update(price=F('price')+10)# 示例二: Q 构建搜索条件from django.db.models import Q# Q 对象可以对关键字参数进行封装,从而更好地应用多个查询models.Book.objects.filter(Q(title__startswith='P')).all()# 可以组合使用 &, | 操作符,当一个操作符用于两个Q的对象,它产生一个新的Q对象Q(title__startswith='P') | Q(title__startswith='J')# Q 对象可以用 ~ 操作符放在前面表示否定, 也可允许否定与肯定形式的组合Q(title__startswith='P') | ~Q(pub_update__year=2005)models.Book.objects.get(    Q(title__startswith='P'),    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 10, 1)))# Q对象可以与关键字参数查询一起使用,不过,一定要把Q对象放在关键字参数查询的前面:# 正确:models.Book.objects.get(    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 10, 1)),    title__startswith='P')# 错误:models.Book.objects.get(    title__startswith='P',    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 10, 1)))

4. admin 的配置

  • admin 是 Django 强大功能之一,它能从数据库中读取数据,呈现在页面上,进行管理。
  • 注册model类到admin的两种方式:
    • 使用register方法:admin.site.register(Book, MyAdmin)
    • 使用register的装饰器:@admin.register(Book)
# 示例:# 一些常用的设置:        # list_display: 指定要显示的字段        # search_fields: 指定搜索的字段        # list_filter: 指定列表过滤器        # ordering: 指定排序字段from django.contrib import adminfrom app01.models import *# 注册modelclass MyAdmin(admin.ModelAdmin):    list_display = ("title", "price", "publisher")    search_fields = ("title", "publisher")    list_filter = ("publisher",)    ordering = ("price",)    fieldsets = [        (None,                {'fields': ['title']}),        ('price information', {'fields': ['price', 'publisher'], 'classes': ['collapse']}),    ]admin.site.register(Book, Admin)admin.site.register(Publish)admin.site.register(Author)

参考资料:

转载于:https://www.cnblogs.com/linkworld/p/8689900.html

你可能感兴趣的文章
Canvas -- 网页特效学习小记
查看>>
PHP错误和异常
查看>>
Python3之enumrate和range对比及示例
查看>>
iOS轻量折线图库
查看>>
ES6 (...)扩展运算符
查看>>
【c】内存空间分配
查看>>
用好这一个写作神器,批量生产爆文不是梦
查看>>
掘金-Markdown 编辑器简介
查看>>
几行命令了解一下远程服务器创建用户并无密登录
查看>>
玩转大数据系列之二:数据分析与处理
查看>>
jQuery里的正则表达式
查看>>
JAVA整理(一)面向对象基础
查看>>
Scrapy爬取内容保存Json文件(unicode转中文)
查看>>
Storm系列(五)DRPC实现远程调用
查看>>
作为菜鸟怎样快速的的学习微信小程序
查看>>
一次诡异的mysql乱码
查看>>
springmvc mybatis shiro构建cms系统
查看>>
MySQL8.0 新特性 top10
查看>>
大数据架构师必读:常见的七种Hadoop和Spark项目案例
查看>>
程序员笔记|如何编写优雅的Dockerfile
查看>>