Stack Exchange
How to create a product filter, when products are just foreigns keys in attribute class? (Django Ecommerce)
I'm trying to create a product filter that filters on product attributes (like this example), but I have a couple of issues:
The attributes of my products are defined indirectly as a foreign key in a ProductAttributesValue class, which connects a product and an attribute key to an attribute value, i.e.:

class ProductAttributes(models.Model):
    """
    The Product Attributes Table contains product attributes
    or features for the product category.
    """

    product_category = models.ForeignKey(ProductCategory, on_delete=models.RESTRICT)
    name = models.CharField(max_length=255)

    class Meta:
        verbose_name = "Product Attributes"
        verbose_name_plural = "Product Attributes"

class Product(models.Model):  # models.Model
    """
    Product Table
    """

    title       = models.CharField(max_length=255)
    description = models.TextField(blank=True, null=True)
    aff_link    = models.URLField(default="https://designerstuen.dk/")
    image       = models.FileField(null=True, blank=True, upload_to='static/images') #, default='static/images/product-default.png')
    merchant    = models.CharField(max_length=150)
    regular_price = models.DecimalField(
        verbose_name = "Regular price",
        decimal_places = 2,
        max_digits = 1000
        )
    discount_price = models.DecimalField(
        verbose_name = "Discount price",
        decimal_places = 2,
        max_digits = 1000,
        null=True,
        blank=True
        )
    created_at = models.DateTimeField(
        verbose_name = "Created at",
        auto_now_add = True,
        editable = False
    )
    updated_at = models.DateTimeField(
        verbose_name = "Updated at",
        auto_now = True
    )

    categories = TreeManyToManyField('ProductCategory') # on_delete=models.CASCADE, null=True, blank=True   

    class Meta:
        ordering = ("-created_at",)
        verbose_name = "Product"
        verbose_name_plural = "Products"

    def get_absolute_url(self):
        #return f"/products/{self.id}/"
        return reverse("products:product_detail", kwargs={"id": self.id})


class ProductAttributesValue(models.Model):
    """
    The Product Attributes Value Table holds each of the product's
    individual attributes or features.
    """

    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    attribute = models.ForeignKey(ProductAttributes, on_delete=models.RESTRICT)
    value = models.CharField(
        verbose_name = "value",
        max_length = 255
    )


For now, I simply show all associated products on each product category page. Meaning attributes aren't used, yet.

How do I, on the product category pages, create a filter on the product attributes, when they aren't directly defined in the Product class as a model field?

Is this even the optimal way of setting up product attributes? (Categories are set up using MPTT, and I found this attribute implementation through online guides).

An important note is that I want product filtering to be "hard URLs", meaning /red/ instead of ?color=red. This one requires some sort of hierarchy in the filtering, as there must be no duplicate URLs (e.g: /red/hugo-boss and /hugo-boss/red).


Thanks!

are 'red' and 'hugo-boss' both ProductAttributeValues?

edit your question to include Product and ProductAttribute models. It may make it easier to provide you some suggestions for url paths and views.

Yes, red and hugo-boss are both ProductAttributeValues, where "color" and "brand" are the respective ProductAttributes (attributes keys).
I have edited the question to include the two models. Thanks for the feedback!

is there a limit to the number of filters and are they always be in a particular order like /color/brand. If you fix that to a known set this can become fairly easy, but if you want to be able to both /brand/color/size/style and /size/style/color/brand it will get significantly trickier, especially if "red" is a brand and a colour.

Not sure about the limit, but for starters I'm cool with there being a limit, if it is easier to create that way. It definitely makes sense to have a fixed ordering, which also aligns with the last sentence of my point 3 in the post (that I want to avoid duplicate URLs). So sure!
One thing to note: There will be different attributes for each product category, like only "waist size" for jeans - although many will be the same, like color, brand etc.
