How to prepare a list for queryset (select2) from multiple m2m filed

Viewed 112

One of my models has three columns which are M2M fields and each of these three M2M fields has different models.

I want to get a dataset from this product attribute model as shown in the output SQU below. And this is the dataset I want to get as the queryset of the model form.

I would be very grateful if someone could give me a little idea on how to do this. Or I'm not sure if the model design is right in the field of getting such a dataset, because I'm brand new to Django.

class ProductAttributes(models.Model):
    product     = models.ForeignKey('Product', blank=True, null=True, on_delete=models.SET_NULL)
    size        = models.ManyToManyField('ProductSize', related_name = "productsize")
    colour      = models.ManyToManyField('ProductColour', related_name="productcolour")
    cupsize     = models.ManyToManyField('ProductCupSize', related_name="productcupsize")

class ProductSize(models.Model):
    name = models.CharField(max_length=10)

class ProductColour(models.Model):
    name = models.CharField(max_length=25)
    colour = models.CharField(max_length=15, blank=True, null=True)

class ProductCupSize(models.Model):
    name = models.CharField(max_length=1)

The way I query data from these three models.

attrs = ProductAttributes.objects.filter(product=product_id).values('product', 'size__name', 'colour__name',
                                                                        'cupsize__name')
        sku = []
        for attr in attrs:
            att = {'id': '-'.join([str(attr['product']), str(attr['size__name']), str(attr['cupsize__name']),
                                   str(attr['colour__name'])]),
                   'text': '-'.join(
                       [str(attr['size__name']), str(attr['cupsize__name']), str(attr['colour__name'])])}
            sku.append(att)

output sku:

[{'id': '108-32-B-Grey', 'text': '32-B-Grey'}, {'id': '108-32-C-Grey', 'text': '32-C-Grey'}, {'id': '108-32-B-White', 'text': '32-B-White'}, {'id': '108-32-C-White', 'text': '32-C-White'}, {'id': '108-34-B-Grey', 'text': '34-B-Grey'}, {'id': '108-34-C-Grey', 'text' : '34-C-Grey'}, {'id': '108-34-B-White', 'text': '34-B-White'}, {'id': '108-34-C-White', 'text': '34-C-White'}]

Updated:

self.fields['product_attr'].queryset = ProductAttributes.objects.filter(product_id=108).values("id").annotate(
                id_dummy=Concat(
                    'product', V('-'), 'size__name', V('-'), 'cupsize__name', V('-'), 'colour__name',
                    output_field=CharField()
                ),
                text=Concat(
                    'size__name', V('-'), 'cupsize__name', V('-'), 'colour__name',
                    output_field=CharField()
                )
            ).values("id_dummy", "text").annotate(id=F('id_dummy')).values_list("id", "text")
1 Answers

You can do that with Concat and Value() expressions

The following code should do what you want:

from django.db.models import CharField, F, Value as V
from django.db.models.functions import Concat

attrs = list(ProductAttributes.objects.values("id").annotate(
    id_dummy=Concat(
        'product', V('-'), 'size__name', V('-'), 'cupsize__name', V('-'), 'colour__name',
        output_field=CharField()
    ),
    text=Concat(
        'size__name', V('-'), 'cupsize__name', V('-'), 'colour__name',
        output_field=CharField()
    )
).values("id_dummy", "text").annotate(id=F('id_dummy')).values_list("id", "text")

In your place i would use django-select2

my_choice = forms.ChoiceField(widget=Select2Widget(attrs={'data-placeholder': 'Your placeholder'}), choices=YOURE_CHOICES, required=False)
Related