如何正确查询 Django 中的外键?
How to correctly query to a Foreign Key in Django?
我有一组模型Cluster
、Server
和Service
,它们通过外键一对多建立关系,如下片段:
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)
但是,在视图中,我在单个 QuerySet 中获取 所有服务,而不是每个 Server
的 QuerySet 仅包含 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>
但我觉得必须有一种方法可以更优雅地遍历每个服务器的服务,而不是每次都遍历所有服务然后决定是否应该取消显示。
是否有可能改进或者这个初始方法是否正确?
谢谢!
为您的 host_server
字段定义一个 related_name 并使用 Django's Reverse ForeignKey Manager 为每个服务器获取相关服务。
注意:如果没有 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>
我有一组模型Cluster
、Server
和Service
,它们通过外键一对多建立关系,如下片段:
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)
但是,在视图中,我在单个 QuerySet 中获取 所有服务,而不是每个 Server
的 QuerySet 仅包含 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>
但我觉得必须有一种方法可以更优雅地遍历每个服务器的服务,而不是每次都遍历所有服务然后决定是否应该取消显示。
是否有可能改进或者这个初始方法是否正确?
谢谢!
为您的 host_server
字段定义一个 related_name 并使用 Django's Reverse ForeignKey Manager 为每个服务器获取相关服务。
注意:如果没有 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>