Лучшая практика Django с запросами внешнего ключа - PullRequest
3 голосов
/ 17 февраля 2011

models.py

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 == sub ...), я должен вместо этого переместить это на уровень модели или вида?

Ответы [ 3 ]

5 голосов
/ 17 февраля 2011

Если есть только одна глубина подкатегории, следующий код не должен быть проблемой:

{% 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, извлечение их идентификаторов в python и группирование каждого набора идентификатороватрибут Category.

Я не знаю ответа на этот вопрос.

2 голосов
/ 18 февраля 2011

Я думаю, что хорошей практикой здесь будет создание тега шаблона для этой работы. Таким образом, вы можете кэшировать визуализированный шаблон и попадать в базу данных только при первом рендере.

Сначала создайте тег шаблона внутри вашего приложения

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 %}

Переопределите метод сохранения в ваших моделях, чтобы он удалял запись кэша списка категорий (заставляя его отображаться при следующем запросе, его также можно поместить в сигнал (pre | post) _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)

И, наконец, используйте это так:

base.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/

0 голосов
/ 17 февраля 2011

Почему бы вам не добавить ссылку и в другом направлении, чтобы каждая категория ссылалась на список подкатегорий? Затем вы сможете написать два вложенных цикла: внешний цикл для категорий и внутренний цикл для итерации по подкатегориям в каждой категории.

...