Django之模型层,单,多表操作(三)

一:多表操作之增、删、改

  1.1:增:

  一对多:

  方式1:

    publish_obj=Publish.objects.get(nid=1)

    book_obj=Book.objects.create(title="海尔兄弟",publishDate="2012-12-12",price=100,publish=publish_obj)

  方式2:

    book_obj=Book.objects.create(title="海尔兄弟",publishDate="2012-12-12",price=100,publish_id=1)

  多对多:

    # 当前生成的书籍对象
    book_obj=Book.objects.create(title="追风筝的人",price=200,publishDate="2012-11-12",publish_id=1)
    # 为书籍绑定的做作者对象
    yuan=Author.objects.filter(name="yuan").first() # 在Author表中主键为2的纪录
    egon=Author.objects.filter(name="alex").first() # 在Author表中主键为1的纪录
    # 绑定多对多关系,即向关系表book_authors中添加纪录
    book_obj.authors.add(yuan,egon)    #  将某些特定的 model 对象添加到被关联对象集合中。

  1.2:删

  book_obj.authors.remove() # 将某个特定的对象从被关联对象集合中去除。 ====== book_obj.authors.remove(*[])

   book_obj.authors.clear() #清空被关联对象集合

 1.3:改 

    set会先清空在设置:

  new_list = [obj1, obj2, obj3]

  e.related_set = new_list

注意:对于所有类型的关联字段,add()、create()、remove()和clear(),set()都会马上更新数据库。换句话说,在关联的任何一端,都不需要再调用save()方法。

 1.4:补充:

  clear() :从关联对象集中移除一切对象。

      b = Blog.objects.get(id=1)

    b.entry_set.clear()

      注意这样不会删除对象 —— 只会删除他们之间的关联。
就像
remove() 方法一样,clear()只能在 null=True的ForeignKey上被调用。
add(obj1[, obj2, ...])
View Code

二:多表操作之查询

  正向查询按字段,反向查询按表明

 2.1:基于对象查询

   一对多正向查询:按字段,publish

# 查询主键为1的书籍的出版社所在的城市
book_obj=Book.objects.filter(pk=1).first()
# book_obj.publish 是主键为1的书籍对象关联的出版社对象
print(book_obj.publish.city)
   一对多反向查询:按表名_set(book_set) 
publish=Publish.objects.get(name="苹果出版社")
#publish.book_set.all() : 与苹果出版社关联的所有书籍对象集合
book_list=publish.book_set.all()    
for book_obj in book_list:
       print(book_obj.title)
  多对多正向查询:正向查询按字段
# python所有作者的名字以及手机号
book_obj=Book.objects.filter(title="python").first()
authors=book_obj.authors.all()
for author_obj in authors:
     print(author_obj.name,author_obj.authorDetail.telephone)

 多对多反向查询:反向查询按表名_set

    # 查询egon出过的所有书籍的名字

    author_obj=Author.objects.get(name="yjp")
    book_list=author_obj.book_set.all()        #与yjp作者相关的所有书籍
    for book_obj in book_list:
        print(book_obj.title)

2.2:基于双下划线查询

 正向查询按字段,反向查询按表名

多对多正向查询:正向查询按字段

    # 正向查询 按字段:authors:
    queryResult=Book.objects.filter(authors__name="yjp").values_list("title")

多对多反向查询:反向查询按字段

 # 反向查询 按表名:book
 queryResult=Author.objects.filter(name="yuan").values("book__title","book__price")

values和values_list区别:

   values():返回QuerySet对象

   values_list():返回list

注意:
反向查询时,如果定义了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")

三:聚合查询和分组查询

  3.1:聚合查询      

from django.db.models import Sum,Avg,Max,Min # 导入分组函数

# 计算所有图书的平均价格,返回{'price__avg': 34.35}
 Book.objects.all().aggregate(Avg('price'))
#计算所有图书的价格,和,最大值,最小值
#返回字典
 Book.objects.aggregate(Sum('price'), Max('price'), Min('price'))

  3.2:分组查询

from django.db.models import Count  #导入分组函数
# 标签列表  通过mldels进行跨表查询,并通过'article_tags'进行分组
# 返回值中 c 就是分组后的值
tag_list=UserInfo.objects.filter(username=username).values(c=Count('article__tags')).values_list('c','article__tags__title')

 四:F查询,Q查询,extra

     4.1:F查询:可以引用当前表内的字段

  在上面所有的例子中,我们构造的过滤器都只是将字段值与某个常量做比较。如果我们要对两个字段的值做比较,那该怎么做呢?Django 提供 F() 来做这样的比较。F() 的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值。

# 查询评论数大于收藏数的书籍
from django.db.models import F
Book.objects.filter(commnetNum__lt=F('keepNum'))

  Django 支持 F() 对象之间以及 F() 对象和常数之间的加减乘除和取模的操作。

# 查询评论数大于收藏数2倍的书籍
 Book.objects.filter(commnetNum__lt=F('keepNum')*2)

  4.2:Q查询:可对查询条件进行 & | ~ 与 或 操作

    filter() 等方法中的关键字参数查询都是一起进行“AND” 的。 如果你需要执行更复杂的查询(例如OR 语句),你可以使用Q 对象

    查询函数可以混合使用Q 对象和关键字参数。所有提供给查询函数的参数(关键字参数或Q 对象)都将"AND”在一起。但是,如果出现Q 对象,它必须位于所有关键字参数的前面。

#
bookList=Book.objects.filter(Q(authors__name="yuan")|Q(authors__name="egon"))
#与和非
bookList=Book.objects.filter(Q(authors__name="yuan") & ~Q(publishDate__year=2017)).values_list("title")
#混合使用
bookList=Book.objects.filter(Q(publishDate__year=2016) | Q(publishDate__year=2017),
                              title__icontains="python"
                             )

   4.3:extra: django提供的sql语句不能进行复杂的操作,extra可以对现有的操作函数进行扩展

    extra源码:

def extra(self, select=None, where=None, params=None, tables=None,
              order_by=None, select_params=None):
        """
        Adds extra SQL fragments to the query.
        """
        assert self.query.can_filter(), \
                "Cannot change a query once a slice has been taken"
        clone = self._clone()
        clone.query.add_extra(select, select_params, where, params, tables, order_by)
        return clone

  extra用法

## select提供简单数据
# SELECT age, (age > 18) as is_adult FROM myapp_person;
Person.objects.all().extra(select={'is_adult': "age > 18"})  # 加在select后面

## where提供查询条件
# SELECT * FROM myapp_person WHERE first||last ILIKE 'jeffrey%';
Person.objects.all().extra(where=["first||last ILIKE 'jeffrey%'"])  # 加一个where条件

## table连接其它表
# SELECT * FROM myapp_book, myapp_person WHERE last = author_last
Book.objects.all().extra(table=['myapp_person'], where=['last = author_last']) # 加from后面

## params添参数
# !! 错误的方式 !!
first_name = 'Joe'  # 如果first_name中有SQL特定字符就会出现漏洞
Person.objects.all().extra(where=["first = '%s'" % first_name])
# 正确方式
Person.objects.all().extra(where=["first = '%s'"], params=[first_name])
View Code

 

 


 

     

  


 
posted @ 2018-12-10 01:54  pyjar  阅读(164)  评论(0编辑  收藏  举报