django 在 ListViews 中与众不同

django distinct in the ListViews

我在 ListViews 中遇到不同的问题 我在“Allergeni”和“Ingredient”之间有一个 M2M 连接,在“Product”和“Ingredient”之间有另一个 M2M,它通过 table“Materiali”。

我需要获得一个 table,其中包含整个“产品”列表,其中包含一个额外字段“Allergeni”,该字段仅包含原始

中所有值的唯一版本

成分型号:

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,所以如果可能我更喜欢其他选项。

我该怎么做?

最佳,

这样不行吗?

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

您可以使用 set of python 可以自动区分不同的数组类型对象所以不需要使用 distinct()对于数组类型的对象。

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

基于Allergeni的foo filter product queryset,你可以在下面使用

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)

现在您将获得具有 过敏原

的独特产品

您必须修改您的模型:

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>

N.B.

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

希望对你有帮助