#django #foreign-keys #django-queryset
#django #внешние ключи #django-queryset
Вопрос:
У меня есть группа моделей Cluster
, Server
и Service
, которые имеют связь, через ForeignKey, один ко многим, как показано в следующем фрагменте:
class Server(models.Model):
cluster = models.ForeignKey(Cluster, null=True, on_delete=models.PROTECT)
shortname = models.CharField(max_length=20, null=False)
.
.
.
class Service(models.Model):
host_server = models.ForeignKey(Server, null=False, on_delete=models.PROTECT)
name = models.CharField(max_length=20, null=False)
technology = models.CharField(max_length=20, null=False)
.
.
.
И теперь я пытаюсь получить набор Servers
в запросе вместе с соответствующим Services
использованием
def infra(request, cluster_name):
cluster = Cluster.objects.get(name__iexact=cluster_name)
servers = Server.objects.filter(cluster_id=cluster.id).order_by('shortname')
services = Service.objects.filter(host_server__in=servers).order_by('id')
template = 'webapp/infra.html'
context = {
'cluster':cluster,
'servers':servers,
'services':services,
}
return render(request, template, context)
Однако в представлении я получаю все службы в одном наборе запросов вместо набора запросов для каждого, Server
содержащего только Services
связанные с ним.
В качестве обходного пути я использовал следующее:
<h5>Services</h5>
<ul class="list-group">
{% for service in services %}
{% if service.host_server_id == server.id %}
<li class="list-group-item">{{ service.name }}</li>
{% endif %}
{% endfor %}
</ul>
Но у меня такое чувство, что должен быть способ перебирать службы каждого сервера более элегантным способом, чем каждый раз просматривать абсолютно все службы, а затем решать, должно ли это отображаться или нет.
Возможно ли улучшить или этот первоначальный подход правильный?
Спасибо!
Ответ №1:
Определите related_name для своего host_server
поля и используйте обратный менеджер внешних ключей Django, чтобы получить связанные службы для каждого сервера.
ПРИМЕЧАНИЕ: без related_name
обратного менеджера было бы доступно из service_set
models.py
class Service(models.Model):
host_server = models.ForeignKey(Server, null=False, on_delete=models.PROTECT, related_name="services")
views.py
def infra(request, cluster_name):
cluster = Cluster.objects.get(name__iexact=cluster_name)
# we use `prefetch_related` to speedup the query
servers = Server.objects.filter(cluster_id=cluster.id).prefetch_related('services').order_by('shortname')
return render(request, 'webapp/infra.html', {
'cluster':cluster,
'servers':servers,
})
infra.html
<ul class="list-group">
{% for server in servers %}
<li class="list-group-item">{{ server.name }}
<ul>
{% for service in server.services.all %}
<li class="list-item">{{ service.name }}</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
Комментарии:
1. Спасибо! Это определенно то, чего я пытался достичь. Я даже просмотрел ссылку, которую вы упомянули, но пример был не таким понятным, как ваш.