django之ORM详解(全)

字段 - 类型

  • models.AutoField()   自增列=int(11),如果没有的话,默认会生成一个名称为id的列,如果要显示的定义一个自增列,必须把该列设置为主键(primary_key=True)

  • models.IntegerField()   整形(-2147483648, 2147483647)

  • models.BigIntegerField()  长整形(-9223372036854775808, 9223372036854775807)

  • models.PositiveIntegerField()  正Integer (0, 2147483647)

  • models.PositiveSmallIntegerField()正smallInteger (0, 32767)

  • models.SmallIntegerField()   短整型 (-32768, 32767)

  • models.Decimal()   十进制小数类型=decimal 必须指定max_digits(总位数)和decimal_places(小数位)

  • models.FloatField()   浮点类型=double

  • models.CharField()   字符串类型字段 必须加max_length参数

    • models.ComaSeparatedIntegerField()用逗号分割的数字类型=varchar 继承CharField,所以必须加max_lenght参数
    • models.EmailField()   字符串类型(正则表达式邮箱)=varchar 对字符串进行正则表达式验证
    • models.IPAddressField()   字符串类型(ip4正则表达式)
    • models.GenericIPAddressField()  字符串类型(ip4和ip6是可选的) 参数protocol可以是:both、ipv4、ipv6 验证时,会根据设置进行报错
    • models.SlugField()   减号、下划线、字母、数字
    • models.URLField()   字符串类型,地址正则表达式
    • models.BinaryField()  二进制
    • models.ImageField() 图片 upload_to=’’ 指定上传图片的路径
    • models.FilePathField() 文件 upload_to=’’ 指定上传图片的路径
  • models.TextField   字符串=longtext

  • models.BooleanField()  布尔类型字段=tinyint(1) 不能为空blank=True

  • models.NullBooleanField()   允许为空的布尔类型

  • models.DateField()   日期字段类型date 参数auto_now=True表示每次更新都会更新这个时间;参数auto_now_add表示只是第一次创建时添加,之后的更新不再改变

  • models.DateTimeField()   日期字段类型datetime 同DateField的参数

  • models.TimeField()   时间 HH:MM[:ss[.uuuuuu]]

字段 - 选项:

  • null=布尔值: 与数据库相关,字段是否允许为空,默认False

  • blank=布尔值: 与表单验证相关,表单是否允许为空,默认False

  • defalut=值或对象: 字段默认值,

  • primary_key=布尔值: 是否主键,默认False

  • unique=布尔值: 是否唯一,默认False

  • verbose_name=文本: 字段描述/form中的label值,也可以放到第一个参数models.CharField(“person’s first name”, max_length=30)

  • db_column 数据库中字段的列名(db_column=“test”)

  • db_index 设置索引,默认False

  • editable 是否可编辑,默认为True

  • help_text 表单帮助信息

  • choices form中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作, 可通过get_字段_display() 访问字段的显示值
    gf = models.IntegerField(choices=[(0, '何穗'),(1, '大表姐'),],default=1)

  • error_messages 自定义错误信息(字典类型),字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date 如:{'null': "不能为空.", 'invalid': '格式错误'}

  • validators 自定义错误验证(列表类型),从而定制想要的验证规则

from django.core.validators import RegexValidator
from django.core.validators import EmailValidator,URLValidator,DecimalValidator,\
MaxLengthValidator,MinLengthValidator,MaxValueValidator,MinValueValidator

test = models.CharField(
	max_length=32,
	error_messages={
		'c1': '优先错信息1',
		'c2': '优先错信息2',
		'c3': '优先错信息3',
	},
	validators=[
		RegexValidator(regex='root_\d+', message='错误了', code='c1'),
		RegexValidator(regex='root_112233\d+', message='又错误了', code='c2'),
		EmailValidator(message='又错误了', code='c3'), ]
)
  • max_length: [字符串型] 必须指定数值的参数,utf8编码的最大长度

  • unique_for_date: [时间日期类型] 日期必须唯一

  • unique_for_month: [时间日期类型] 月必须唯一

  • unique_for_year: [时间日期类型] 年必须唯一

  • auto_now: [时间日期类型] 更新当前时间

  • auto_now_add: [时间日期类型] 创建时更新当前时间

  • max_digits: [浮点型] DecimalField字段必须指定,一共多少位

  • decimal_places: [浮点型] DecimalField字段必须指定,小数点位数

blank主要用在CharField, TextField 这两个字符型字段可用字符串来存储空值

null主要用在IntegerField,DateField,DateTimeField 这几个字段不接受空字符串,所以在使用时,必须将blank和null同时赋值True

元数据Meta

class Meta:
	db_table = "addressinfo"    		# 表的名称
	ordering = 'pid'                    # 排序字段
	verbose_name = "省市县地址信息"
	verbose_name_plural = verbose_name  # 复数
	unique_together = ("address", "note")  # 联合唯一健,还可以用二维元组 ((), ())
	app_label = 'app_name'  			# 模型类属于哪一个应用
	# db_tablespace       				# 定义数据库表空间的名称
	# abstract = True   				# 基类用于继承,默认为False

表关系

示例:

from django.db import models

class School(models.Model):
    ''' 学院 '''
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=30)
	
    def __str__(self):
        return "School".format(self.id, self.name)

class Student(models.Model):
	''' 学生 '''
	GENDER_CHOICES = (('male', "男"), ('female', "女"), ('secret', "保密"))
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=30)
    school = models.ForeignKey('School',
							   null=True, 					# 可以为空值
							   related_name='student', 		# 反向查询用(就不_set了:d1.student_set.all() -》d1.student )
							   on_delete=models.CASCADE)	# 外键,自动关联表的主键 级联删除
	gender = models.CharField(max_length=6, choices=GENDER_CHOICES, default="secret", verbose_name="性别")
	introduce = models.TextField(blank=True, verbose_name="介绍")
    age = models.IntegerField(default=0, verbose_name="年龄")
    rank = models.PositiveIntegerField(default=1, verbose_name="排名", unique=True)
    discount = models.DecimalField(max_digits=3, decimal_places=2, verbose_name="折扣", default=1.0)
    grade = models.FloatField(default=0.0, verbose_name="成绩")
    url = models.URLField(verbose_name="个人主页", max_length=100)
    email = models.EmailField(verbose_name="邮箱")
    image = models.ImageField(upload_to='img/%Y/%m/%d/', verbose_name='上传图片', null=True)
    file = models.FileField(upload_to="file/%Y/%m/%d/", verbose_name="上传文件", blank=True)
    is_deleted = models.BooleanField(verbose_name="已删除", default=False, blank=True)
    time_added = models.DateTimeField(verbose_name="添加时间", auto_now_add=True, blank=True)
	
    def __str__(self):
        return "Student".format(self.id, self.name, self.school_id)
    
class Course(models.Model):
    ''' 课程 '''
    id = models.AutoField(primary_key=True)
    name= models.CharField(max_length=30)
    student = models.ManyToManyField('Student', related_name='course') # 多对多  生成第三张关系表

    def delete(self, using=None, keep_parents=False):
        self.is_deleted = True
        # some actions
        self.save()

    def save(self, force_insert=False, force_update=False, using=None,
             update_fields=None):
        # some actions
        self.name = self.name.capitalize()  # 首字母大写
        return super().save(force_insert=force_insert, force_update=force_update, using=using,
                            update_fields=update_fields)

    def __repr__(self):
        return "UserProfile:{}".format(self.name)

    def __str__(self):
        return self.name

    class Meta:
        ordering = ['-time_added']

        # 对象的默认排序字段,获取对象列表时使用,升序ordering['time_added'],降序ordering['-time_added']
        verbose_name = "用户信息"
        verbose_name_plural = verbose_name
        db_table = "student_info"

关系数据操作

添加

	s1 = Student(name='张三', school_id=1)
	s1.save()
	# 或
	s2 = Student(name='李四', school=School.objects.get(pk=1))
	s2.save()	

关联访问

studentObj.school			# 属性取值,获取学生对象studentObj的school对象信息

# 通过管理器反向访问
schoolObj.student_set.all()
#或
schoolObj.student.all()		# 需要定义related_name='student' 作为反向查询的别名

d1 = School.objects.get(d_id=1)
s1 = Student.objects.get(s_id=1)
c1 = Course.objects.get(c_id=1)

d1.student.all()	# 查询到学院的所有学生, 通过一对多关系,管理器.all()
s1.department 		# 模型类里面的属性,直接访问
c1.student 			# 管理器 多对多
c1.student.all()	# 报名这个课程的学生
s1.course.all()		# 学生报名了哪些课程

一对多,多的那头就有这个管理器,有如下方法

  1. add(obj1, obj2, …) 添加的已经存在数据库的数据

添加一指定的模型对象到关联的对象集中

# 将studentObj学生改成schoolObj学院中
schoolObj.student.add(studentObj)    

# 先查询后添加
studentObj_QuerySet = Student.objects.filter(id=1)
schoolObj_QuerySet = School.objects.filter(id=1)  filter取到的是QuerySet,类似于集合形式
schoolObj_QuerySet[0].student.add(studentObj_QuerySet[0])

# 先创建后添加
s6 = Student(s_name='张三', school_id=1)
s6.save()
schoolObj.student.add(s6) 
  1. create(**kwargs) 添加不存在的数据 ,将数据直接存入数据库

创建一个新的对象,将它保存并放在关联的对象集返回新创建的对象

studentObj.course.create(name='php') 	# 会同时向两个表格添加数据
schoolObj.student.create(name='李四')   # 给schoolObj学院添加一个学生(之前不存在数据库中)
  1. remove(obj1, obj2, …) 从关联的对象集中删除指定的模型对象。

删除的是关系表中的数据

studentObj.course.remove(courseObj) # 学生取消某个课程

  1. clear() 从关联的对象集中删除所有的对象

studentObj.course.clear() # 删除的是中间信息表的信息

QuerySet接口

1、链式调用接口:返回QuerySet对象

  • all() 用于查询所有数据
  • filter() 过滤
  • exclude() 跟filter相反
  • reverse() 结果倒序排列
  • distinct() 字段去重
  • none() 返回空的QuerySet

2、非链式调用:

  • get(): get(id=1)存在直接返回实例,否则抛出DoesNotExist异常

  • create() 创建一个model对象,create(title=’’,content=’’,…)

  • bulk_create() 批量创建

  • get_or_create() 条件查找,如果没有找到,就调用create创建

  • update_or_create() 更新时如果不存在则创建

  • update() 更新 filter().update()

  • delete() 删除 filter().delete()

  • count() select count(*) from table

  • latest() 返回最新的一条记录,需要在model的Meta中定义,get_latest_by = <排序字段>

  • earliest() 同latest,返回最早的一条记录

  • first() 当前QuerySet记录中获取第一条

  • last() 当前QuerySet记录中获取最后一条

  • exists() 返回boolen

  • in_bulk() 批量查询

  • values() filter().values(‘title’)

  • values_list() filter().values_list(‘title’)

3、进阶接口:

defer: 把不需要展示的字段延迟加载 如all().defer(‘content’) content需要的时候再查询

posts = Post.objects.all().defer('content')
for post in posts:	# 执行数据库查询
	print(post.content)	#再次查询数据库,获取content 【N+1次查询】

only: 同defer,逻辑相反,只获取xxx字段内容

select_related: 处理一对一 关系的N+1查询问题

posts = Post.objects.all().select_related('category')
for post in posts: # 产生数据库查询,category数据也会一次性查询出来
	print(post.category)

prefetch_related: 处理多对多 关系的N+1查询问题

posts = Post.objects.all().prefetch_related('tag')
for post in posts:	#产生两条查询语句,分别查询post和tag
	print(post.tag.all())

4、常用的字段查询:Post.objects.filter(content__contains=‘查询条件’)

__contains__iscontains 包含,用来进行相似查询
__exact__iexact 精准匹配
__startswith__istartswith 以某个字符串开头, like ‘<关键字>%’
__endswith__iendswith 以某个字符串开头, like ‘<关键字>%’
__gt__lt__gte__lte 比较,相当于>、<、>=、<=
__in 指定某个集合,如:filter(id_in=[1,2,3])
__range 范围查询,多用于时间范围,filter(crated_time__range=(time1,time2)) 相当于 between time1 and time2
__year__month__day 日期字段的年/月/日
__isnull True/False

5、进阶查询:

F(): 用来执行数据库层面的计算,避免出现竞争状态

post = Post.objects.get(id=1)
post.pv = F('pv') + 1	# 相当于pv = pv + 1,如果使用post.pv + 1 在多线程有问题
post.save()

Q(): 解决or查询

from django.db.models import Q
Post.objects.filter(Q(id=1) | Q(id=2))
Post.objects.filter(Q(id=1) & Q(id=2))

Count(): 聚合查询

# 某个分类下的文章:
category = Category.objects.get(id=1)
posts_count = category.post_set.count()

# 通过category.post_count()
from django.db.models import Count
categories = Category.objects.annotate(posts_count=Count('post'))
print(categories[0].posts_count)

聚合、分组:

class Student(models.Model):
	'''学生类'''
	name = models.CharField(max_length=20)
	age = models.IntegerField()
	hobbies = models.ManyToManyField(Hobby)
class Hobby(models.Model):
	'''兴趣类'''
	name = models.CharField(max_length=20)

aggregate()聚合方法详解:

from django.db.models import Avg, Max, Min

# 平均年龄
Student.objects.all().aggregate(Avg('age'))	# => { 'age__avg': 12 }
Student.objects.aggregate(Avg('age'))		# => { 'age__avg': 12 }

# 学生平均年龄, 设置字典的key
Student.objects.aggregate(average_age = Avg('age'))	# => { 'average_age': 12 }

# 年龄累计
Student.objects.aggregate(Sum('age'))		# =>  {'age__sum': 144}

# 年龄最大
Student.objects.aggregate(Max('age'))		# =>	{'age__max': 66}

# 同时获取多个聚合
Student.objects.aggregate(Avg('age'), Max('age'), Min('age'))	# => {'age__avg': 66, 'age__max': 66, 'age__min': 66}

# 根据Hobby爱好 反查学生最大年龄。查询字段student和age间有双下划线哦。
Hobby.objects.aggregate(Max('student__age'))	# => { 'student__age__max': 12 }

**annotate()分组**方法详解: 
```python
# 按学生分组,统计每个学生的爱好数量
Student.objects.annotate(hobby_count_by_student=Count('hobbies'))

#按爱好分组,再统计每组学生数量。
Hobby.objects.annotate(Count('student'))

你可能感兴趣的:(python)