2011-02-17 41 views
3

models.pyDjango的最好的外鍵查詢做法

class Category(models.Model): 
    name = models.CharField(max_length=50) 

class SubCatergory(models.Model): 
    parent_category = models.ForeignKey(Category) 
    name = models.CharField(max_length=100) 

views.py

def all_products(request): 
c = Category.objects.all() 
s = SubCatergory.objects.all() 

return render_to_response('all_products.html', 
          {'c':c, 's':s}) 

all_products.html

{% for category in c %} 
    <h1>{{ category.name }}</h1> 
    <ul> 
     {% for sub in s %} 
     {% if category.id == sub.parent_category.id %} 
      <li>{{ sub.name }}</li> 
     {% endif %} 
     {% endfor %} 
    </ul> 
{% endfor %} 

只是想知道如果以上是外鍵的最佳實踐查詢。我在過濾模板級別(如果category.id ==子......),我應該提出這個模型或視圖的水平呢?

回答

5

如果只有一個曾經深度子類別,下面的代碼不應該是一個問題:

{% for category in c %} 
    <h1>{{ category.name }}</h1> 
    <ul> 
     {% for sub in category.subcatergory_set.all %} 
      <li>{{ sub.name }}</li> 
     {% endfor %} 
    </ul> 
{% endfor %} 

但也有一些優化技巧來減少你會做每個循環查詢查詢計數。我正在試着想一個。

其實,我開始認爲這是一個有趣的問題:最佳做法?

你的方法是使用2個查詢。我的方法是使用Django的做法,但做了多個查詢。

爲了防止多個查詢,你實際上必須做你已經在你的模板做在你看來同樣的事情,即遍歷SubCatergory,在蟒蛇拉它們的ID和Category每個ID設置分組到一個屬性。

我不知道這個問題的答案之一。

0

爲什麼不在另一個方向添加引用,以便每個類別都會引用一個SubCategories列表?然後,你就可以寫兩個嵌套的循環:外循環的類別和循環遍歷每個類別中的子類別內循環。

+2

這是正確的想法,但請注意,Django自動爲你做這個。它會自動爲指向模型的每個外鍵創建一個「反向關係」,這是(如果您沒有明確更改它)相關模型的名稱加上「_set」。 請參閱以下鏈接以獲取更多信息: http://docs.djangoproject.com/en/dev/topics/db/queries/#backwards-related-objects – vitorbal 2011-02-17 14:33:52

+0

確實,django爲您提供了一個API來查詢反向關係。如果使用反向關係檢索相關模型,仍然會導致額外的SQL查詢,如果多次執行(即在循環中),這可能會造成巨大的性能下降。爲了避免這種情況,可能需要對關係進行非規範化,以便在上述情況下,可以在每個類別中保存對SubCategories的引用。 – heyman 2011-02-23 11:37:37

2

我認爲這裏的一個好的做法是爲這個工作創建一個模板標籤。這樣你就可以緩存渲染後的模板,並且只能在第一次渲染時觸擊數據庫。

首先,創建模板標籤應用內的

templatetags/show_categories_list.py

from django.core.cache import cache 

@register.simple_tag 
def show_categories_list(): 
    cached = cache.get('CATEGORIES_LIST_CACHE_KEY', None) 
    if cached is None: 
     categories = Category.objects.all() 
     rendered = render_to_string('all_categories.html', {'categories': categories}) 
     cache.set('CATEGORIES_LIST_CACHE_KEY', rendered) 
     return rendered 
    return cached 

然後,創建使用

all_categories.html

{% for category in categories %} 
    <h1>{{ category.name }}</h1> 
    <ul> 
     {% for sub in category.subcategory_set.all %} 
      <li>{{ sub.name }}</li> 
     {% endfor %} 
    </ul> 
{% endfor %} 
模板

覆蓋模型中的保存方法,以便刪除th Ë分類列表緩存條目(迫使它在下一請求被渲染,這也可以被放置在(預|發表)_save信號):

models.py

class Category(models.Model): 
    name = models.CharField(max_length=50) 

    def save(self, *args, **kwargs): 
     cache.delete('CATEGORIES_LIST_CACHE_KEY') 
     return super(Category, self).save(*args, **kwargs) 

class SubCatergory(models.Model): 
    parent_category = models.ForeignKey(Category) 
    name = models.CharField(max_length=100) 

    def save(self, *args, **kwargs): 
     cache.delete('CATEGORIES_LIST_CACHE_KEY') 
     return super(Category, self).save(*args, **kwargs) 

最後使用像這樣:

基數。HTML

{% load show_categories_list %} 
{% show_categories_list %} 

您還可以添加一個超時的緩存條目,所以你不必來覆蓋你的模型的保存方法,但你將不得不等待超時,因此它可以被再次呈現。

的一些有用參考:

http://docs.djangoproject.com/en/1.2/howto/custom-template-tags/#shortcut-for-simple-tags http://docs.djangoproject.com/en/1.2/topics/cache/#the-low-level-cache-api http://docs.djangoproject.com/en/1.2/topics/signals/