前言
object relation mapping(ORM)关系对象映射表,一个类实例映射为一条表记录
目录
数据库配置
1.django 默认使用sqlite的数据库,如果需要使用mysql数据库,就需要在settings中修改配置信息
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME' : '', #你的数据库的名字 'USER' : '', #你的数据库用户 'PASSWORD' : '', #你的数据库密码 'HOST' : '', #你的数据库主机,默认localhost 'PORT' : '3306', #你的数据库端口 } }
2.需要手动导入PyMySQL,在_init_.py中导入
import MySQLdb
#注:如果想要显示表执行的sql语句,就在settings中配置 LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console':{ 'level':'DEBUG', 'class':'logging.StreamHandler', }, }, 'loggers': { 'django.db.backends': { 'handlers': ['console'], 'propagate': True, 'level':'DEBUG', }, } }
创建类
1. 在models.py中创建类映射表
from django.db import models # Create your models here. class Book(models.Model): name=models.CharField(max_length=20) price=models.FloatField() pub_date=models.DateField() publish = models.ForeignKey("Publish", on_delete=models.CASCADE) #一对多 authors = models.ManyToManyField("Author") #多对多 def __str__(self): return self.name class Publish(models.Model): name=models.CharField(max_length=32) city=models.CharField(max_length=32) def __str__(self): return self.name class Author(models.Model): name = models.CharField(max_length=32) age = models.IntegerField(default=20) def __str__(self): return self.name
2.在终端中输入 python manage.py makemigrations , python manage.py migrate 两条命令
类属性进阶操作
class UserInfo(models.Model): age = CharFiled(是否为空,类型,长度,列名,索引,错误提示,自定义验证规则) ... ...
字段参数 null 数据库中字段是否可以为空 db_column 数据库中字段的列名 default 数据库中字段的默认值 primary_key 数据库中字段是否为主键 db_index 数据库中字段是否可以建立索引 unique 数据库中字段是否可以建立唯一索引(用于一对一) unique_for_date 数据库中字段【日期】部分是否可以建立唯一索引 unique_for_month 数据库中字段【月】部分是否可以建立唯一索引 unique_for_year 数据库中字段【年】部分是否可以建立唯一索引 verbose_name Admin中显示的字段名称 blank Admin中是否允许用户输入为空 editable Admin中是否可以编辑 help_text Admin中该字段的提示信息 choices Admin中显示选择框的内容,用不变动的数据放在内存中从而避免跨表操作 如:gf = models.IntegerField(choices=[(0, 'chen'),(1, 'xiaoyi'),],default=1) error_messages 自定义错误信息 字典健:null, blank, invalid, invalid_choice, unique, and unique_for_date 如:{'null': "不能为空.", 'invalid': '格式错误'}
单表操作
-----------增 # 单表 #添加方法一 b = Book(name="python基础",price=99,author="chen",pub_date="2017-12-12") b.save() #添加方法二 Book.objects.create(name="PHP基础",price=70,author="chen",pub_date="2016-12-12") -----------删 # 单表 Book.objects.filter(author="liu").delete() -----------改 # 单表 Book.objects.filter(author="chen").update(price=100) -----------查 # 单表 book_list = Book.objects.all() print(book_list[0]) book_list = Book.objects.all()[::-2] book_list = Book.objects.all()[::2] book_list = Book.objects.first() book_list = Book.objects.last() book_list = Book.objects.get(id=4) #只能取出一条记录的时候不报错 ret = Book.objects.filter(author="chen").values("name","price") #以字典的形式显示 ret = Book.objects.filter(author="chen").values_list("name","price") #以元组的形式显示 book_list = Book.objects.exclude(author="chen").values("name","price") #除了chen以外的人的数据 book_list = Book.objects.all().values("name").distinct() #根据一个字段去重 ret = Book.objects.all().values("name").distinct().count() #根据一个字段去重 Book.objects.filter(authors__id__in=[1,2]) #获取id等于1或2的数据 Book.objects.filter(authors__id__range=[1,2]) #范围 #万能的__ #价格大于50的数/85.41 book_list = Book.objects.filter(price__gt=50).values("name","price") #模糊查询 book_list = Book.objects.filter(name__icontains="P").values("name","price")
一对多(外键)
外键关系及参数
ForeignKey(ForeignObject) to, 要进行关联的表名 to_field=None, 要关联的表中的字段名称 on_delete=None, 当删除关联表中的数据时,当前表与其关联的行的行为 - models.CASCADE,删除关联数据,与之关联也删除(常用) - models.DO_NOTHING,删除关联数据,引发错误IntegrityError - models.PROTECT,删除关联数据,引发错误ProtectedError - models.SET_NULL,删除关联数据,与之关联的值设置为null(前提FK字段需要设置为可空) - models.SET_DEFAULT,删除关联数据,与之关联的值设置为默认值(前提FK字段需要设置默认值) related_name = None, 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all() related_query_name=None, 反向操作时,使用的连接前缀,用于替换【表名】 如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名') limit_choices_to=None, 在Admin或ModelForm中显示关联数据时,提供的条件: 如: - limit_choices_to={'nid__gt': 5} - limit_choices_to=lambda : {'nid__gt': 5} db_constraint=True 是否在数据库中创建外键约束 parent_link=False 在Admin中是否显示关联数据
书籍和出版社是一对多的关系
class Book(models.Model): name=models.CharField(max_length=20) price=models.FloatField() pub_date=models.DateField() publish = models.ForeignKey("Publish", on_delete=models.CASCADE) #一对多 def __str__(self): return self.name class Publish(models.Model): name=models.CharField(max_length=32) city=models.CharField(max_length=32) def __str__(self): return self.name
添加数据的方法
#多表添加 Book.objects.create(name="linux运维",price=77,pub_date="2017-12-12",publish_id=2) Book.objects.create(name="GO",price=23,pub_date="2017-05-12",publish=publish_obj)
多表查询的方法
#含外键:一对多查询 # 查询人民出版社出过的所有书籍名字和价格 # 方式一: pub_obj=Publish.objects.filter(name="人民出版社")[0] ret=Book.objects.filter(publish=pub_obj).values("name","price") #方式二 pub_obj = Publish.objects.filter(name="人民出版社")[0] print(pub_obj.book_set.all().values("name","price")) #book_set print(type(pub_obj.book_set.all())) # 方式三,用__ ret=Book.objects.filter(publish__name="人民出版社").values("name","price") #python基础书出版社的名字 #法一 ret = Publish.objects.filter(book__name="Python基础").values("name") # 法二 ret3=Book.objects.filter(name="python基础").values("publish__name") #北京出版出版的所有的书 ret = Book.objects.filter(publish__city="北京").values("name") ret = Publish.objects.filter(city="北京")
一对一(外键+unique)
class Book(models.Model): name=models.CharField(max_length=20) price=models.FloatField() pub_date=models.DateField() publish = models.ForeignKey( to = "Publish", on_delete=models.CASCADE, unique=True, ) #一对一 def __str__(self): return self.name class Publish(models.Model): name=models.CharField(max_length=32) city=models.CharField(max_length=32) def __str__(self): return self.name
多对多(关系表)
多对多关系及参数
ManyToManyField(RelatedField) to, 要进行关联的表名 related_name=None, 反向操作时,使用的字段名,用于代替 【表名_set】 如: obj.表名_set.all() related_query_name=None, 反向操作时,使用的连接前缀,用于替换【表名】 如: models.UserGroup.objects.filter(表名__字段名=1).values('表名__字段名') limit_choices_to=None, 在Admin或ModelForm中显示关联数据时,提供的条件: 如: - limit_choices_to={'nid__gt': 5} - limit_choices_to=lambda : {'nid__gt': 5} symmetrical=None, 仅用于多对多自关联时,symmetrical用于指定内部是否创建反向操作的字段 #可选字段有:code, id, m1 class BB(models.Model): code = models.CharField(max_length=12) m1 = models.ManyToManyField('self',symmetrical=True) # 可选字段有: bb, code, id, m1 class BB(models.Model): code = models.CharField(max_length=12) m1 = models.ManyToManyField('self',symmetrical=False) through = None, 自定义第三张表时,使用字段用于指定关系表 through_fields = None, 自定义第三张表时,使用字段用于指定关系表中那些字段做多对多关系表 from django.db import models class Person(models.Model): name = models.CharField(max_length=50) class Group(models.Model): name = models.CharField(max_length=128) members = models.ManyToManyField( Person, through='Membership', through_fields=('group', 'person'), ) class Membership(models.Model): group = models.ForeignKey(Group, on_delete=models.CASCADE) person = models.ForeignKey(Person, on_delete=models.CASCADE) inviter = models.ForeignKey( Person, on_delete=models.CASCADE, related_name="membership_invites", ) invite_reason = models.CharField(max_length=64) db_constraint = True, 是否在数据库中创建外键约束 db_table = None, 默认创建第三张表时,数据库中表的名称
书籍和作者是多对多的关系
注:使用authors = models.ManyToManyField("Author"),会自动创建book_authors表,也可以自己创建关系表(不会有authors属性) class Book(models.Model): name=models.CharField(max_length=20) price=models.FloatField() pub_date=models.DateField() authors = models.ManyToManyField("Author") #多对多 def __str__(self): return self.name class Author(models.Model): name = models.CharField(max_length=32) age = models.IntegerField(default=20) def __str__(self): return self.name
-----------增 #绑定多表关系 book_obj = Book.objects.get(id=4) authors_objs = Author.objects.get(id=2) #authors_objs = Author.objects.all() book_obj.authors.add(authors_objs) -----------查 #多对多的关系,第三张表关系表 #通过对象的方式绑定关系 #书找作者 book_obj=Book.objects.get(id=3) print(book_obj.authors.all()) #作者找书 author_obj = Author.objects.get(id=2) print(author_obj.book_set.all()) return HttpResponse("添加成功") -----------删 # 解除多表关系 book_obj = Book.objects.get(id=4) authors_objs = Author.objects.all() #是列表 book_obj.authors.remove(*authors_objs) book_obj.authors.remove(2) #删除的是数量 #清空 book_obj.authors.clear() -----------改 #修改的set()方法 book_obj = Book.objects.get(id=4) book_obj.authors.set([2,3])
手动创建的多表关系
#手动创建关系表 class Book(models.Model): name=models.CharField(max_length=20) price=models.FloatField() pub_date=models.DateField() def __str__(self): return self.name class Book_Author(models.Model): book=models.ForeignKey("Book",on_delete=models.CASCADE) author=models.ForeignKey("Author",on_delete=models.CASCADE) class Author(models.Model): name = models.CharField(max_length=32) age = models.IntegerField(default=20) def __str__(self): return self.name
-----------增 #手动创建的关系表 Book_Author.objects.create(book_id=2,author_id=3) -----------查 #关联查询,查找书的所有作者 obj = Book.objects.get(id=2) print(obj.book_author_set.all()[0].author) #chen出过的书和价格 ret = Book.objects.filter(book_author__author__name="chen").values("name","price")
手动创建的表因为没有第三张的字段,因此没有自动创建的表查询的方便,而自动创建的表默认只有三个字段
因此引入 手动+自动联合创建表
class User(models.Model): username = models.CharField(max_length=32,db_index=True) def __str__(self): return self.username class Tag(models.Model): title = models.CharField(max_length=16) m = models.ManyToManyField( to='User', through='UserToTag', through_fields=['u','t'] ) def __str__(self): return self.title #使用ManyToManyField只能在第三张表中创建三列数据 class UserToTag(models.Model): # nid = models.AutoField(primary_key=True) u = models.ForeignKey(to='User') t = models.ForeignKey(to='Tag') ctime = models.DateField() #用于关系表u,t两个字段共同约束唯一 class Meta: unique_together=[ ('u','t'), ]
自关联
用户粉丝互相关注(在同一张用户表里,用户互相关联)
class User(models.Model): username = models.CharField(max_length=32,db_index=True) d = models.ManyToManyField('User',related_name='b') def __str__(self): return self.username
注:自关联的跨表查询
symmetrical=None, 仅用于多对多自关联时,symmetrical用于指定内部是否创建反向操作的字段 #可选字段有:code, id, m1 class BB(models.Model): code = models.CharField(max_length=12) m1 = models.ManyToManyField('self',symmetrical=True) # 可选字段有: bb, code, id, m1 class BB(models.Model): code = models.CharField(max_length=12) m1 = models.ManyToManyField('self',symmetrical=False)
聚合函数,Q函数,F函数
先导入模块
from django.db.models import Min,Avg,Max,Sum from django.db.models import F,Q
#聚合函数(需要先导入函数) ret = Book.objects.all().aggregate(Avg("price")) ret = Book.objects.all().aggregate(chen_money = Sum("price")) #取别名 #查各个作者的书的价格总和 value:按照作者名字分组 ret = Book.objects.values("authors__name").annotate(Sum("price")) print(ret) #查各个出版社出的书的最小 ret = Publish.objects.values("name").annotate(Min("book__price")) print(ret) #----------------------------------------------------------------------------------------------------------------------------- #F查询和Q查询,(使用前要导入模块) #F拿到的值 Book.objects.all().update(price=F("price")+10) #Q可以做or操作 ,~Q表示非 re = Book.objects.filter(Q(price=80) | Q(name="GO")) #组合查询 re = Book.objects.filter(Q(name__contains="G")) #Q查询和关键字查询组合,Q要在前面 re = Book.objects.filter(Q(name="GO"),price=80)
惰性取值,迭代对象,exists()函数
#只有在使用ret使用的时候才去查询,惰性取值 re = Book.objects.filter(price=80) #不会取值 for i in re: #使用时才会去查询 print(i) print(re) #--------------------------------------------------------------------- #exists() re = Book.objects.filter(price=80) re.exists() #会查询,但re不会被赋值,只有使用re变量的时候才会被赋值 #---------------------------------------------------------------------- #iterator() 迭代器对象 ret = Book.objects.filter(price=80) ret = ret.iterator()