【问题标题】:Django how to generate a filtered querysetDjango如何生成过滤的查询集
【发布时间】:2021-08-11 13:53:05
【问题描述】:

我有 2 个模型。资产和资产类型。在我的资产类型详细视图中,我想列出该资产类型的所有资产。我想我必须使用 models.Asset.queryset().filter() 但我无法让它工作。

在我的模板上,我想用“for”循环遍历列表(例如:列表中的对象)并打印像这样的值 {{ object.name }}

models.py

    class Asset(models.Model):
    
        # Relationships
        room = models.ForeignKey("asset_app.Room", on_delete=models.SET_NULL, blank=True, null=True)
        model_hardware = models.ForeignKey("asset_app.Model_hardware", on_delete=models.SET_NULL, blank=True, null=True)
    
        # Fields
        name = models.CharField(max_length=30)
        serial = models.CharField(max_length=30, unique=True, blank=True, null=True, default=None)
        mac_address = models.CharField(max_length=30, null=True, blank=True)
        purchased_date = models.DateField(null=True, blank=True)
        may_be_loaned = models.BooleanField(default=False, blank=True, null=True)
        notes = models.TextField(max_length=448, null=True, blank=True)
        ip = models.CharField(max_length=90, null=True, blank=True)
        created = models.DateTimeField(auto_now_add=True, editable=False)
        last_updated = models.DateTimeField(auto_now=True, editable=False)
    
        class Meta:
            ordering = ["name"]
    
        def __str__(self):
            return str(self.name)
    
        def get_absolute_url(self):
            return reverse("asset_app_asset_detail", args=(self.pk,))
    
        def get_update_url(self):
            return reverse("asset_app_asset_update", args=(self.pk,))
    
    
    class Asset_type(models.Model):
    
        # Fields
        name = models.CharField(max_length=30)
        last_updated = models.DateTimeField(auto_now=True, editable=False)
        created = models.DateTimeField(auto_now_add=True, editable=False)
        notes = models.TextField(max_length=448, null=True, blank=True)
    
        class Meta:
            ordering = ["name"]
    
        def __str__(self):
            return str(self.name)
    
        def get_absolute_url(self):
            return reverse("asset_app_asset_type_detail", args=(self.pk,))
    
        def get_update_url(self):
            return reverse("asset_app_asset_type_update", args=(self.pk,))

class Model_hardware(models.Model):

    # Relationships
    asset_type = models.ForeignKey("asset_app.Asset_type", on_delete=models.SET_NULL, blank=True, null=True)
    brand = models.ForeignKey("asset_app.Brand", on_delete=models.SET_NULL, blank=True, null=True)

    # Fields
    name = models.CharField(max_length=30)
    notes = models.TextField(max_length=448, null=True, blank=True)
    created = models.DateTimeField(auto_now_add=True, editable=False)
    last_updated = models.DateTimeField(auto_now=True, editable=False)

    class Meta:
        ordering = ["name"]

    def __str__(self):
        return str(self.name) + " :: " + str(self.brand.name) + " :: " + self.asset_type.name

    def get_absolute_url(self):
        return reverse("asset_app_model_hardware_detail", args=(self.pk,))

    def get_update_url(self):
        return reverse("asset_app_model_hardware_update", args=(self.pk,))

views.py

class Asset_typeDetailView(generic.DetailView):
    model = models.Asset_type
    form_class = forms.Asset_typeForm

【问题讨论】:

  • Retrieving specific objects with filters 指南可能对您有所帮助。
  • AssetAsset_type 之间没有关系吗?你需要一个从AssetAsset_typeForeignKey
  • @AbdulAzizBarkat 我忘了给你看 Model_hardware(models.Model) 类

标签: django filter django-queryset


【解决方案1】:

您可以使用默认的相关名称简单地迭代模板中的相关对象,该名称是小写的模型名称,附加_set。因此,asset_type.model_hardware_set.all() 将为您提供与 Asset_type 相关的所有 Model_hardware 实例,model_hardware.asset_set.all() 也是如此:

{% for model_hardware object.model_hardware_set.all %}
    {% for asset in model_hardware.asset_set.all %}
        {{ asset.name }}
    {% endfor %}
{% endfor %}

但这可能会变得很慢,因为我们遇到了 N + 1 问题,我们将针对每个模型硬件进行查询以获取其资产。我们可以在您的模型实例上使用prefetch_related_objects 来预取所有相关对象(在更少的查询中)并使其更快:

from django.db.models import prefetch_related_objects
from django.views.generic import DetailView


class YourDetailView(DetailView):
    model = Asset_type
    template_name = '<your_template_name>.html'
    
    def get_object(self, queryset=None):
        obj = super().get_object(queryset=queryset)
        prefetch_related_objects([obj], 'model_hardware__asset')
        return obj

注意:python中的类名最好是PascalCase而不是Some_case(不要认为有任何这样的约定 这里),因此 ModelHardware 而不是 Model_hardwareAssetType 而不是 Asset_type 会是更好的名字。

【讨论】:

  • 我会更正我的班级名称。感谢您的提示:-)
  • 如果我不能通过这样做来订购我的查询集:obj = super().get_object(queryset=queryset.order_by('asset_type','brand','model_hardware','name' ))
  • @Reventlow 是的,您可以这样做,或者您可以根据需要覆盖get_queryset(尽管按 4 列排序?请注意按顺序添加的列越多,数据库的工作量就越大必须做的)
猜你喜欢
  • 2016-02-01
  • 2014-04-18
  • 2018-12-19
  • 2020-08-22
  • 2019-04-15
  • 2011-09-29
相关资源
最近更新 更多