一、中介模型:多對多新增的時候用到中介模型
自己建立的第三張表就屬於是中介模型
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了
為什麼不能這樣做? 這是因為你不能只建立 article和 tag之間的關聯關係,你還要指定 Membership模型中所需要的所有資訊;而簡單的add、create 和賦值語句是做不到這一點的。所以它們不能在使用中介模型的多對多關係中使用。此時,唯一的辦法就是建立中介模型的例項。
remove()方法被禁用也是出於同樣的原因。但是clear() 方法卻是可用的。它可以清空某個例項所有的多對多關係:
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() 方法卻是可用的。它可以清空某個例項所有的多對多關係:
二、優化查詢
簡單使用
對於一對一欄位(OneToOneField)和外來鍵欄位(ForeignKey),可以使用select_related 來對QuerySet進行優化。
select_related 返回一個QuerySet,當執行它的查詢時它沿著外來鍵關係查詢關聯的物件的資料。它會生成一個複雜的查詢並引起效能的損耗,但是在以後使用外來鍵關係時將不需要資料庫查詢。
簡單說,在對QuerySet使用select_related()函式後,Django會獲取相應外來鍵對應的物件,從而在之後需要的時候不必再查詢資料庫了。
下面的例子解釋了普通查詢和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 '''
如果我們使用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");
總結
- select_related主要針一對一和多對一關係進行優化。
- select_related使用SQL的JOIN語句進行優化,通過減少SQL查詢的次數來進行優化、提高效能。
- 可以通過可變長引數指定需要select_related的欄位名。也可以通過使用雙下劃線“__”連線欄位名來實現指定的遞迴查詢。
- 沒有指定的欄位不會快取,沒有指定的深度不會快取,如果要訪問的話Django會再次進行SQL查詢。
- 也可以通過depth引數指定遞迴的深度,Django會自動快取指定深度內所有的欄位。如果要訪問指定深度外的欄位,Django會再次進行SQL查詢。
- 也接受無引數的呼叫,Django會盡可能深的遞迴查詢所有的欄位。但注意有Django遞迴的限制和效能的浪費。
- Django >= 1.7,鏈式呼叫的select_related相當於使用可變長引數。Django < 1.7,鏈式呼叫會導致前邊的select_related失效,只保留最後一個。
三、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']
四、整體插入
建立物件時,儘可能使用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具有多對多關聯。