Django框架06 /orm多表操作
Django框架06 /orm多表操作
目录
1. admin相关操作
-
注册超级用户
python manage.py createsuperuser # 输入用户名:liubing # 邮箱不用输 直接回车 # 输入密码:必须超过8位,并且别太简单
-
在admin文件中注册orm表
from django.contrib import admin from app01 import models admin.site.register(models.Author) admin.site.register(models.AuthorDetail) admin.site.register(models.Publish) admin.site.register(models.Book) # 在admin页面设置可编辑 from django.contrib import admin from sales import models class UserInfoAdmin(admin.ModelAdmin): list_display = ['id','username','telephone'] class CourseRecordAdmin(admin.ModelAdmin): list_display = ['id','day_num','course_title','re_class','teacher'] list_editable = ['day_num','course_title','re_class','teacher',] class StudyRecordAdmin(admin.ModelAdmin): list_display = ['id','attendance','score','student',] list_editable = ['attendance','score','student',] admin.site.register(models.UserInfo,UserInfoAdmin) admin.site.register(models.Department) admin.site.register(models.ClassList) admin.site.register(models.Campuses) admin.site.register(models.Customer) admin.site.register(models.ConsultRecord) admin.site.register(models.StudyRecord,StudyRecordAdmin) admin.site.register(models.Enrollment) admin.site.register(models.CourseRecord,CourseRecordAdmin)
2. 创建模型
-
表和表之间的关系
- 一对一
- 多对一
- 多对多
-
简单表关系构建
1.作者模型:一个作者有姓名和年龄。 2.作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等信息。作者详情模型和作者模型之间是一对一的关系(one-to-one) 3.出版商模型:出版商有名称,所在城市以及email。 4.书籍模型: 书籍有书名和出版日期,一本书可能会有多个作者,一个作者也可以写多本书,所以作者和书籍的关系就是多对多的关联关系(many-to-many);一本书只应该由一个出版商出版,所以出版商和书籍是一对多关联关系(one-to-many)。
-
代码实现:
from django.db import models # 作者表 class Author(models.Model): # id可以省略不写,默认id为主键自增 # id = models.AutoField(primary_key=True) name = models.CharField(max_length=32) age = models.IntegerField() authorDetail = models.OneToOneField(to='AuthorDetail',to_field='id',on_delete=models.CASCADE) on_delete=models.CASCADE # Django 1.把版本默认就是,Django 2.版本没有需要自己需要时设置 # 简写 # authorDetail=models.OneToOneField("AuthorDetail",on_delete=models.CASCADE) # 作者明细表 class AuthorDetail(models.Model): # id = models.AutoField(primary_key=True) birthday = models.DateField() # 电话字段选择CharField类型,如果查找以'151'开头的话,整型不能实现 telephone = models.CharField(max_length=20) addr = models.CharField(max_length=64) # 出版社表 class Publish(models.Model): # id = models.AutoField(primary_key=True) name = models.CharField(max_length=32) city = models.CharField(max_length=32) email = models.EmailField() # 书籍表 class Book(models.Model): # id = models.AutoField(primary_key=True) title = models.CharField(max_length=32) publishDate = models.DateField() price = models.DecimalField(max_digits=5,decimal_places=2) # 多对一 # publish = models.ForeignKey(to='Publish',to_field='id',on_delete=models.CASCADE) # 简写 publishs=models.ForeignKey(to="Publish",on_delete=models.CASCADE,) # 多对多 # authors = models.ManyToManyField(to='Author',) # 简写 authors=models.ManyToManyField('Author',)
-
元信息
- ORM对应的类里面包含另一个Meta类,而Meta类封装了一些数据库的信息。
class Author2Book(models.Model): author = models.ForeignKey(to="Author") book = models.ForeignKey(to="Book") class Meta: db_table='authordetail' # 指定表名 index_together= ("author", "book") # 创建联合索引 unique_together = ("author", "book") # 创建联合唯一索引 ordering = ['-id',] # 按id字段排序 db_table # ORM在数据库中的表名默认是 app_类名,可以通过db_table可以重写表名。db_table = 'book_model' index_together # 联合索引。 unique_together # 联合唯一索引。 ordering # 指定默认按什么字段排序。 ordering = ['id',] # 只有设置了该属性,我们查询到的结果才可以被reverse(),否则是能对排序了的结果进行反转(order_by()方法排序过的数据)
3. 增加
-
代码示例
def test(request): # 一对一 au_obj = models.AuthorDetail.objects.get(id=4) models.Author.objects.create( name = 'song', age = 59, # 方式一 authorDetail=au_obj, # 方式二 authorDetail_id=4 ) # 一对多 pub_obj = models.Publish.objects.get(id=3) models.Book.objects.create( title = 'python', publishDate='2016-6-6', price = 88, # 方式一: publish = pub_obj # 方式二: publish_id = 3 ) # 多对多 a1 = models.Author.objects.get(id=1) a2 = models.Author.objects.get(id=4) new_obj = models.Book.objects.create( title = '老人与海', price = 99, publishDate='2019-1-1', publish_id=2, ) # 方式一(常用): new_obj.authors.add(*[1,4]) # *args,**kwargs # 方式二: new_obj.authors.add(1,4) # 方式三: new_obj.authors.add(a1,a2)
4. 删除
-
代码示例
# 一对一 # 先删除关联表,再删除被关联表,否则就是级联删除 models.Author.objects.filter(id=3).delete() models.AuthorDetail.objects.filter(id=3).delete() # 一对多 models.Book.objects.filter(id=3).delete() models.Publish.objects.filter(id=3).delete() # 多对多 --- 删除第三张表、关联两两张表的中间表 book_obj = models.Book.objects.get(id=2) book_obj.authors.remove(1) #删除 id=2的book表对应的id=1的Author的第三张表的记录 book_obj.authors.clear() #清除 book_obj.authors.set(['1','5']) #先清除再添加,相当于修改,列表里的id值必须用引号引起来
5. 修改
-
代码示例
ret = models.Publish.objects.get(id=2) models.Book.objects.filter(id=5).update( title = 'linux', # 方式一: publish =ret, # 方式二: publish_id = 1, ) # 修改 --- models对象不能使用update方法
6. 基于对象的跨表查询
-
代码示例
# 一对一 # 正向查询 -- 对象.属性 # 关系属性写在表1,关联到表2,那么通过表1的数据去找表2的数据,叫做正向查询,反过来就是反向查询 # 查询一下song的电话号码 obj = models.Author.objects.filter(name='song').first() te = obj.authorDetail.telephone print(te) # 反向查询 -- 对象.小写表名 # 查一下电话号码为110的作者姓名 obj = models.AuthorDetail.objects.filter(telephone=110).first() na = obj.author.name print(na) # 一对多 # 正向查询 # 查询老人与海这本书是哪个出版社出版的 obj = models.Book.objects.filter(title='老人与海').first() te = obj.publish.name print(te) # 反向查询 # 查询24出版社出版过哪些书 obj = models.Publish.objects.filter(name='24出版社').first() ret = obj.book_set.all() # print(ret) #<QuerySet [<Book: python>]> # 循环取值 for i in ret: print(i.title) #python # 多对多 # 正向查询 # 老人与海 是哪些作者写的 obj = models.Book.objects.filter(title='老人与海').first() ret = obj.authors.all() print(te) #<QuerySet [<Author: liu>, <Author: song>]> # 循环取值 for i in ret: print(i.name) #liu song # 反向查询 # 查询一下song写了哪些书 obj = models.Author.objects.filter(name='song').first() ret = obj.book_set.all() print(ret) #<QuerySet [<Book: 老人与海>]> # 循环取值 for i in ret: print(i.title) #老人与海 print(i.publish.name) #北大出版社 # 总结: # 通过数据库字段增删改的话,对应写的是对应的id值 # 通过类的属性增删改的话,对应写的是对应的对象
7. 基于双下划线的跨表查询 -- 基于join实现的
-
双下划线方法查询概述
- Django 还提供了一种直观而高效的方式在查询(lookups)中表示关联关系,它能自动确认 SQL JOIN 联系。要做跨关系查询,就使用两个下划线来链接模型(model)间关联字段的名称,直到最终链接到你想要的model 为止。
- 基于双下划线的查询就一句话:正向查询按字段,反向查询按表名小写用来告诉ORM引擎join哪张表,一对一、一对多、多对多都是一个写法,注意,我们写orm查询的时候,哪个表在前哪个表在后都没问题,因为走的是join连表操作。
-
正向查询和反向查询
# 一对一 # 1. 查询二狗的电话号 # 方式1 正向查询 obj = models.Author.objects.filter(name='二狗').values('authorDetail__telephone') print(obj) #<QuerySet [{'authorDetail__telephone': '888'}]> # 方式2 反向查询 obj = models.AuthorDetail.objects.filter(author__name='二狗').values('telephone','author__age') print(obj) #<QuerySet [{'telephone': '888'}]> # 2. 哪个老师的电话是88 # 方式1 正向查询 obj = models.Author.objects.filter(authorDetail__telephone='888').values('name') print(obj) # 方式2 反向查询 obj = models.AuthorDetail.objects.filter(telephone='888').values('author__name') print(obj) # 一对多 # 1.查询一下李老头的故事这本书的出版社是哪个 # 方式1 正向查询 obj = models.Book.objects.filter(title='李老头的故事').values('publishs__name') print(obj) #<QuerySet [{'publishs__name': '李老头出版社'}]> # 方式2 反向查询 obj = models.Publish.objects.filter(book__title='李老头的故事').values('name') obj = models.Publish.objects.filter(xx__title='李老头的故事').values('name') print(obj) # 2.李老头出版社出版了哪些书 # 方式1 反向查询 obj = models.Publish.objects.filter(name='李老头出版社').values('book__title') print(obj) #<QuerySet [{'book__title': '李老头的故事'}, {'book__title': '李老头的故事2'}]> # 方式2 正向查询 obj = models.Book.objects.filter(publishs__name='李老头出版社').values('title') print(obj) #<QuerySet [{'title': '李老头的故事'}, {'title': '李老头的故事2'}]> # 多对多 # 1.李老头的故事这本书是谁写的 # 方式1 正向查询 obj = models.Book.objects.filter(title='李老头的故事').values('authors__name') print(obj) # 方式2 反向查询 obj = models.Author.objects.filter(book__title='李老头的故事').values('name') print(obj) #<QuerySet [{'name': '大狗'}, {'name': '二狗'}]> # 2.大狗写了哪些书 # 方式1 正向查询 obj = models.Book.objects.filter(authors__name='大狗').values('title') print(obj) # 方式2 反向查询 obj = models.Author.objects.filter(name='大狗').values('book__title') print(obj) # 进阶的 # 多表联查 # 1.李老头出版社 出版的书的名称以及作者的名字 obj = models.Book.objects.filter(publishs__name='李老头出版社').values('title','authors__name') print(obj) #结果:<QuerySet [{'title': '李老头的故事', 'authors__name': '大狗'}, {'title': '李老头的故事', 'authors__name': '二狗'}, {'title': '李老头的故事2', 'authors__name': '二狗'}, {'title': '李老头的故事2', 'authors__name': '三狗'}]> ''' sql语句: SELECT app01_book.title,app01_author.name from app01_publish INNER JOIN app01_book on app01_publish.id=app01_book.publishs_id INNER JOIN app01_book_authors on app01_book.nid = app01_book_authors.book_id INNER JOIN app01_author ON app01_author.id = app01_book_authors.author_id where app01_publish.name='李老头出版社'; :param request: :return: ''' obj = models.Publish.objects.filter(name='李老头出版社').values('book__title','book__authors__name') print(obj) obj = models.Author.objects.filter(book__publishs__name='李老头出版社').values('name','book__title') print(obj) # authorDetail author book publish # 2.手机号以4开头的作者出版过的所有书籍名称以及出版社名称 ret = models.AuthorDetail.objects.filter(telephone__startswith='4').values('author__book__title','author__book__publishs__name') print(ret) #QuerySet [{'author__book__title': '李老头的故事', 'author__book__publishs__name': '李老头出版社'}, {'author__book__title': '李老头的故事2', 'author__book__publishs__name': '李老头出版社'}]> # 3.查询一下李老头出版社出版了哪些书 obj = models.Publish.objects.filter(name='李老头出版社').first() print(obj.xx.all())
-
related_name
publish = ForeignKey(Blog, related_name='bookList') # 反向查询时,如果定义了related_name ,则用related_name替换 表名
8. Python脚本中调用Django 环境(Django外部脚本使用models)
-
如果你想通过自己创建的python文件在django项目中使用django的models,那么就需要调用django的环境
import os if __name__ == '__main__': os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BMS.settings") import django django.setup() from app01 import models #引入也要写在上面三句之后 books = models.Book.objects.all() print(books)