#django #django-models
#django #django-модели
Вопрос:
Моя модель данных проста:
class Neighborhood(models.Model):
name = models.CharField(max_length = 50)
slug = models.SlugField()
class Location(models.Model):
company = models.ForeignKey(Company)
alt_name = models.CharField()
neighborhoods = models.ManyToManyField(Neighborhood)
Я хотел бы предоставить страницу на своем сайте, в которой перечислены все местоположения по их окрестностям. Если бы это было единственное число, я думаю {% regroup %}
, что с помощью a {% ifchanged %}
, примененного к названию района, было бы все, что мне нужно, но в моем случае, если это будет m2m, я не уверен, как это сделать. Местоположение может иметь несколько окрестностей, и поэтому я бы хотел, чтобы они отображались избыточно в каждом соответствующем районе.
Я также знаю FOO_set
, но это для каждого объекта; Я хочу загрузить весь набор данных.
Конечный результат (в шаблоне) должен быть примерно таким:
Alameda
Crazy Thai
Castro
Kellys Burgers
Pizza Orgasmica
Filmore
Kellys Burgers
Some Jazz Bar
Mission
Crazy Thai
Elixir
...
Синтаксис шаблона (в идеале?) выглядит примерно так:
{% for neighborhood in neighborhood_list %}
{% ifchanged %}{{ neighborhood.name }}{% endifchanged %}
{% for location in neighborhood.restaurants.all %}
{{ location.name }}
{% endfor %}
{% endfor %}
Комментарии:
1. что мешает вам поместить поле m2m, указывающее на компании, в тип вашего района?
2. Я мог бы, но Location уже присвоено соседство. Я должен быть в состоянии получить обратное отношение. Я думаю, что мне поможет что-то вроде deafaultdict, но я запутался…
3. если я не неправильно понял вопрос, я думаю, вы можете Location.objects.order_by(‘окрестности__name’)
4. это упорядочило бы окрестности внутри каждого объекта, но не глобально.
5. о, это только что пришло мне в голову. вы можете использовать сквозную модель. Я добавил ответ.
Ответ №1:
Я бы просто сделал это самым дорогим способом и спрятал результат, а не ломал голову. Ваш пример шаблона будет работать нормально до тех пор, пока производительность не станет проблемой при генерации этой одной страницы за X тайм-аута кэша.
Вы могли бы сделать это и на python, если результирующий набор достаточно мал:
# untested code - don't have your models
from collections import defaultdict
results = defaultdict(list)
for location_m2m in Location.neighborhoods.through.objects.all() # line wrap
.select_related('neighborhood', 'location', 'location__company__name'):
if location_m2m.location not in results[location_m2m.neighborhood]:
results[location_m2m.neighborhood].append(location_m2m.location)
# sort now unique locations per neighborhood
map(lambda x: x.sort(key=lambda x: x.location.company.name), results.values())
# sort neighborhoods by name
sorted_results = sorted(results.items(), key=lambda x:x[0].name)
Комментарии:
1. Ага. Идеальный. Я собираюсь рассмотреть этот и другой вариант и взвесить их. Мне определенно не нравится тратить время на то, чтобы почесать голову, поэтому я посмотрю, смогу ли я это сделать сейчас. Оно того стоит. Еще раз спасибо за пример, относящийся к моим моделям.
2. Для меня это хорошо работает. Теперь у меня есть список, отображаемый так, как я хотел бы. Однако я не сортирую по
company.name
, поэтому я просто убрал это. Это нарушает сортировку.Location
Имеет локальное поле,alt_name
но при замене company.name в некоторых случаях, связанных с этим, я получаю ошибки. Не уверен, почему. Однако запрос правильный — и это кажется / потрясающим /.3. Эй, эй, классные бобы! В чем ошибка? Можете ли вы повторно опубликовать то, что вы пытаетесь?
4. dpaste.com/640425 При каждой перезагрузке страницы порядок, по-видимому, отображается в случайном порядке.
5. Хорошо, я обнаруживаю ошибку: попробуйте изменить последнюю строку сортировки на
key=lambda x:x[0].id
— вам нужно отсортировать окрестности по /something/ . В моем тестировании, если вы попытаетесь отсортировать набор запросов без аргументов, он изменится.
Ответ №2:
создайте другую модель, которая определяла бы ваши отношения m2m:
class ThroughModel(models.Model):
location = models.ForeignKey('Location')
neighborhood = models.ForeignKey('Neighborhood')
и используйте его в качестве through
модели для вашего поля m2m:
class Location(models.Model): ... neighborhoods = models.ManyToManyField(Neighborhood, through='ThroughModel')
Затем вы можете отсортировать все свои окрестности:
ThroughModel.objects.select_related().order_by('neighborhood__name')
Это непроверено.
Или, если вы не можете изменить базу данных, просто выполните необработанное SQL-соединение.
Комментарии:
1. Разве я не могу просто что-то сделать в представлении? Мне кажется странным создавать другую таблицу только для того, чтобы получить запрос, который требуется. Я вижу в этом преимущество, возможно, в новом проекте, но не в этом. Если бы это было отдельное соседство, никаких проблем. Это было бы очень похоже на то, как мы перечисляем сообщения в блоге, соответствующие определенной категории. Что-то вроде
Location.objects.filter(neighborhoods__slug = slug)
. Я считаю, что я хочу выполнить итерацию по каждому объекту location на одной странице / словаре. Вот почему я подумал, что, возможноcollections.defaultdict
, это будет ключом (хех).2. промежуточная таблица создается в любом случае, вы просто не видите ее в коде django, но она есть в базе данных. между моей сквозной моделью и реализацией m2m по умолчанию нет внутренней разницы.
3. Могу ли я просто ретроактивно добавить through() в поле моей модели или South может мне помочь?
4. Я думаю, что лучше использовать South, если у вас есть данные в вашей производственной базе данных.
5. но если вы можете просто использовать
.through()
, как показано в другом ответе, зачем мне уходить с пути, чтобы вручную создать это через tabel?