Django Prefetch相关问题——正确理解
Django Prefetch Related Issue - Understand it correctly
我确实有以下问题 - 我想在模板中显示所有捆绑包及其组件关系:
这是我的 ORM 模型:
class Component(models.Model):
plenty_var_number = models.CharField(max_length=120, default=None, unique=True, null=True)
plenty_var_id = models.CharField(max_length=120, default=None, unique=True)
description = models.TextField(max_length=1000)
category = models.ForeignKey(Category, on_delete=models.DO_NOTHING, null=False)
updated_at = models.DateTimeField(auto_now=True, null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True, null=True, blank=True)
def __str__(self):
return f"{self.category.name} - {self.plenty_var_number}"
class Bundle(models.Model):
active = models.BooleanField(default=True)
plenty_var_number = models.CharField(max_length=120, default=None, unique=True, null=True)
plenty_var_id = models.CharField(max_length=120, null=True, default=None)
car = models.ForeignKey(Car, on_delete=models.DO_NOTHING)
# m2m defined by BundleComponentRelation
components = models.ManyToManyField(Component, through="BundleComponentRelation")
linked_to_plenty = models.BooleanField(default=False)
price = models.DecimalField(max_digits=10, decimal_places=2, default=-1.00)
updated_at = models.DateTimeField(auto_now=True, null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True, null=True, blank=True)
class BundleComponentRelation(models.Model):
component = models.ForeignKey(Component, on_delete=models.DO_NOTHING)
bundle = models.ForeignKey(Bundle, on_delete=models.DO_NOTHING)
qty = models.IntegerField(default=1)
updated_at = models.DateTimeField(auto_now=True, null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True, null=True, blank=True)
在我看来,我已经尝试过 select_related
和 prefetch_related
,通过上下文将它们传递给模板,以便为我的用户显示它:
html-模板:
{% for bundle in bundles %}
<tr>
<td><p class="fw-bold">{{ bundle.plenty_var_number }}</p></td>
<td>{{ bundle.price }}</td>
<td><p class="fw-bolder mb-0">{{ bundle.car }}</p>
<p class="mb-0">{{ bundle.car.roof_type }}</p>
<p class="mb-0">BJ: {{ bundle.car.production_start }}
- {{ bundle.car.production_end }}</p>
</td>
{# Bundle Component Relations here #}
<td style="font-size: 1em;">
<a href={% url "edit_bundle" bundle.pk %}><i
class="fas fa-xl fa-edit "></i></a>
<a href={% url "sync_bundle" bundle.pk %}><i
class="fas fa-xl fa-sync "></i></a>
</td>
</tr>
{% endfor %}
views.py
def bundle_view(request):
bundles = Bundle.objects.prefetch_related('components').all()
print(bundles[0].components)
return render(request, "all_bundles.html", context={"bundles": bundles})
print(bundles[0].components)
的输出是bundle.Component.None
我理解 select_related
的正向用法,但在我的情况下,我很难理解 prefetch_related
的反向用法。
我认为我的问题是 prefetch_related
的查找语法,但我这里可能是错误的。
我在这里错过了什么?
提前致谢。
编辑
我试过了:
{% for bundle in bundles %}
<tr>
<td><p class="fw-bold">{{ bundle.plenty_var_number }}</p></td>
<td>{{ bundle.price }}</td>
<td><p class="fw-bolder mb-0">{{ bundle.car }}</p>
<p class="mb-0">{{ bundle.car.roof_type }}</p>
<p class="mb-0">BJ: {{ bundle.car.production_start }}
- {{ bundle.car.production_end }}</p>
</td>
{% for comp_rel in bundle.components.all %}
{{ comp_rel }}
{% endfor %}
<td style="font-size: 1em;">
<a href={% url "edit_bundle" bundle.pk %}><i
class="fas fa-xl fa-edit "></i></a>
<a href={% url "sync_bundle" bundle.pk %}><i
class="fas fa-xl fa-sync "></i></a>
</td>
</tr>
{% endfor %}
我只想获取当前迭代包的相关组件。我这里遇到的问题是模板又触发了数据库:
monitoring
简单地使用模板中的 bundle.component
导致
ManyRelatedManager object is not iterable TypError
你的 prefetch_related 没有问题,但是你想要访问这些对象的方式,你应该这样做 bundles[0].components.all()
因为可以使用与 M2M 字段相同的方式访问使用反向关系获取的对象
你确定一定是prefetch_related
吗?我想一定是select_related
.
我认为您应该在模型中使用 Bundle.objects.select_related('components').all()
和 Component.objects.prefetch_related('bundle_set').all()
。但我不确定。
模板错误怎么办 - 您应该在模板中使用 {% for component in bundle.components.all %}
。
和同样的问题,mb会有帮助。
发生这种情况的原因是因为 Component
的 __str__
访问 Category
,因此对于每个 {{ comp_rel }}
,你渲染,它会进行额外的查询.
您应该在与获取 Component
的查询相同的查询中使用 Prefetch
object [Django-doc] 获取 Category
:
from <em>app_name</em>.models import Bundle, Component
from django.db.models import Prefetch
def bundle_view(request):
bundles = Bundle.objects.prefetch_related(
Prefetch('components', Component.objects<strong>.select_related('category')</strong>)
)
return render(request, 'all_bundles.html', {'bundles': bundles})
我确实有以下问题 - 我想在模板中显示所有捆绑包及其组件关系:
这是我的 ORM 模型:
class Component(models.Model):
plenty_var_number = models.CharField(max_length=120, default=None, unique=True, null=True)
plenty_var_id = models.CharField(max_length=120, default=None, unique=True)
description = models.TextField(max_length=1000)
category = models.ForeignKey(Category, on_delete=models.DO_NOTHING, null=False)
updated_at = models.DateTimeField(auto_now=True, null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True, null=True, blank=True)
def __str__(self):
return f"{self.category.name} - {self.plenty_var_number}"
class Bundle(models.Model):
active = models.BooleanField(default=True)
plenty_var_number = models.CharField(max_length=120, default=None, unique=True, null=True)
plenty_var_id = models.CharField(max_length=120, null=True, default=None)
car = models.ForeignKey(Car, on_delete=models.DO_NOTHING)
# m2m defined by BundleComponentRelation
components = models.ManyToManyField(Component, through="BundleComponentRelation")
linked_to_plenty = models.BooleanField(default=False)
price = models.DecimalField(max_digits=10, decimal_places=2, default=-1.00)
updated_at = models.DateTimeField(auto_now=True, null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True, null=True, blank=True)
class BundleComponentRelation(models.Model):
component = models.ForeignKey(Component, on_delete=models.DO_NOTHING)
bundle = models.ForeignKey(Bundle, on_delete=models.DO_NOTHING)
qty = models.IntegerField(default=1)
updated_at = models.DateTimeField(auto_now=True, null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True, null=True, blank=True)
在我看来,我已经尝试过 select_related
和 prefetch_related
,通过上下文将它们传递给模板,以便为我的用户显示它:
html-模板:
{% for bundle in bundles %}
<tr>
<td><p class="fw-bold">{{ bundle.plenty_var_number }}</p></td>
<td>{{ bundle.price }}</td>
<td><p class="fw-bolder mb-0">{{ bundle.car }}</p>
<p class="mb-0">{{ bundle.car.roof_type }}</p>
<p class="mb-0">BJ: {{ bundle.car.production_start }}
- {{ bundle.car.production_end }}</p>
</td>
{# Bundle Component Relations here #}
<td style="font-size: 1em;">
<a href={% url "edit_bundle" bundle.pk %}><i
class="fas fa-xl fa-edit "></i></a>
<a href={% url "sync_bundle" bundle.pk %}><i
class="fas fa-xl fa-sync "></i></a>
</td>
</tr>
{% endfor %}
views.py
def bundle_view(request):
bundles = Bundle.objects.prefetch_related('components').all()
print(bundles[0].components)
return render(request, "all_bundles.html", context={"bundles": bundles})
print(bundles[0].components)
的输出是bundle.Component.None
我理解 select_related
的正向用法,但在我的情况下,我很难理解 prefetch_related
的反向用法。
我认为我的问题是 prefetch_related
的查找语法,但我这里可能是错误的。
我在这里错过了什么?
提前致谢。
编辑
我试过了:
{% for bundle in bundles %}
<tr>
<td><p class="fw-bold">{{ bundle.plenty_var_number }}</p></td>
<td>{{ bundle.price }}</td>
<td><p class="fw-bolder mb-0">{{ bundle.car }}</p>
<p class="mb-0">{{ bundle.car.roof_type }}</p>
<p class="mb-0">BJ: {{ bundle.car.production_start }}
- {{ bundle.car.production_end }}</p>
</td>
{% for comp_rel in bundle.components.all %}
{{ comp_rel }}
{% endfor %}
<td style="font-size: 1em;">
<a href={% url "edit_bundle" bundle.pk %}><i
class="fas fa-xl fa-edit "></i></a>
<a href={% url "sync_bundle" bundle.pk %}><i
class="fas fa-xl fa-sync "></i></a>
</td>
</tr>
{% endfor %}
我只想获取当前迭代包的相关组件。我这里遇到的问题是模板又触发了数据库:
monitoring
简单地使用模板中的 bundle.component
导致
ManyRelatedManager object is not iterable TypError
你的 prefetch_related 没有问题,但是你想要访问这些对象的方式,你应该这样做 bundles[0].components.all()
因为可以使用与 M2M 字段相同的方式访问使用反向关系获取的对象
你确定一定是prefetch_related
吗?我想一定是select_related
.
我认为您应该在模型中使用 Bundle.objects.select_related('components').all()
和 Component.objects.prefetch_related('bundle_set').all()
。但我不确定。
模板错误怎么办 - 您应该在模板中使用 {% for component in bundle.components.all %}
。
和
发生这种情况的原因是因为 Component
的 __str__
访问 Category
,因此对于每个 {{ comp_rel }}
,你渲染,它会进行额外的查询.
您应该在与获取 Component
的查询相同的查询中使用 Prefetch
object [Django-doc] 获取 Category
:
from <em>app_name</em>.models import Bundle, Component
from django.db.models import Prefetch
def bundle_view(request):
bundles = Bundle.objects.prefetch_related(
Prefetch('components', Component.objects<strong>.select_related('category')</strong>)
)
return render(request, 'all_bundles.html', {'bundles': bundles})