Django【第26篇】:中介模型以及優化查詢以及CBV模式

中介模型以及優化查詢以及CBV模式

 

1、中介模型:多對多添加的時候用到中介模型css

本身建立的第三張表就屬因而中介模型
複製代碼
class Article(models.Model):
    '''
    文章表
    '''
    title = models.CharField(max_length=64,verbose_name="文章標題")
    summary = models.CharField(max_length=244, verbose_name="文章概要")
    create_time = models.DateTimeField(verbose_name="建立時間",auto_now_add=True)
    update_time = models.DateTimeField(verbose_name="修改時間",auto_now=True)
    up_count = models.IntegerField(verbose_name="點贊數",default=0)
    down_count = models.IntegerField(verbose_name="點滅數",default=0)
    comment_count = models.IntegerField(verbose_name="評論數",default=0)
    read_count = models.IntegerField(verbose_name="閱讀數",default=0)

    user = models.ForeignKey(to="UserInfo",verbose_name="所屬做者",null=True,blank=True)
    classify = models.ForeignKey(to="Classfication",verbose_name="所屬類別",null=True,blank=True)
    tags = models.ManyToManyField(to="Tag",through="Article2tag",through_fields=('article', 'tag'),verbose_name="所屬標籤")
    site_article_category = models.ForeignKey(to="SiteArticleCategory",verbose_name="所屬文章分類",null=True,blank=True)
    class Meta:
        verbose_name_plural = "文章表"
    def __str__(self):
        return self.title




class Tag(models.Model):
    '''標籤表'''
    name = models.CharField(max_length=32,verbose_name="標籤名")
    blog = models.ForeignKey(to="Blog",verbose_name="所屬博客")
    class Meta:
        verbose_name_plural = "標籤表"

    def __str__(self):
        return self.name


class Article2tag(models.Model):
    article = models.ForeignKey(verbose_name="文章",to="Article")
    tag = models.ForeignKey(verbose_name="標籤",to="Tag")
    class Meta:
        verbose_name="文章和標籤關係表"
        '''聯合惟一'''
        unique_together = [
            ("article","tag")
        ]
    def __str__(self):
        return self.article.title + "  "+self.tag.name

像是這樣本身建立的第三張表就屬因而中介模型。通常就Django會給咱們自動建立第三張表,
人家本身建立的只是有關係字段,不能在增長其餘的字段了,
若是根據需求添加其餘字段,不須要ManytoMany本身建立第三張表就本身設置第三張表
這就須要咱們本身去建立第三張表。
固然我如今設計的Article2tag這個第三張表就能夠在裏面添加其餘你須要的字段。
複製代碼

 

若是用了中介模型了,就不能在用add,remove了html

爲何不能這樣作? 這是由於你不能只建立 article和 tag之間的關聯關係,你還要指定 Membership模型中所須要的全部信息;而簡單的addcreate 和賦值語句是作不到這一點的。因此它們不能在使用中介模型的多對多關係中使用。此時,惟一的辦法就是建立中介模型的實例。ajax

 remove()方法被禁用也是出於一樣的緣由。可是clear() 方法倒是可用的。它能夠清空某個實例全部的多對多關係:sql

複製代碼
cate = request.POST.get("cate")
tag = request.POST.getlist("tag")
article_obj = models.Article.objects.create(title=title,summary=content[0:30],create_time=datetime.datetime.now(),user=request.user,classify_id = cate)
models.Article_detail.objects.create(content=content,article=article_obj)
if tag:
  for i in tag:   #[2,4]
      models.Article2tag.objects.create(tag_id=i,article_id=article_obj.id)   #直接從關係表裏面去查
複製代碼

 

remove()方法被禁用也是出於一樣的緣由。可是clear() 方法倒是可用的。它能夠清空某個實例全部的多對多關係:數據庫

2、優化查詢django

簡單使用

對於一對一字段(OneToOneField)和外鍵字段(ForeignKey),可使用select_related 來對QuerySet進行優化。緩存

select_related 返回一個QuerySet,當執行它的查詢時它沿着外鍵關係查詢關聯的對象的數據。它會生成一個複雜的查詢並引發性能的損耗,可是在之後使用外鍵關係時將不須要數據庫查詢。less

簡單說,在對QuerySet使用select_related()函數後,Django會獲取相應外鍵對應的對象,從而在以後須要的時候沒必要再查詢數據庫了。ide

下面的例子解釋了普通查詢和select_related() 查詢的區別。函數

查詢id=2的文章的分類名稱,下面是一個標準的查詢:

 
  
obj = models.Article.objects.get(id=2)
print(obj.classify.title) #走兩次數據庫,基於對象的屬於子查詢,基於雙下劃線的屬於連表查詢

sql是這樣的

1 ''' 2 3 SELECT 4 "blog_article"."nid", 5 "blog_article"."title", 6 "blog_article"."desc", 7 "blog_article"."read_count", 8 "blog_article"."comment_count", 9 "blog_article"."up_count", 10 "blog_article"."down_count", 11 "blog_article"."category_id", 12 "blog_article"."create_time", 13 "blog_article"."blog_id", 14 "blog_article"."article_type_id" 15 FROM "blog_article" 16 WHERE "blog_article"."nid" = 2; args=(2,) 17 18 SELECT 19 "blog_category"."nid", 20 "blog_category"."title", 21 "blog_category"."blog_id" 22 FROM "blog_category" 23 WHERE "blog_category"."nid" = 4; args=(4,) 24 25 26 '''
View Code

 若是咱們使用select_related()函數:

複製代碼
articleList=models.Article.objects.select_related("category").all()
   
 
    for article_obj in articleList:
        #  Doesn't hit the database, because article_obj.category
        #  has been prepopulated in the previous query.
        print(article_obj.category.title)


#查詢全部書的分類標題
obj_list=models.Article.objects.select_related("user").select_related("classify").all()
for obj in obj_list:
print(obj,"2222222",type(obj))
print(obj.classify.title)

# obj_list = models.Article.objects.select_related("user","classify").all()
# for obj in obj_list:
# print(obj.classify.title)
# 要看需求查的數據多很少,若是一次的話就沒有必要了
 
  
複製代碼
1 SELECT 2      "blog_article"."nid", 3      "blog_article"."title", 4      "blog_article"."desc", 5      "blog_article"."read_count", 6      "blog_article"."comment_count", 7      "blog_article"."up_count", 8      "blog_article"."down_count", 9      "blog_article"."category_id", 10      "blog_article"."create_time", 11      "blog_article"."blog_id", 12      "blog_article"."article_type_id", 13  
14      "blog_category"."nid", 15      "blog_category"."title", 16      "blog_category"."blog_id"
17  
18 FROM "blog_article"
19 LEFT OUTER JOIN "blog_category" ON ("blog_article"."category_id" = "blog_category"."nid");
View Code

總結

  1. select_related主要針一對一和多對一關係進行優化。
  2. select_related使用SQL的JOIN語句進行優化,經過減小SQL查詢的次數來進行優化、提升性能。
  3. 能夠經過可變長參數指定須要select_related的字段名。也能夠經過使用雙下劃線「__」鏈接字段名來實現指定的遞歸查詢。
  4. 沒有指定的字段不會緩存,沒有指定的深度不會緩存,若是要訪問的話Django會再次進行SQL查詢。
  5. 也能夠經過depth參數指定遞歸的深度,Django會自動緩存指定深度內全部的字段。若是要訪問指定深度外的字段,Django會再次進行SQL查詢。
  6. 也接受無參數的調用,Django會盡量深的遞歸查詢全部的字段。但注意有Django遞歸的限制和性能的浪費。
  7. Django >= 1.7,鏈式調用的select_related至關於使用可變長參數。Django < 1.7,鏈式調用會致使前邊的select_related失效,只保留最後一個。

3、CBV模式

就是把以前的函數視圖用類實現了

簡單測試一下:

urls.py

#CBV模式
    url(r'^login_cbv/$', views.Login_cbv.as_view()),
注意:這裏的Login_cbv是類名,它必須後面調用as_view()

views.py

複製代碼
from django.views import View
class Login_cbv(View):
   def get(self,request):  #若是是get請求須要執行的代碼
       return render(request,"login_cbv.html")
   def post(self,request): #若是是post請求須要執行的代碼
       return HttpResponse(".....")
   def delete(self,request):
       pass
複製代碼
login_cbv.html
<form action="/login_cbv/" method="post">
    {% csrf_token %}
    姓名:<input type="text">
    <input type="submit">
</form>

對於form表單只支持post和get請求,對於ajax請求支持8種,

http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

4、總體插入

建立對象時,儘量使用bulk_create()來減小SQL查詢的數量。例如:

Entry.objects.bulk_create([ Entry(headline="Python 3.0 Released"), Entry(headline="Python 3.1 Planned") ]) 

...更優於:

Entry.objects.create(headline="Python 3.0 Released") Entry.objects.create(headline="Python 3.1 Planned") 

注意該方法有不少注意事項,因此確保它適用於你的狀況。

這也能夠用在ManyToManyFields中,因此:

my_band.members.add(me, my_friend) 

...更優於:

my_band.members.add(me) my_band.members.add(my_friend) 

...其中Bands和Artists具備多對多關聯。

相關文章
相關標籤/搜索