【问题标题】:django distinct in the ListViewsdjango 在 ListViews 中不同
【发布时间】:2018-07-31 04:02:48
【问题描述】:

我在 ListViews 中遇到了一个 distinct 我在“Allergeni”和“Ingredient”之间有一个 M2M 连接,在“Product”和“Ingredient”之间有另一个 M2M,它通过表“Materiali”。

我需要获取一个包含“产品”完整列表的表格,其中包含一个额外字段“过敏原”,其中仅包含原始值中所有值的唯一版本

成分模型:

class Ingredient (models.Model):
    nome = models.CharField(max_length=200)
    categoria = models.ForeignKey("Categoria")
    costokg = models.DecimalField(max_digits=20,decimal_places=2,default=Decimal('0.00'))
    resa = models.IntegerField()
    prezzopulito = models.DecimalField(max_digits=20,decimal_places=3,default=Decimal('0.00'))
    componenti = models.TextField()
    allergeni = models.ManyToManyField("Allergeni", blank=True)

    def __str__(self):
        return self.nome

    def get_absolute_url(self):
        return reverse("ingredients:detail", kwargs={"pk": self.pk})



class Allergeni (models.Model):
    allergene = models.CharField(max_length=100)

产品型号:

class Product (models.Model):
    nome = models.CharField(max_length=250)
    descrizione = models.TextField(blank=True, null=True)
    prezzo = models.DecimalField(max_digits=20,decimal_places=2,default=Decimal('0.00'))
    peso_finale = models.DecimalField(max_digits=20,decimal_places=2,default=Decimal('0.00'))
    categoria = models.ForeignKey("Categoria")
    tag = models.ManyToManyField("Tag", blank=True)
    componenti = models.ManyToManyField(Ingredient, through='Materiali', through_fields=('object_id', 'ingrediente'))
    creazione = models.DateTimeField(auto_now=False, auto_now_add=True)
    aggiornamento = models.DateTimeField(auto_now=True, auto_now_add=False)

    def __str__(self):
        return self.nome

    def get_absolute_url(self):
        return reverse("products:detail", kwargs={"pk": self.pk})

class Materiali (models.Model):
    object_id = models.ForeignKey("Product", on_delete=models.CASCADE)
    ingrediente = models.ForeignKey(Ingredient, on_delete=models.CASCADE, related_name="materia_prima")
    peso = models.DecimalField(max_digits=20,decimal_places=2,default=Decimal('0.00'))


    def __str__(self):
        return self.ingrediente.nome

产品视图

def product_list(request):
    queryset = Product.objects.all() \
        .annotate(total=Round((Sum((F('materiali__ingrediente__prezzopulito')/1000) * F('materiali__peso'))) / (F('peso_finale'))) * 1000 )


    materiali = Materiali.objects.all()

    allergeni= materiali.values_list('ingrediente__allergeni__allergene', flat=True).distinct()

    context = {
        "object_list" : queryset,
        "title": "List",
        "allergeni": allergeni,
    }

    return render(request, "product/product_list.html", context)

代码https://pastebin.com/LcyPF8v8

通过“values_list”,我获得了唯一的值,但没有被 forloop 中的对象过滤,而且我不能使用 TemplateTag,所以如果可能的话,我更喜欢其他选项。

我该怎么做?

最好的,

【问题讨论】:

  • distinct() 方法在使用 Postgresql 数据库时可以正常工作,因为 Django 提供了具有许多选项的 distinct 方法。
  • 我尝试过使用 Postgresql,但我有同样的问题,不同的作品,但它不会在循环期间过滤产品的查询集

标签: python django django-templates django-views distinct-values


【解决方案1】:

你必须修改你的模型:

class Ingredient (models.Model):
    ...
    allergeni = models.ManyToManyField("Allergeni", blank=True, 
                                       related_name="ingredienti")
    ...

class Product (models.Model):
    ...
    componenti = models.ManyToManyField(Ingredient, 
                                        through='Materiali', through_fields=('product', 'ingrediente'), 
                                        related_name="prodotti")
    ...

class Materiali(models.Model):
    ...
    # Don't use object_id this is an object
    product = models.ForeignKey("Product", on_delete=models.CASCADE)
    # use plural for 1..* related_name
    ingrediente = models.ForeignKey(Ingredient, 
                                    on_delete=models.CASCADE, 
                                    related_name="materie_prime") 

    ...

所以在你看来:

def product_list(request):
    queryset = Product.objects.all().annotate(total=Round((Sum((F('materiali__ingrediente__prezzopulito')/1000) * F('materiali__peso'))) / (F('peso_finale'))) * 1000 )
    product_info = {}
    for product in queryset:
        product_allergeni = Allergeni.objects.filter(ingredienti__prodotti=product).values_list('allergene', flat=True)
        product_info.update({product.id:list(product_allergeni)})

    context = {
        "object_list" : queryset,
        "title": "List",
        "product_info": product_info,
    }

    return render(request, "product/product_list.html", context)

在您的模板中,改为:

<ul>
{% for product in object_list %}
<li>
  <p>Product : {{product.name}}</p>
  <ol>Allergeni :
  {% for product_id,allergeni in product_info.items %}
      {% if product_id == product.id %}
          {% for allergene in allergeni %}
            <li>{{ allergene }}</li>
          {% endfor %}
      {% endif %}
  {% endfor %}
  </ol>
</li>
{% endfor %}
</ul>

注意

  1. 要直接访问您的 product_info 字典,您可以使用 this trick:而不是循环每个键、值
  2. 始终使用英文变量,以便非意大利程序员更好地帮助和理解您;)

希望对你有帮助

【讨论】:

    【解决方案2】:

    这样不行吗?

    allergeni= materiali.distinct('ingrediente__allergeni__allergene').values_list('ingrediente__allergeni__allergene', flat=True)
    

    【讨论】:

    • 谢谢,但我使用 mysql,所以我不会像那样使用 .distinct
    【解决方案3】:

    你可以使用pythonset来自动区分数组类型的对象,所以不需要对数组类型的对象使用distinct()。

    allergeni = set(materiali.values_list('ingrediente__allergeni__allergene', flat=True))
    

    基于 Allergeni 的 Foo 过滤产品查询集,您可以在下面使用

    queryset = Product.objects.all() \
            .annotate(total=Round((Sum((F('materiali__ingrediente__prezzopulito')/1000) * F('materiali__peso'))) / (F('peso_finale'))) * 1000 )
    
    materiali = Materiali.objects.all()
    allergeni= materiali.values_list('ingrediente__allergeni__allergene', flat=True).distinct()
    queryset = queryset.filter(materiali__ingrediente__allergeni__in=allergeni)
    

    现在您将获得具有过敏原的独特产品

    【讨论】:

    • 谢谢,我也已经尝试过该解决方案。对于不同的,它可以工作,但它不会在循环期间过滤产品的查询集
    猜你喜欢
    • 2012-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-09
    • 1970-01-01
    • 1970-01-01
    • 2020-03-21
    相关资源
    最近更新 更多