Django基础mysql多表操做

一 建立模型

 表和表之间的关系python

    一对1、多对1、多对多 ,用book表和publish表本身来想一想关系,想一想里面的操做,加外键约束和不加外键约束的区别,一对一的外键约束是在一对多的约束上加上惟一约束。mysql

  实例:咱们来假定下面这些概念,字段和关系git

  做者模型:一个做者有姓名和年龄。sql

  做者详细模型:把做者的详情放到详情表,包含生日,手机号,家庭住址等信息。做者详情模型和做者模型之间是一对一的关系(one-to-one)数据库

  出版商模型:出版商有名称,所在城市以及email。django

  书籍模型: 书籍有书名和出版日期,一本书可能会有多个做者,一个做者也能够写多本书,因此做者和书籍的关系就是多对多的关联关系(many-to-many);一本书只应该由一个出版商出版,因此出版商和书籍是一对多关联关系(one-to-many)。api

  模型创建以下:app

from django.db import models # Create your models here.


class Author(models.Model): #比较经常使用的信息放到这个表里面
    nid = models.AutoField(primary_key=True) name=models.CharField( max_length=32) age=models.IntegerField() # 与AuthorDetail创建一对一的关系,一对一的这个关系字段写在两个表的任意一个表里面均可以
    authorDetail=models.OneToOneField(to="AuthorDetail",to_field="nid",on_delete=models.CASCADE) #就是foreignkey+unique,只不过不须要咱们本身来写参数了,而且orm会自动帮你给这个字段名字拼上一个_id,数据库中字段名称为authorDetail_id。在django 1.xx的版本不须要加(to_field="nid",on_delete=models.CASCADE)默认是级联的
,若是on_delete=models.SET_NULL默认为空。(to="AuthorDetail")要加字符串(引号用反射查找) class AuthorDetail(models.Model):#不经常使用的放到这个表里面
 nid = models.AutoField(primary_key=True) birthday=models.DateField() # telephone=models.BigIntegerField() 
    telephone=models.CharField() addr=models.CharField( max_length=64) class Publish(models.Model): nid = models.AutoField(primary_key=True) name=models.CharField( max_length=32) city=models.CharField( max_length=32) email=models.EmailField()   #CharField--xx@xx.com

#多对多的表关系,咱们学mysql的时候是怎么创建的,是否是手动建立一个第三张表,而后写上两个字段,每一个字段外键关联到另外两张多对多关系的表,orm的manytomany自动帮咱们建立第三张表,两种方式创建关系均可以,之后的学习咱们暂时用orm自动建立的第三张表,由于手动建立的第三张表咱们进行orm操做的时候,不少关于多对多关系的表之间的orm语句方法没法使用 #若是你想删除某张表,你只须要将这个表注销掉,而后执行那两个数据库同步指令就能够了,自动就删除了。
class Book(models.Model): nid = models.AutoField(primary_key=True) title = models.CharField( max_length=32) publishDate=models.DateField() price=models.DecimalField(max_digits=5,decimal_places=2) # 与Publish创建一对多的关系,外键字段创建在多的一方,字段publish若是是外键字段,那么它自动是int类型
    publish=models.ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE) #foreignkey里面能够加不少的参数,都是须要我们学习的,慢慢来,to指向表,to_field指向你关联的字段,不写这个,默认会自动关联主键字段,on_delete级联删除
   字段名称不须要写成publish_id,orm在翻译foreignkey的时候会自动给你这个字段拼上一个_id,这个字段名称在数据库里面就自动变成了publish_id # 与Author表创建多对多的关系,ManyToManyField能够建在两个模型中的任意一个,自动建立第三张表,而且注意一点,你查看book表的时候,你看不到这个字段,由于这个字段就是建立第三张表的意思,不是建立字段的意思,因此只能说这个book类里面有authors这个字段属性
    authors=models.ManyToManyField(to='Author',) #注意不论是一对多仍是多对多,写to这个参数的时候,最后后面的值是个字符串,否则你就须要将你要关联的那个表放到这个表的上面

 

表操做

python提供admin后台管理系统

在django项目下的urlide

访问网页http://127.0.0.1:8000/admin/函数

建立用户

 

用户名:degang

Email:能够为空

Password:密码要求要有复杂度(要有数字,字母,很多于八位)输入两次密码

 

 在django项目下把models导入到admin中,而后重启项目

 

orm 经常使用字段和参数

字段

AutoField  # 主键
CharField  # 字符串
TextField  # 大字符串
IntegerField  # 整形
DateTimeField   DateField   # 日期 日期时间
BooleanField  # 布尔
DecimalField  max_digits=5  decimal_places=2   999.99

参数

null=True 数据库该字段能够为空 blank=True 校验时能够为空 default 默认值 unique 惟一索引 verbose_name 显示的名称 choices=((True, ''), (False, ''))    可选择的参数

 

class Meta(在models设置)

class Meta: # 数据库中生成的表名称 默认 app名称 + 下划线 + 类名
        db_table = "person"

        # admin中显示的表名称
        verbose_name = '我的信息'

        # verbose_name加s
        verbose_name_plural = '全部用户信息'

        # 联合索引
        index_together = [ ("name", "age"),  # 应为两个存在的字段
 ] # 联合惟一索引
        unique_together = (("name", "age"),)  # 应为两个存在的字段

 

 

 

关于多对多表的三种建立方式(目前你先做为了解)

方式一:自行建立第三张表

复制代码
class Book(models.Model):
    title = models.CharField(max_length=32, verbose_name="书名")


class Author(models.Model):
    name = models.CharField(max_length=32, verbose_name="做者姓名")


# 本身建立第三张表,分别经过外键关联书和做者
class Author2Book(models.Model):
    author = models.ForeignKey(to="Author")
    book = models.ForeignKey(to="Book")

    class Meta:
        unique_together = ("author", "book")
复制代码

方式二:经过ManyToManyField自动建立第三张表

复制代码
class Book(models.Model):
    title = models.CharField(max_length=32, verbose_name="书名")


# 经过ORM自带的ManyToManyField自动建立第三张表
class Author(models.Model):
    name = models.CharField(max_length=32, verbose_name="做者姓名")
    books = models.ManyToManyField(to="Book", related_name="authors")
复制代码

方式三:设置ManyTomanyField并指定自行建立的第三张表

复制代码
class Book(models.Model):
    title = models.CharField(max_length=32, verbose_name="书名")


# 本身建立第三张表,并经过ManyToManyField指定关联
class Author(models.Model):
    name = models.CharField(max_length=32, verbose_name="做者姓名")
    books = models.ManyToManyField(to="Book", through="Author2Book", through_fields=("author", "book"))
    # through_fields接受一个2元组('field1','field2'):
    # 其中field1是定义ManyToManyField的模型外键的名(author),field2是关联目标模型(book)的外键名。


class Author2Book(models.Model):
    author = models.ForeignKey(to="Author")
    book = models.ForeignKey(to="Book")

    class Meta:
        unique_together = ("author", "book")
复制代码

  

注意:

  当咱们须要在第三张关系表中存储额外的字段时,就要使用第三种方式。

  可是当咱们使用第三种方式建立多对多关联关系时,就没法使用orm提供的set、add、remove、clear方法来管理多对多的关系了,须要经过第三张表的model来管理多对多关系。

 

to 设置要关联的表。 to_field 设置要关联的字段。 on_delete 同ForeignKey字段。
建立一对一关系字段时的一些参数
to 设置要关联的表 to_field 设置要关联的表的字段 related_name 反向操做时,使用的字段名,用于代替原反向查询时的'表名_set'。 related_query_name 反向查询操做时,使用的链接前缀,用于替换表名。 on_delete 当删除关联表中的数据时,当前表与其关联的行的行为。
建立一对多关系字段时的一些参数
多对多的参数: to 设置要关联的表 related_name 同ForeignKey字段。 related_query_name 同ForeignKey字段。 through 在使用ManyToManyField字段时,Django将自动生成一张表来管理多对多的关联关系。 但咱们也能够手动建立第三张表来管理多对多关系,此时就须要经过 through来指定第三张表的表名。 through_fields 设置关联的字段。 db_table 默认建立第三张表时,数据库中表的名称。 
建立多对多字段时的一些参数
元信息 ORM对应的类里面包含另外一个Meta类,而Meta类封装了一些数据库的信息。主要字段以下: class Author2Book(models.Model): author = models.ForeignKey(to="Author") book = models.ForeignKey(to="Book") class Meta: unique_together = ("author", "book") db_table ORM在数据库中的表名默认是 app_类名,能够经过db_table能够重写表名。db_table = 'book_model' index_together 联合索引。 unique_together 联合惟一索引。 ordering 指定默认按什么字段排序。 ordering = ['pub_date',] 只有设置了该属性,咱们查询到的结果才能够被reverse(),不然是能对排序了的结果进行反转(order_by()方法排序过的数据)
建立表时的一些元信息设置

 

增删改查

一对一

obj=models.AuthorDetail.objects.create( birthday='1979-12-12', telephone='13838338', addr='黑龙江' ) models.Author.objects.create( name='王涛', age=72, # authorDetail=obj,
)
增长方式一
obj1=models.AuthorDetail.objects.filter(addr='山西').first() #取得对象
 models.Author.objects.create( name='b哥', age=63, authorDetail_id=obj1.id )
增长方式二

 

一对多

new_pu=models.Publish.objects.get(id=1) obj=models.Book.objects.create( title='亚索的故事', publishDate='2013-09-12', price=11.1, publish=new_pu, ) print(obj)
方式一
new_pu=models.Publish.objects.get(id=2) models.Book.objects.create( title="箫曲", publishDate='2011-07-04', price=96, publish_id=new_pu.id )
方式二

 

 

多对多

book_obj=models.Book.objects.get(nid=1) print(book_obj) book_obj.authors.add(*[1,2])
方式一
author1 = models.Author.objects.get(id=1) author2 = models.Author.objects.get(id=3) book_obj = models.Book.objects.get(nid=2) book_obj.authors.add(*[author1,author2])
方式二

 

models.AuthorDetail.objects.get(id=6).delete()
一对一
models.Publish.objects.get(id=2).delete() models.Book.objects.get(pk=5).delete()
一对多
book_obj = models.Book.objects.get(nid=4) print(book_obj) book_obj.authors.remove(2) # book_obj.authors.remove(*[5,6]) # book_obj.authors.clear() # book_obj.authors.add(*[1,]) # book_obj.authors.set('1') # book_obj.authors.set(['5','6'])
多对多

多表删除 

URL下

url(r'(\w+)_del/(\d+)/$', views.delete, name='delete')

VIEWS下

def delete(request,table,pk):                      #table 表名 pk 删除的id
    print(table,pk) model_cls=getattr(models,table.capitalize(),)  #capitalize 首字母大写
    model_cls.objects.filter(pk=pk).delete() return redirect(table)

HTML下

<a  class="btn btn-danger btn-sm" id="{{ i.nid }}" href="{% url 'delete' 'author' i.nid %}" >删除</a>

 

 

models.Author.objects.filter(id=3).update( name='壮壮', age=80, authorDetail_id=7, )
一对一
models.Book.objects.filter(pk=1).update( title='b哥的往事3', publishDate='2019-01-01', price='100', publish_id=1. )
一对多

 

多对多

book_obj.authors.remove()      # 将某个特定的对象从被关联对象集合中去除。    ======   book_obj.authors.remove(*[1,2]),将多对多的关系数据删除
book_obj.authors.clear()       #清空被关联对象集合
book_obj.authors.set()         #先清空再设置   =====

 

查(重点)

关系属性(字段)写在哪一个类(表)里面,从当前类(表to)的数据去查询它关联类(表)的数据叫作正向查询,反之叫作反向查询

# 查询
    # 一对一
    # 正向查询
    # 1 查询崔老师的电话号
    author_obj = models.Author.objects.filter(name='崔老师').first() print(author_obj.authorDetail) #辽宁峨眉山
    print(author_obj.authorDetail.telephone) #444
        #2 反向查询
        #2 查询一下这个444电话号是谁的.
    author_detail_obj = models.AuthorDetail.objects.get(telephone='444') print(author_detail_obj.author) #崔老师
    print(author_detail_obj.author.name) #崔老师

    ''' 正向查询:Authorobj.authorDetail,对象.关联属性名称 Author----------------------------------->AuthorDetail <----------------------------------- 反向查询:AuthorDetailobj.author ,对象.小写类名 '''

    # 一对多
    # 查询一下李帅的床头故事这本书的出版社是哪一个
    # 正向查询
    book_obj = models.Book.objects.get(title='李帅的床头故事') print(book_obj.publishs)  # B哥出版社
    print(book_obj.publishs.name)  # B哥出版社

    # B哥出版社出版社出版了哪些书
    # 反向查询
    pub_obj = models.Publish.objects.get(name='B哥出版社') print(pub_obj.book_set.all())  # <QuerySet [<Book: 李帅的床头故事>, <Book: 李帅的床头故事2>]>

    ''' 正向查询 book_obj.publishs 对象.属性 Book ---------------------------------------------> Publish <---------------------------------------------- 反向查询 publish_obj.book_set.all() 对象.表名小写_set '''

    # 多对多
    # 李帅的床头故事这本书是谁写的
    # 正向查询
    book_obj = models.Book.objects.get(title='李帅的床头故事') print(book_obj.authors.all()) # 高杰写了哪些书
    author_obj = models.Author.objects.get(name='高杰') print(author_obj.book_set.all()) ''' 正向查询 book_obj.authors.all() 对象.属性 Book ---------------------------------------------> Author <---------------------------------------------- 反向查询 author_obj.book_set.all() 对象.表名小写_set '''
正向查询和反向查询

 Django 还提供了一种直观而高效的方式在查询(lookups)中表示关联关系,它能自动确认 SQL JOIN 联系。要作跨关系查询,就使用两个下划线来连接模型(model)间关联字段的名称,直到最终连接到你想要的model 为止。

 

'''
    基于双下划线的查询就一句话:正向查询按字段,反向查询按表名小写用来告诉ORM引擎join哪张表,一对1、一对多、多对多都是一个写法,注意,咱们写orm查询的时候,哪一个表在前哪一个表在后都没问题,由于走的是join连表操做。
'''

一对一查询

# 查询yuan的手机号
    
# 正向查询
    ret=Author.objects.filter(name="yuan").values("authordetail__telephone") # 反向查询
    ret=AuthorDetail.objects.filter(author__name="yuan").values("telephone")
一对一查询

一对多查询

# 练习: 查询苹果出版社出版过的全部书籍的名字与价格(一对多) 

# 正向查询 按字段:publish
 queryResult=Book.objects             .filter(publish__name="苹果出版社")  #经过__告诉orm将book表和publish表进行join,而后找到全部记录中publish.name='苹果出版社'的记录(注意publish是属性名称),而后select book.title,book.price的字段值
            .values_list("title","price") #values或者values_list

# 反向查询 按表名:book
 queryResult=Publish.objects               .filter(name="苹果出版社")               .values_list("book__title","book__price")
一对多查询

多对多查询  

# 练习: 查询yuan出过的全部书籍的名字(多对多)

# 正向查询 按字段:authors:
    queryResult=Book.objects             .filter(authors__name="yuan")             .values_list("title") # 反向查询 按表名:book
    queryResult=Author.objects               .filter(name="yuan")               .values_list("book__title","book__price")
多对多查询

进阶练习(连续跨表)

# 练习: 查询人民出版社出版过的全部书籍的名字以及做者的姓名


    # 正向查询
    queryResult=Book.objects             .filter(publish__name="人民出版社")             .values_list("title","authors__name") # 反向查询
    queryResult=Publish.objects               .filter(name="人民出版社")               .values_list("book__title","book__authors__age","book__authors__name") # 练习: 手机号以151开头的做者出版过的全部书籍名称以及出版社名称


    # 方式1:
    queryResult=Book.objects             .filter(authors__authorDetail__telephone__regex="151")             .values_list("title","publish__name") # 方式2: 
    ret=Author.objects .filter(authordetail__telephone__startswith="151") .values("book__title","book__publish__name")
进阶练习(连续跨表)

 

related_name

只能反向查找用

反向查询时,若是定义了related_name ,则用related_name替换 表名,例如:

publish = ForeignKey(Blog, related_name='bookList')
# 练习: 查询人民出版社出版过的全部书籍的名字与价格(一对多)

# 反向查询 再也不按表名:book,而是related_name:bookList
 queryResult=Publish.objects               .filter(name="人民出版社")               .values_list("bookList__title","bookList__price")
related_name

 

聚合查询、分组查询、F查询和Q查询

聚合

 aggregate(*args, **kwargs) # 计算全部图书的平均价格
    >>> from django.db.models import Avg >>> Book.objects.all().aggregate(Avg('price')) #或者给它起名字:aggretate(a=Avg('price'))
    {'price__avg': 34.35}   aggregate()是QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。若是你想要为聚合值指定一个名称,能够向聚合子句提供它。 >>> Book.objects.aggregate(average_price=Avg('price')) {'average_price': 34.35}   若是你但愿生成不止一个聚合,你能够向aggregate()子句中添加另外一个参数。因此,若是你也想知道全部图书价格的最大值和最小值,能够这样查询: >>> from django.db.models import Avg, Max, Min >>> Book.objects.aggregate(Avg('price'), Max('price'), Min('price'))  #count('id'),count(1)也能够统计个数,Book.objects.all().aggregete和Book.objects.aggregate(),均可以
{'price__avg': 34.35, 'price__max': Decimal('81.20'), 'price__min': Decimal('12.99')}
aggregate

 分组

 annotate() 为调用的QuerySet中每个对象都生成一个独立的统计值(统计方法用聚合函数)。 models.Publish.objects.annotate(a=Avg('book__price')).values('a') models.Book.objects.values('publish_id','id').annotate(a=Avg('price')) {'pulish_id':1,'a':11.11} 总结 :跨表分组查询本质就是将关联表join成一张表,再按单表的思路进行分组查询,,既然是join连表,就可使用我们的双下划线进行连表了。
annotate

F查询

from django.db.models import F,Q F 针对本身单表中字段的比较和处理 # good(点赞)comment(评论)

#比较
models.Book.objects.filter(good__gt=F('comment')*2) #修改
models.Book.objects.all().update(price=F('price')+1)
F比较和修改

Q查询

Q 对象可使用&(与) 、|(或)、~(非) 操做符组合起来。当一个操做符在两个Q 对象上使用时,它产生一个新的Q 对象。 bookList=Book.objects.filter(Q(authors__name="yuan")|Q(authors__name="egon")) 你能够组合& 和|  操做符以及使用括号进行分组来编写任意复杂的Q 对象。同时,Q 对象可使用~ 操做符取反,这容许组合正常的查询和取反(NOT) 查询: bookList=Book.objects.filter(Q(authors__name="yuan") & ~Q(publishDate__year=2017)).values_list("title") bookList=Book.objects.filter(Q(Q(authors__name="yuan") & ~Q(publishDate__year=2017))&Q(id__gt=6)).values_list("title") #能够进行Q嵌套,多层Q嵌套等,其实工做中比较经常使用
  查询函数能够混合使用Q 对象和关键字参数。全部提供给查询函数的参数(关键字参数或Q 对象)都将"AND”在一块儿。可是,若是出现Q 对象,它必须位于全部关键字参数的前面。例如:
 bookList=Book.objects.filter(Q(publishDate__year=2016) | Q(publishDate__year=2017), title__icontains="python"  #也是and的关系,可是Q必须写在前面
                             )
Q查询

 

 

 

 

 

ORM执行原生sql语句(了解)

在模型查询API不够用的状况下,咱们还可使用原始的SQL语句进行查询。

  Django 提供两种方法使用原始SQL进行查询:一种是使用raw()方法,进行原始SQL查询并返回模型实例;另外一种是彻底避开模型层,直接执行自定义的SQL语句。

  执行原生查询

    raw()管理器方法用于原始的SQL查询,并返回模型的实例:

    注意:raw()语法查询必须包含主键。

    这个方法执行原始的SQL查询,并返回一个django.db.models.query.RawQuerySet 实例。 这个RawQuerySet 实例能够像通常的QuerySet那样,经过迭代来提供对象实例。

    举个例子:

class Person(models.Model):
    first_name = models.CharField(...)
    last_name = models.CharField(...)
    birth_date = models.DateField(...)

  能够像下面这样执行原生SQL语句

>>> for p in Person.objects.raw('SELECT * FROM myapp_person'):
...     print(p)

  raw()查询能够查询其余表的数据。

    举个例子:

ret = models.Student.objects.raw('select id, tname as hehe from app02_teacher')
    for i in ret:
        print(i.id, i.hehe)

  raw()方法自动将查询字段映射到模型字段。还能够经过translations参数指定一个把查询的字段名和ORM对象实例的字段名互相对应的字典

d = {'tname': 'haha'}
    ret = models.Student.objects.raw('select * from app02_teacher', translations=d)
    for i in ret:
        print(i.id, i.sname, i.haha)

  原生SQL还可使用参数,注意不要本身使用字符串格式化拼接SQL语句,防止SQL注入!

d = {'tname': 'haha'}
    ret = models.Student.objects.raw('select * from app02_teacher where id > %s', translations=d, params=[1,])
    for i in ret:
        print(i.id, i.sname, i.haha)

  直接执行自定义SQL

    有时候raw()方法并不十分好用,不少状况下咱们不须要将查询结果映射成模型,或者咱们须要执行DELETE、 INSERT以及UPDATE操做。在这些状况下,咱们能够直接访问数据库,彻底避开模型层。

    咱们能够直接从django提供的接口中获取数据库链接,而后像使用pymysql模块同样操做数据库。

from django.db import connection, connections
cursor = connection.cursor()  # cursor = connections['default'].cursor()
cursor.execute("""SELECT * from auth_user where id = %s""", [1])
ret = cursor.fetchone()
相关文章
相关标签/搜索