django 记录三 orm多表查询

orm多表关系的增删改查


创建数据

from django.db import models


# 作者表
class Author(models.Model):
    nid = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)
    age = models.IntegerField()
    authorDetail = models.OneToOneField(to="AuthorDetail", on_delete=models.CASCADE)      # 作者和作者详细信息 一对一关系
    # 如果不创建nid,mysql会自动创建id,建立联系时候需要添加to_field
    # authorDetail = models.OneToOneField(to="AuthorDetail", to_field="id")

    def __str__(self):
        return self.name


# 作者详细信息表
class AuthorDetail(models.Model):
    nid = models.AutoField(primary_key=True)
    birthday = models.DateField()
    telephone = models.CharField(max_length=32)
    address = models.CharField(max_length=64)

    def __str__(self):
        return self.address


# 出版社
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()

    def __str__(self):
        return self.name


# 书籍表
class Books(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 = models.ForeignKey(to="Publish")               # 一个出版社可出版多本书籍  多对一关系
    authors = models.ManyToManyField(to="Author")           # 一个作者有多本书籍,一本书籍可由多个作者完成  多对多关系
    # authors = models.ManyToManyField(to="Author", through="BookToAuthor",through_fields=("author_id", "book_id"))

    def __str__(self):
        return self.title


# 通过创建第三张表的方式,建立多对多关系,里面可以添加额外字段
# class BookToAuthor(models.Model):
#     book_id = models.ForeignKey(to="Books")
#     author_id = models.ForeignKey(to="Author")
#     other = models.CharField(max_length=32)


 


一对一

# 方式一 作者和作者信息
def add(request):
    author_detail = models.AuthorDetail.objects.create(
        birthday="1990-01-01",
        telephone="18000000000",
        address="恶魔岛",
    )
    models.Author.objects.create(
        name="罗宾",
        age="18",
        authorDetail=author_detail
    )
    return HttpResponse("200")

# 方式二
def add(request):
    obj = models.AuthorDetail.objects.get(address="葫芦岛")
    # obj = models.AuthorDetail.objects.filter(address="冰火岛").first()
    models.Author.objects.create(
        name="葫芦娃",
        age="18",
        authorDetail=obj
    )
    return HttpResponse("200")

# 方式三
def add(request):
    obj = models.AuthorDetail.objects.get(address="蛋糕岛")
    # obj = models.AuthorDetail.objects.filter(address="冰火岛").first()
    models.Author.objects.create(
        name="大妈",
        age="88",
        authorDetail_id=obj.nid
    )
    return HttpResponse("200")

一对多

# 跟一对一方法基本一样  书籍对出版社
def add_book(request):
    obj = models.Publish.objects.get(nid=1)
    models.Books.objects.create(
        title="睡前故事",
        publishDate="2020-07-17",
        price=1.11,
        publish=obj,
        # publish_id=obj.nid  
    ) 
    return HttpResponse("200") 

多对多

# 书和出版社多对多
# 方式一
def add(request):
    book_obj = models.Books.objects.get(nid=1)
    book_obj.authors.add(*[1, 2])
    return HttpRespon("200")

# 方式二
def add(request):
    author1 = models.Author.objects.get(nid=3)
    author2 = models.Author.objects.get(nid=4)
    book = models.Books.objects.get(nid=2)
    book.authors.add(*[author1, author2])
    return HttpRespon("200")

 


# 一对一删除    作者和作者信息表
models.AuthorDetail.objects.get(nid=2).delete()
models.Author.objects.get(nid=3).delete()

# 一对多删除    书籍和出版社表
models.Publish.objects.get(nid=1).delete()
models.Book.objects.get(nid=1).delete()

# 多对多删除    书籍和作者表
book_obj = models.Book.objects.get(nid=6)
# book_obj.authors.remove(6)             # 删除单个
# book_obj.authors.remove(*[5,6])        # 删除多个
book_obj.authors.clear()                 # 删除书籍nid为6的所有信息
book_obj.authors.set('1')                # 删除nid为6的书籍,然后让书籍6和出版社1创建联系
book_obj.authors.set(['5','6'])          # 批量操作
book_obj.authors.add(*[2, 3])            # 为书籍6添加出版社2和3的联系

 

# 一对一
models.Author.objects.filter(pk=5).update(
    name='小崔',
    age=36,
    # authorDetail=models.AuthorDetail.objects.get(pk=5),
    authorDetail_id=4,
)

# 一对多
models.Book.objects.filter(pk=4).update(
    title='往事不堪回首',
    # publishs=models.Publish.objects.get(id=3),
    publishs_id=3,
)

# 多对多
book_obj = models.Book.objects.get(nid=6)
book_obj.authors.set('1')                # 删除nid为6的书籍,然后让书籍6和出版社1创建联系
book_obj.authors.set(['5','6'])          # 批量操作
book_obj.authors.add(*[2, 3])            # 为书籍6添加出版社2和3的联系

 


基于对象的跨表查询——类似于子查询

查询分为正向查询和反向查询,哪张表创建时候关键属性字段创建在哪张表(ForeignKey,OneToOneField、ManyToManyField),去查询另外一张表为正向查询,反之为反向查询

# 如果model中,关键属性字段添加了related_name='xx',则在反向查询时候不能用表明,只能用这个xx

def index(request):
    # 一对一正向查询——查询路飞的生日
    author_obj = models.Author.objects.filter(name="路飞").first()
    print(author_obj.authorDetail.birthday)         # authorDetail为创建关系的字段名

    # 一对一反向查询——已知电话查询是谁
    address_obj = models.AuthorDetail.objects.get(telephone="15000000000")
    print(address_obj.author.name)                  # author为类名(小写)
    return HttpResponse("200")


def index(request):
    # 一对多正向查询——查询python这本书是那个出版社出版的
    book_obj = models.Books.objects.get(title='python')
    print(book_obj.publish.name)

    # 一对多反向查询——查询北京出版社都出了哪些书
    publish_obj = models.Publish.objects.get(name='北京出版社')
    print(publish_obj.books_set.all())              # querySet类型
    return HttpResponse("200")


def index(request):
    # 多对多正向查询——查询金瓶梅这本书都有哪些作者创作
    book_obj = models.Books.objects.get(title="金瓶梅")
    print(book_obj.authors.all())

    # 多对多反向查询——查询罗宾都创作了哪些书籍
    author_obj = models.Author.objects.get(name="罗宾")
    print(author_obj.books_set.all())
    return HttpResponse("200")

基于双下划线的的跨表查询——连表join

# 如果model中,关键属性字段添加了related_name='xx',则在反向查询时候不能用表明,只能用这个xx

def index(request):
    # 一对一正向查询——查询路飞的地址和生日
    author_obj = models.Author.objects.filter(name="路飞").values('authorDetail__address', 'authorDetail__birthday')
    print(author_obj)
    
    # 一对一反向查询——查询路飞的地址和生日
    author_obj = models.AuthorDetail.objects.filter(author__name="路飞").values('address', 'birthday')      # author为类名(小写)
    print(author_obj)
    return HttpResponse("200")


def index(request):
    # 一对多正向查询——查询python这本书是那个出版社出版的
    book_obj = models.Books.objects.filter(title='python').values('publish__name')
    print(book_obj)

    # 一对多反向查询——查询python这本书是那个出版社出版的
    publish_obj = models.Publish.objects.filter(books__title='python').values('name')
    print(publish_obj)
    return HttpResponse("200")


def index(request):
    # 多对多正向查询——查询金瓶梅这本书都有哪些作者创作
    book_obj = models.Books.objects.filter(title="金瓶梅").values('authors__name')
    print(book_obj)
    # 多对多反向查询——查询金瓶梅这本书都有哪些作者创作
    author_obj = models.Author.objects.filter(books__title="金瓶梅").values('name')
    print(author_obj)
    return HttpResponse("200")

# 多于两张表的查询
def index(request):
    # 北京出版社出版的所有书名称和作者名称
    obj = models.Publish.objects.filter(name="北京出版社").values("books__title","books__authors__name")
    print(obj)

    # 手机号以4开头的作者出版过的所有书籍名称以及出版社名称
    ret = models.AuthorDetail.objects.filter(telephone__startswith='4').values('author__book__title','author__book__publishs__name')
    return HttpResponse("200")

聚合的查询

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

def index(request):
    # 查询书籍的平均价格,最大价格,最小价格
    price_dict = models.Books.objects.all().aggregate(Avg('price'), Max('price'), Min('price'))
    # price_dict = models.Books.objects.all().aggregate(a=Avg('price'), m=Max('price'), n=Min('price'))    # 将返回字典的key起别名
    print(price_dict)       # {'price__avg': 76.4, 'price__max': Decimal('188.70'), 'price__min': Decimal('10.00')}
    return HttpResponse("200")

分组查询

def query(request):
    # 统计每个出版社出版书籍的平均价格
    # 方法一
    ret = models.Books.objects.values("publish__nid", "publish__name").annotate(a=Avg("price"))
    print(ret)    # 
    
    # 方法二
    ret = models.Publish.objects.annotate(a=Avg("books__price")).values("name", "a")
    print(ret)        
    return HttpResponse("200")

F查询和Q查询

  • F查询针对自己表中字段的比较和处理
  • Q查询 &、|和~   且、或和取反,如果不用嵌套&优先级高于|
from django.db.models import F,Q


def query(request):
    # books表添加评论和点赞字段
    # 查询books表中 点赞数大于评论数+1的书籍
    ret = models.Books.objects.filter(like__gt=F('comment')+1)
    print(ret)

    # 让books表中的说有书籍价格加20
    models.Books.objects.all().update(price=F('price')+20)
    return HttpResponse("200")


def query(request):
    # 查询评论数大于70的或点赞数小于等于70的书籍
    ret = models.Books.objects.filter(Q(comment__gt=70) | ~Q(like__gt=70))

    # Q还可做嵌套
    # ret = models.Books.objects.filter(Q(Q(comment__gt=70) | Q(like__gt=70)) & Q(price=38))
    print(ret)
    return HttpResponse("200")
# 多个Q查询配置
def customers(request):
    kw = request.GET.get('kw')  # 关键字
    search_field = request.GET.get("search_field")
    if kw:
        q_obj = Q()
        q_obj.connector = 'or'    # 设置多个Q之间关系,default=and
        q_obj.children.append((search_field, kw))    # 将查询条件 k=v 添加到元组中
        customer_list = models.Customer.objects.filter(q_obj)

 

ORM执行原生sql语句

def query(request):
    ret = models.Books.objects.raw('select * from app01_books')
    print(ret)                # 
    for i in ret:
        print(i.publishDate)
    return HttpResponse("200")


from django.db import connection
def query(request):
    cursor = connection.cursor()  # cursor = connections['default'].cursor()
    cursor.execute("""SELECT * from app01_author where nid = %s""", [1])
    ret = cursor.fetchone()
    print(ret)                # (1, '路飞', 18, 1)
    return HttpResponse("200")


# 查看原生sql语句
from django.db import connection
print(connection.queries)

ORM查询的坑——分组

  • 首先确定下mysql的sql_mode里面是否设置了ONLY_FULL_GROUP_BY这个模式
  • 如果没有设置,在查询时候就要注意group by分组的坑
  • group by实际意义是查询分组后的数据或者sql函数(max,min等)用的,不应该查询其他字段
  • 如果查询其他字段会造成不匹配现象,因为分组后,其他字段会从下往下覆盖只取第一条数据

 

事务和锁


  • 行级锁——select_for_update()
  • 可接受参数nowait=True或skip_locked=True,可忽略锁定的行,但是mySql不支持此参数 
# 行级锁——必须用在事务里边——select_for_update()
entries = Entry.objects.select_for_update().filter(author=request.user)  # 加互斥锁,由于mysql在查询时自动加的是共享锁,所以我们可以手动加上互斥锁。create、update、delete操作时,mysql自动加行级互斥锁


  • 全局事务——settings里面ATOMIC_REQUESTS=True
  • 当有请求过来,django会在调用视图方法前开启一个事务。如果正确返回了结果,会提交事务,否则回滚事务
  • 局部事务——装饰器atomic和上下文管理器
# 全局事务settings
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'mxshop',
        'HOST': '127.0.0.1',
        'PORT': '3306',
        'USER': 'root',
        'PASSWORD': '123',
        'OPTIONS': {
            "init_command": "SET default_storage_engine='INNODB'",
       #'init_command': "SET sql_mode='STRICT_TRANS_TABLES'", #配置开启严格sql模式


        }
        "ATOMIC_REQUESTS": True, #全局开启事务,绑定的是http请求响应整个过程
        "AUTOCOMMIT":False, #全局取消自动提交,慎用
    },
  'other':{
    'ENGINE': 'django.db.backends.mysql', 
            ......
  } #还可以配置其他数据库
}

# views
from django.db import transaction

@transaction.non_atomic_requests        # 设置不使用事务处理,针对全局设置
def my_view(request):
    do_stuff()

@transaction.non_atomic_requests(using='other')
def my_other_view(request):
    do_stuff_on_the_other_database()

# 装饰器添加事务
from django.db import transaction

@transaction.atomic
def viewfunc(request):
    # This code executes inside a transaction.
    do_stuff()


# 上下文管理
from django.db import IntegrityError, transaction

@transaction.atomic
def viewfunc(request):
    create_parent()
    try:
        with transaction.atomic():
            generate_relationships()
    except IntegrityError:
        handle_exception()
    add_children()

 

你可能感兴趣的:(web框架,#,django框架)