VATSAL JAIN
VATSAL JAIN

Reputation: 581

How to iterate over a particular field of an object of a model in django

This is my models.py:

class Siz(models.Model):
    size=models.CharField(max_length=3,null=True,blank=True)

class Product(models.Model):
    productid=models.CharField(max_length=30)
    size=models.ManyToManyField(Siz)

I have several sizes objects in siz model and I have selected manually for a particular product.(For eg. A product has three different sizes). In my template I want to display the available sizes for every product which I have manually set.I am not able to figure out what to passas context in my views.py so that only the available sizes for that product is displayed in its size select box.

This is my views.py:

def category(request):
    context = {
        'types' : Category.objects.all(),
        'prods': Product.objects.filter(),
        'cartItems':[],
        'size'=Siz.objects.all()
        
    }
    if request.user.is_authenticated:
        customer=request.user.customer
        order, created=Order.objects.get_or_create(customer=customer, complete=False)
        cartItems=order.get_cart_items,     
        items=order.orderitem_set.all()
        context['list_cart'] = order.orderitem_set.values_list('product__id', flat=True)    
    return render(request,"category.html",context)

Currently when I iterate over size in my template it gives me all sizes in my Siz model instead of the ones that are available for the product.This is because I am passing all() . Please help me figure out a way so that for all products I display only the sizes that are available for it.Also how do I iterate over a many to many field in a html select box?

Upvotes: 1

Views: 1320

Answers (3)

Dickson Chibuzor
Dickson Chibuzor

Reputation: 241

I think what you need to do from the question is to iterate over the sizes in the products and you don't need to pass all the sizes in the context unless you need it for some other thing in the template.

{% for obj in prods %}
   <h3> Product: {{ obj.productid }} </h3> <br>
    <select> 
       <option value=''>No size</option>
       {% for s in obj.size.all %}
          <option value={{ s.id }}> {{ s.size }}</option>
       {% endfor %}
    </select> 
{% endfor %}

Upvotes: 1

Roham
Roham

Reputation: 2110

I don't know if I understand your question very well but as far as I know you don't have to add 'size': Siz.objects.all() in your context. You can add nested loop in your template and then for each product obj you can loop through and then show the list of your sizes which is related to that product. Something like following code which goes in your template:

{% for obj in prods %}
    <h3> Product id: {{ obj.id }} </h3> <br>
    {% for s in obj.size.all %}
        <p>{{ s.id }}, {{ s.size }}</p>
        {% endfor %}
    {% endfor %}

Or if you want all the sizes that are used in all of your products (may change based on your needs) and then iterate through them you can use something like following code:

context = {
    'types' : Category.objects.all(),
    'prods': Product.objects.filter(),
    'cartItems':[],
    'sizes': Product.objects.values_list(size__size, flat=True) # or values_list(size__id, flat=True) or .values('id', 'size')
    
}

Now you have access to all sizes that you have used in all of your products and if one of them is not related to any product will not appear in queryset results.

Upvotes: 0

Anthony
Anthony

Reputation: 959

I would recommend your Siz model size field needs to have multiple choice something like:

class Siz(models.Model):
     small = 'Small'
     medium = 'Medium'
     large = 'Large'

    sizeChoices = 
            (small, 'Small'),
            (medium, 'medium'),
            (large, 'large')
 
    size=models.CharField(max_length=6, choices=sizeChoices, null=True, blank=True)

And then in your template just use a template tag for loop...

{% for s in size.size %}
   <p> {{s}} </p>
{% endfor %}

doc: https://docs.djangoproject.com/en/3.0/ref/templates/builtins/#for

Upvotes: 0

Related Questions