中介模型,cbv视图,和查询优化

中介模型:

处理类似搭配 pizza 和 topping 这样简单的多对多关系时,使用标准的ManyToManyField  就可以了。但是,有时你可能需要关联数据到两个模型之间的关系上。

例如,有这样一个应用,它记录音乐家所属的音乐小组。我们可以用一个ManyToManyField 表示小组和成员之间的多对多关系。但是,有时你可能想知道更多成员关系的细节,比如成员是何时加入小组的。

对于这些情况,Django 允许你指定一个中介模型来定义多对多关系。 你可以将其他字段放在中介模型里面。源模型的ManyToManyField 字段将使用through 参数指向中介模型。对于上面的音乐小组的例子,代码如下:

from django.db import models

class Person(models.Model):

    name = models.CharField(max_length=128)

    def __str__(self):              # __unicode__ on Python 2

        return self.name

class Group(models.Model):

    name = models.CharField(max_length=128)

    members = models.ManyToManyField(Person, through=‘Membership‘)

    def __str__(self):              # __unicode__ on Python 2

        return self.name

class Membership(models.Model):

    person = models.ForeignKey(Person)

    group = models.ForeignKey(Group)

    date_joined = models.DateField()

    invite_reason = models.CharField(max_length=64)

既然你已经设置好ManyToManyField 来使用中介模型(在这个例子中就是Membership),接下来你要开始创建多对多关系。你要做的就是创建中介模型的实例:

>>> ringo = Person.objects.create(name="Ringo Starr")

>>> paul = Person.objects.create(name="Paul McCartney")

>>> beatles = Group.objects.create(name="The Beatles")

>>> m1 = Membership(person=ringo, group=beatles,

...     date_joined=date(1962816),

...     invite_reason="Needed a new drummer.")

>>> m1.save()

>>> beatles.members.all()

[<Person: Ringo Starr>]

>>> ringo.group_set.all()

[<Group: The Beatles>]

>>> m2 = Membership.objects.create(person=paul, group=beatles,

...     date_joined=date(196081),

...     invite_reason="Wanted to form a band.")

>>> beatles.members.all()

[<Person: Ringo Starr>, <Person: Paul McCartney>]

与普通的多对多字段不同,你不能使用add、 create和赋值语句(比如,beatles.members = [...])来创建关系:

# THIS WILL NOT WORK

>>> beatles.members.add(john)

# NEITHER WILL THIS

>>> beatles.members.create(name="George Harrison")

# AND NEITHER WILL THIS

>>> beatles.members = [john, paul, ringo, george]

为什么不能这样做? 这是因为你不能只创建 Person和 Group之间的关联关系,你还要指定 Membership模型中所需要的所有信息;而简单的addcreate 和赋值语句是做不到这一点的。所以它们不能在使用中介模型的多对多关系中使用。此时,唯一的办法就是创建中介模型的实例。

remove()方法被禁用也是出于同样的原因。但是clear() 方法却是可用的。它可以清空某个实例所有的多对多关系:

>>> # Beatles have broken up

>>> beatles.members.clear()

>>> # Note that this deletes the intermediate model instances

>>> Membership.objects.all()

[]

blogsystem项目中:我们也是通过创建实例来进行创建关系的代码如下:

def addArticle(request):

if request.method=="POST":        article_form = ArticleForm(request.POST)        if article_form.is_valid():            title=article_form.cleaned_data.get("title")            content=article_form.cleaned_data.get("content")

personal_cate=request.POST.get("personal_cate")            personal_tag=request.POST.getlist("personal_tag")

article_obj=models.Article.objects.create(title=title,desc=content[0:30],create_time=datetime.datetime.now(),user=request.user,category_id=personal_cate)            models.ArticleDetail.objects.create(content=content,article=article_obj)

if personal_tag:  #   [2,3]                for i in personal_tag:                     models.Article2Tag.objects.create(article_id=article_obj.nid,tag_id=i)#在第三张表中自动添加关系

else:            pass

return HttpResponse("添加成功")

article_form=ArticleForm()    cate_list=models.Category.objects.filter(blog__user=request.user)    tag_list=models.Tag.objects.filter(blog__user=request.user)    return render(request,"addArticle.html",{"article_form":article_form,"cate_list":cate_list,"tag_list":tag_list})

惰性查询

查询集 是惰性执行的 —— 创建查询集不会带来任何数据库的访问。你可以将过滤器保持一整天,直到查询集 需要求值时,Django 才会真正运行这个查询。

ret=models.Article.objects.all()这个就不会进入数据库查询print(ret)  就会对数据库进行查询一般来说,只有在“请求”查询集 的结果时才会到数据库中去获取它们。当你确实需要结果时,查询集 通过访问数据库来求值缓存机制:

每个查询集都包含一个缓存来最小化对数据库的访问。理解它是如何工作的将让你编写最高效的代码。

在一个新创建的查询集中,缓存为空。首次对查询集进行求值 —— 同时发生数据库查询 ——Django 将保存查询的结果到查询集的缓存中并返回明确请求的结果(例如,如果正在迭代查询集,则返回下一个结果)。接下来对该查询集 的求值将重用缓存的结果。

请牢记这个缓存行为,因为对查询集使用不当的话,它会坑你的。例如,下面的语句创建两个查询集,对它们求值,然后扔掉它们:

print([a.title for in models.Article.objects.all()])

print([a.create_time for in models.Article.objects.all()])

这意味着相同的数据库查询将执行两次,显然倍增了你的数据库负载。同时,还有可能两个结果列表并不包含相同的数据库记录,因为在两次请求期间有可能有Article被添加进来或删除掉。为了避免这个问题,只需保存查询集并重新使用它:

queryResult=models.Article.objects.all()

print([a.title for in queryResult])

print([a.create_time for in queryResult])

什么时候不会保存缓存?

查询集不会永远缓存它们的结果。当只对查询集的部分进行求值时会检查缓存, 如果这个部分不在缓存中,那么接下来查询返回的记录都将不会被缓存。所以,这意味着使用切片或索引来限制查询集将不会填充缓存。

例如,重复获取查询集对象中一个特定的索引将每次都查询数据库:

>>> queryset = Entry.objects.all()

>>> print queryset[5# Queries the database

>>> print queryset[5# Queries the database again

然而,如果已经对全部查询集求值过,则将检查缓存:

>>> queryset = Entry.objects.all()

>>> [entry for entry in queryset] # Queries the database

>>> print queryset[5# Uses cache

>>> print queryset[5# Uses cache

下面是一些其它例子,它们会使得全部的查询集被求值并填充到缓存中:

>>> [entry for entry in queryset]

>>> bool(queryset)

>>> entry in queryset

>>> list(queryset)

注:简单地打印查询集不会填充缓存。

queryResult=models.Article.objects.all()

print(queryResult) #  hits database

print(queryResult) #  hits database

exists 和iterator

exists:

简单的使用if语句进行判断也会完全执行整个queryset并且把数据放入cache,虽然你并不需要这些 数据!为了避免这个,可以用exists()方法来检查是否有数据:

 if queryResult.exists():
    #SELECT (1) AS "a" FROM "blog_article" LIMIT 1; args=()
        print("exists...")

iterator:

当queryset非常巨大时,cache会成为问题。

处理成千上万的记录时,将它们一次装入内存是很浪费的。更糟糕的是,巨大的queryset可能会锁住系统 进程,让你的程序濒临崩溃。要避免在遍历数据的同时产生queryset cache,可以使用iterator()方法 来获取数据,处理完数据就将其丢弃。

objs = Book.objects.all().iterator()
# iterator()可以一次只从数据库获取少量数据,这样可以节省内存
for obj in objs:
    print(obj.title)
#BUT,再次遍历没有打印,因为迭代器已经在上一次遍历(next)到最后一次了,没得遍历了
for obj in objs:
    print(obj.title)当然,使用iterator()方法来防止生成cache,意味着遍历同一个queryset时会重复执行查询。所以使用#iterator()的时候要当心,确保你的代码在操作一个大的queryset时没有重复执行查询

总结:

queryset的cache是用于减少程序对数据库的查询,在通常的使用下会保证只有在需要的时候才会查询数据库。 使用exists()和iterator()方法可以优化程序对内存的使用。不过,由于它们并不会生成queryset cache,可能 会造成额外的数据库查询。


查询优化

对于一对一字段(OneToOneField)和外键字段(ForeignKey),可以使用select_related 来对QuerySet进行优化。

select_related 返回一个QuerySet,当执行它的查询时它沿着外键关系查询关联的对象的数据。它会生成一个复杂的查询并引起性能的损耗,但是在以后使用外键关系时将不需要数据库查询。

简单说,在对QuerySet使用select_related()函数后,Django会获取相应外键对应的对象,从而在之后需要的时候不必再查询数据库了。

obj_list=models.Article.objects.select_related("user").select_related("category").all()print(obj_list)for i in obj_list:    print(i.category)for i in obj_list:    print(i.title)

cbv视图:

通过类来对应url  通过类里面的方法来对应

views代码:

from django.views import View

class Login(View):

def get(self,request):

return render(request,"login_cbv.html")

def post(self,request):        return HttpResponse("post.........")

def delete(self):        pass
时间: 2024-07-31 11:29:19

中介模型,cbv视图,和查询优化的相关文章

Django 【第二十一篇】中介模型以及优化查询以及CBV模式

一.中介模型:多对多添加的时候用到中介模型 自己创建的第三张表就属于是中介模型 class Article(models.Model): ''' 文章表 ''' title = models.CharField(max_length=64,verbose_name="文章标题") summary = models.CharField(max_length=244, verbose_name="文章概要") create_time = models.DateTimeF

Django-model进阶(中介模型,查询优化,extra,整体插入)

QuerySet 可切片 使用Python 的切片语法来限制查询集记录的数目 .它等同于SQL 的LIMIT 和OFFSET 子句. ? 1 >>> Entry.objects.all()[:5]      # (LIMIT 5) >>> Entry.objects.all()[5:10] # (OFFSET 5 LIMIT 5) 不支持负的索引(例如Entry.objects.all()[-1]).通常,查询集 的切片返回一个新的查询集 —— 它不会执行查询. 可迭代

model进阶(queryset,中介模型,查询优化,extra)

中介模型: 针对多对多关系,虽然可以自动创建关联表,但是需求是想要加入一些字段信息呢,这就需要自己手动建关联表了 对于这些情况,Django 允许你指定一个中介模型来定义多对多关系. 你可以将其他字段放在中介模型里面.源模型的ManyToManyField 字段将使用through 参数指向中介模型 models 1 from django.db import models 2 3 class Person(models.Model): 4 name = models.CharField(max

MVC 模型、视图、控制器

所谓模型,就是在MVC设计模式中需要被显示的数据.在通常情况下,该模型需要从数据库中读取数据.保存模型的状态等,提供数据的访问方法及数据维护. 例如,对于SQL Server中数据库NorthWind的表Products来说,一个Product对象就是一个模型,该对象需要读取数据库中的信息,并对该数据表进行查询.添加.修改等操作.对于一个比较小型的应用程序而言,模型也许只是概念上的,假如一个应用程序需要读取数据,然后显示在用户界面上,而在该应用程序中并不存在一个物理上的数据模型或者相关的类,那么

[.net 面向对象程序设计深入](6).NET MVC 6 —— 模型、视图、控制器、路由等的基本操作

[.net 面向对象程序设计深入](6).NET MVC 6 —— 模型.视图.控制器.路由等的基本操作 1. 使用Visual Studio 2015创建Web App (1)文件>新建>项目,选择Web>ASP.NET Web 应用程序 (2)在新项目MyFirstWebApp对话框中,选择ASP.NET 5模板>Web Application 由于是RC版,这里的”添加单元测试“暂时不能选,上面的WebForms MVC WebAPI将合并,前面一节介绍过了,因此也不需要再选

【ThinkPHP】关于ThinkPHP关联模型和视图模型的一些心得

视图模型更加类似一张表虚拟的表,视图包含一系列带有名称的列和行数据.但是,视图并不在数据库中以存储的数据值集形式存在.行和列数据来自由定义视图的查询所引用的表,并且在引用视图时动态生成.对其中所引用的基础表来说,视图的作用类似于筛选,这是ThinkPHP手册上的说法 其实说白了,视图模型就是mysql多表查询而已,视图模型不支持多表更新,删除 而关联模型是多个表查询以后的结果组合,会多次查询mysql,(在执行完主表查询以后,会有个_after_select)之类的操作,然后组合结果集.在一些情

模型-视图-提供器 模式

随着像Asp.Net和Windows窗体这样的用户界面创建技术越来越强大,让用户界面层做多于它本应做的事是很常见的.没有一个清晰的职责划分,UI层经常沦为一个包含实际上应属于程序其他层的逻辑的容器.有一个称为 模型(Model)-视图(View)-提供器(Presenter)(MVP)的设计模式,特别适合解决这个问题.为了表明我的观点,我将为Northwind数据库中的客户建一个遵循MVP模式的显示屏幕(display screen). 为什么在UI层包含太多的逻辑是很糟糕的?在既不手动运行应用

数据绑定:模型到视图

Object.defineProperty 听说vuejs和avalon都是使用这种方式实现的. Object.defineProperty最早是由IE8实现的,但是IE8的实现有许多问题而且不能hack...所以vuejs才支持IE9+,avalon才使用VBScript这个鬼. 我们可以在Object.defineProperty里用getter和setter方法来定义对象的属性,这个属性叫存储器属性(JavaScript权威指南的翻译,JavaScript高级程序设计翻译为访问器属性,英文

ORM中介模型 + auth模块

ORM中介模型 Django 允许你指定一个中介模型来定义多对多关系. 你可以将其他字段放在中介模型里面.源模型的ManyToManyField 字段将使用through 参数指向中介模型.对于上面的音乐小组的例子,代码如下: 注意:ManyToMany("Student",through="Course_students") ForeignKey("xxx") class student courst id name id name id na