Django Model 进阶

回顾:

  • 定义 models
  • settings.py激活app才能使用models
  • migrations:版本控制,当更改库表结构时可以处理数据
  • 增删改查
  • 常见Field

模型的价值在于定义数据模型,使用Python的形式操作数据库

from django.db import models

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)

转换为sql

CREATE TABLE IF NOT EXISTS myapp_person(
    id INT(11) NOT NULL AUTO_INCREMENT,
    first_name VARCHAR(30) DEFAULT NULL,
    last_name VARCHAR(30) DEFAULT NULL,
    PRIMARY KEY (id)
) ENGINE=InnoDB;

关系:

  • 一对多 ForeignKey,如厂商和汽车关系
  • 多对多 ManyToManyField,如用户和组关系
  • 一对一 OneToOneField,如饭店和地址关系
# 多对一关系
class Manufacturer(models.Model):
    pass
class Car(models.Model):
    manufacturer = models.ForeignKey(‘Manufacturer‘)

# 多对多关系
class Group(models.Model):
    pass
class User(models.Model):
    groups = models.ManyToManyField(‘Group‘)

# 一对一关系
class Place(models.Model):
    name = models.CharField(max_length=50)
    address = models.CharField(max_length=80)
class Restaurant(models.Model):
    place = models.OneToOneField(‘Place‘, primary_key=True)
    serves_hot_dogs = models.BooleanField(default=False)
    serves_pizza = models.BooleanField(default=False)

重写save()方法:

如保存记录之前,写入日志操作,注意一定要记得调用超类的save()方法,否则不会保存到数据库

class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()

    def save(self, *args, **kwargs):
        print(‘do something‘)
        super(Blog, self).save(*args, **kwargs)
        print(‘do something else‘)

模型继承:

  • 抽象基类

只想使用父类来持有一些信息,不想在每个子模型中都敲一遍,这个类永远不会单独使用,使用abstract表明基类,数据库不会建该表

如auth模块 User继承(AbstractUser)

class CommonInfo(models.Model):
    name = models.CharField(max_length=100)
    age = models.PositiveIntegerField()
    class Meta:
        abstract = True
        ordering = [‘name‘]

class Student(CommonInfo):
    home_group = models.CharField(max_length=5)
    class Meta(CommonInfo.Meta):
        db_table = ‘student_info‘

说明:

Meta 也可以继承,如果子类不实现Meta则默认会继承

  • 多表继承

继承一个存在的模型,每个模型都有自己的数据库表。每一个层级下的每个model都是一个真正意义上完整的model,

每个model都有专属的数据表,都可以查询和创建数据表,

继承关系在子model和它的每个父类之间都添加一个链接(通过自动创建的OneToOneField来实现)

class Place(models.Model):
    name = models.CharField(max_length=50)
    address = models.CharField(max_length=80)

class Restaurant(Place):
    serves_hot_dogs = models.BooleanField(default=False)
    serves_pizza = models.BooleanField(default=False)
  • 代理继承

使用多表继承时,model的每个子类都会自动创建一张新数据表,通常情况下,这正是我们想要的操作,

这是因为子类需要一个空间来存储不包含在基类中的字段数据。但有时,可能只想更改model在Python层的行为实现,

比如:更改默认的manager,或是添加一个新方法

代理继承可以做到:为原始模型创建一个代理。可以创建、删除、更新代理model的实例,而且所有数据都可以像使用原始model一样保存

不同之处在于:可以在代理model中改变默认的排序设置和默认的manager,不会对原始model产生影响

设置 Meta类中proxy的值为True,就完成了对代理model的声明

class Person(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)

class MyPerson(Person):
    class Meta:
        proxy = True

    def do_something(self):
        pass

说明:

MyPerson只是一个代理,数据库中不会建立该表,MyPerson类和它的父类Person操作同一个数据表,

特别的是,Person的任何实例也可以通过MyPerson访问,反之亦然

  • 多重继承

多重继承和多表继承没什么大的差别,会自动添加两个OneToOneField,

需要指出,两个基类的默认自增id要重新命名,否则添加OneToOneField会有问题,也不允许子类重写父类字段

class Article(models.Model):
    article_id = models.AutoField(primary_key=True)

class Book(models.Model):
    book_id = models.AutoField(primary_key=True)

class BookReview(Book, Article):
    pass

创建记录时,父类的各个字段需要填写

b = BookReview.objects.create(headline=‘T‘ , body=‘body‘ , title=‘ title‘)

Model querys

回顾:

  • 简单增删改查
  • 返回结果 object QuerySets
  • exclude
  • 反向查询 b.entry_set.all()    可起别名,返回QuerySets
  • 复杂查询 Q
  • 跨关联关系查询,__
  • QuerySet链式过滤
  • F查询
  • 限制返回个数

查询对象比较

比较两个model实例,实质在后台,它会比较两个模型主键的值

所有查询api

https://docs.djangoproject.com/en/1.11/ref/models/querysets/

进阶:

1.  annotate添加注释属性 与聚合函数一起使用返回聚合值,如统计问题的个数,q就有了choice_num这个属性

2.  aggregate 聚合函数返回结果字典

3.  聚合类函数,或注释函数,在django.db.models模块中

  • class Avg(expression, output_field=FloatField, **extra)
  • class Count(expression, distinct=False,  **extra)
  • class Max(expression, output_field=None,  **extra)
  • class Min(expression, output_field=None,  **extra)
  • class Sum(expression, output_field=None,  **extra)
  • class StdDev(expression, sample=False, **extra) # 标准差
  • class Variance(expression, sample=False, **extra) # 方差

4.  distinct() 去重

5.  values 返回ValuesQuerySet(类字典),而不是模型实例对象

6.  vlaues_list与values类似,但返回元组而不是字典

7.  defer only

8.  using使用哪个数据库

9.  select_for_update 返回一个queryset,会锁定相关行直到事务结束

在支持的数据库上面产生一个 SELECT...FOR UPDATE

10.  raw 执行原始sql

11.  get_or_create,有就获取;没就新增,注意返回结果类型和参数defaults含义

try:
    obj = Person.objects.get(first_name=‘John‘, last_name=‘Lennon‘)
except Person.DoesNotExist:
    obj = Person.objects.get(first_name=‘John‘, last_name=‘Lennon‘, birthday=(1993, 7, 1))
# Equal
obj, created = Person.objects.get_or_create(
    first_name = ‘John‘,
    last_name = ‘Lennon‘,
    defaults={‘birthday‘: date(1993, 7, 1)})

12.  update_or_create

13.  bulk_create

14.  in_bulk

15.  latest、earliest、first、last

事务:

事务是绑定在view中实现的

from django.db import transaction

@transaction.non_atomic_requests
def my_view(request):
    print(‘do_stuff‘)

@transaction.atomic
def viewfunc(request):
    print(‘do_stuff‘)

‘‘‘
警告!!!
虽然这种事务模式的优势在于它的简单性,但在访问量增长到一定的时候会造成很大的性能损耗。
这是因为为每一个视图开启一个事物会有一些额外的开销。
另外,这种性能影响还取决于你的应用程序的查询模式以及你的数据库对锁的处理是否高效。
‘‘‘

自定义管理器:

  • 添加额外管理器方法

默认objects添加自定义方法,方法需写原生sql。

添加额外管理器方法是类增加“表级”功能的首选方式(如果要添加行级功能,比如只对某个模型的实例起作用,应使用模型方法,而不是管理器方法)

额外管理器方法可以返回你想要的任何数据,而不需要返回一个查询及集

例如,下面这个自定义管理器提供一个with_counts()方法,它返回所有OpinionPoll对象的列表,列表的每项都有一额外num_reponses属性,

该属性保存一个聚合查询的结果(注:对应的是SQL查询语句中的COUNT(*)生成的项)

# 添加额外管理器方法
class PollManager(models.Manager):
    def with_counts(self):
        from django.db import connection
        cursor = connection.cursor()
        cursor.execute("""
        SELECT p.id, p.question, p.poll_date, COUNT(*)
        FROM polls_opinionpoll p, polls_resopnse r
        WHERE p.id = r.poll_id
        GROUP BY p.id, p.question, p.poll_date
        ORDER BY p.poll_date DESC""")
        result_list = []
        for row in cursor.fetchall():
            p = self.model(id=row[0], question=row[1], poll_date=row[2])
            p.num_responses = row[3]
            result_list.append(p)
        return result_list

class OpinionPoll(models.Model):
    question = models.CharField(max_length=200)
    poll_date = models.DateField()
    objects = PollManager()  # 关键点***

class Response(models.Model):
    poll = models.ForeignKey(‘OpinionPoll‘)
    person_name = models.CharField(max_length=50)
    response = models.TextField()
  • 添加自定义manager 

简单的说,就是在模型里添加属性=models.Manager(),或者它的自定义子类,从而实现对库表的操作

class AuthorManager(models.Manager):
    def get_queryset(self):
        return super(AuthorManager, self).get_queryset().filter(role=‘A‘)

class EditorManager(models.Manager):
    def get_queryset(self):
        return super(EditorManager, self).get_queryset().filter(role=‘E‘)

class Person(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)
    role = models.CharField(max_length=1, choices=((‘A‘, ‘Author‘), (‘E‘, ‘Editor‘)))
    people = models.Manager()  # 等同于原始 objects
    authors = AuthorManager()
    editros = EditorManager()

Person.objects.all()
Person.people.all()
Person.authors.all()
Person.editros.all()
时间: 2024-08-29 15:27:55

Django Model 进阶的相关文章

Django model 进阶以及优化

一.QuerySet 可迭代 querysey=models.Book.objects.all() for book in querysey: print(book.title) 可切片 Book.objects.all()[:3] Book.objects.all()[3:6] # 不支持负的索引,例如Book.objects.all()[0:-1].通常,查询集的切片返回一个新的查询集,它不会执行查询. 惰性查询 QuerySet 是懒惰的 -- 创建查询集不会带来任何数据库的访问:直到查询

Django框架学习-Model进阶用法

Model进阶用法 回顾 访问外键 访问多对多关系 更改数据库结构 当处理数据库结构改变时,需要注意到几点: 增加字段 首先在开发环境中: 再到产品环境中: 删除字段 删除多对多字段 删除model Manager管理器 给管理器添加新的方法 修改返回的QuerySet Model的方法 执行自定义SQL语句 Model进阶用法 回顾 Django中的model层主要和数据库进行交互,使用数据库API对数据库进行增删改查的操作. 下面将介绍关于model层更深入的用法. 下面是之前创建model

Python之路【第十七篇】:Django【进阶篇 】

Python之路[第十七篇]:Django[进阶篇 ] Model 到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: 创建数据库,设计表结构和字段 使用 MySQLdb 来连接数据库,并编写数据访问层代码 业务逻辑层去调用数据访问层执行数据库操作 import MySQLdb def GetList(sql): db = MySQLdb.connect(user='root', db='wupeiqidb', passwd='1234', host='localhost')

Python开发【第二十二篇】:Web框架之Django【进阶】

Python开发[第二十二篇]:Web框架之Django[进阶] 猛击这里:http://www.cnblogs.com/wupeiqi/articles/5246483.html 博客园 首页 新随笔 联系 订阅 管理 随笔-124  文章-127  评论-205 Python之路[第十七篇]:Django[进阶篇 ] Model 到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: 创建数据库,设计表结构和字段 使用 MySQLdb 来连接数据库,并编写数据访问层代码 业务逻

Python之路【第十七篇】:Django【进阶篇】

Python之路[第十七篇]:Django[进阶篇 ] Model 到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: 创建数据库,设计表结构和字段 使用 MySQLdb 来连接数据库,并编写数据访问层代码 业务逻辑层去调用数据访问层执行数据库操作 import MySQLdb def GetList(sql): db = MySQLdb.connect(user='root', db='wupeiqidb', passwd='1234', host='localhost')

Python之路,Day15 - Django适当进阶篇

Python之路,Day15 - Django适当进阶篇 本节内容 学员管理系统练习 Django ORM操作进阶 用户认证 Django练习小项目:学员管理系统设计开发 带着项目需求学习是最有趣和效率最高的,今天就来基于下面的需求来继续学习Django 项目需求: 1.分讲师\学员\课程顾问角色,2.学员可以属于多个班级,学员成绩按课程分别统计3.每个班级至少包含一个或多个讲师4.一个学员要有状态转化的过程 ,比如未报名前,报名后,毕业老学员5.客户要有咨询纪录, 后续的定期跟踪纪录也要保存6

Django【进阶篇 】(地阶段位二)

Django[进阶篇 ] Model 到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: 创建数据库,设计表结构和字段 使用 MySQLdb 来连接数据库,并编写数据访问层代码 业务逻辑层去调用数据访问层执行数据库操作 import MySQLdb def GetList(sql): db = MySQLdb.connect(user='root', db='wupeiqidb', passwd='1234', host='localhost') cursor = db.cur

Django model select的各种用法详解

<Django model update的各种用法介绍>文章介绍了Django model的各种update操作,这篇文章就是她的姊妹篇,详细介绍Django model select的用法,配以对应MySQL的查询语句,理解起来更轻松. 基本操作 # 获取所有数据,对应SQL:select * from User User.objects.all() # 匹配,对应SQL:select * from User where name = '运维咖啡吧' User.objects.filter(

Django model与数据库操作对应关系(转)

? Django对数据库的操作分用到三个类:Manager.QuerySet.Model. Manager的主要功能定义表级方法(表级方法就是影响一条或多条记录的方法),我们可以以models.Manager为父类,定义自己的manager,增加表级方法: QuerySet是Manager的方法返回的,是一个可遍历结构,包含一个或多个元素,每个元素都是一个Model 实例,它里面的方法也是表级方法. Model是一条记录的类,它的功能很强大,里面包含外键实体等,它的方法都是记录级方法(都是实例方