I can't add Many-To-Many relation in Django

Hi guys,

I have 2 models:

models.py:

class Item(models.Model):
    name = models.CharField(max_length=100)
    price = models.FloatField(max_length=20)
    shelfLife = models.BooleanField()
   
    def __str__(self):
        return self.name  

    @property
    def shL(self):
        temp = "Doesnt' have shelf life"
        if(self.shelfLife):
            temp = "Does have sehlf life"
        return temp


class Order(models.Model):
    num = models.CharField(max_length=20)
    date = models.DateField()
    items = models.ManyToManyField(Item)
   
    def __str__(self):
        return self.num 

according to this doc I can do:

views.py:

    elif request.method == "POST":
        list_items = request.POST.getlist('arr[]') # get list of items
        order_num = request.POST.getlist('o_n') # get order num
        order_date = request.POST.getlist('o_d') # get order date 
        
        order = Order(num=order_num[0], date=order_date[0])
        order.save()
        items = Item.objects.filter(name__in=list_items)
        
        order.items.add(*items)

I still get a QuerySet items as an empty QuerySet.
I have checked the request variable list_tems and it is a list of strings (it’s not empty).
I tested it by creating an array of Strings

arr=["Salad", "Chocolate"]

and paste it as a filter

items = Item.objects.filter(name__in=arr)
order.items.add(*items)

to the QuerySet and it works - QuerySet object items is not empty and it writes the right data to the DB.

item = Item.objects.filter(name="Salad")

the returned QuerySet is not empty, however, if I pass a string variable to the name filter it returns an empty QuerySet.

index.html:

 $(document).on('click','.btn-create-order',function(){              
                $.ajax({
                    method: "GET",
                    contentType: "application/json",
                    url: "{% url 'order-items api'  %}", 
                    success: function(data){
                        var index = 1;
                        data.forEach(element => {
                            $('#multyItemSelect').append("<option value='" + index + "' id='" +index+ "'> "+ element['fields'].name+"</option>")
                            index++;
                        });
                    },
                    error: function(jqXHR, textStatus, errorThrown){}
                })        
            })
            $('.order-new-submit').click(function(){
                var order_num = $('#InputNumber').val()
                var order_date = $('#InputDate').val()
                var item_selected = $('#multyItemSelect').val() // number 
                var arr = [] // arr for the item names 
                
                
                var index = 0;
                item_selected.forEach(e => {
                    arr[index] = $('#' + e).html()
                    index++
                });
                console.log(order_date)
                // DEBUGIN
                // arr.forEach(e => {
                //     console.log(e)
                // });
                // END DEBUGIN

                $.ajax({
                    method: "POST",
                    url: "{% url 'order-items api'  %}",
                    data: {'arr[]': arr,
                            'o_n' : order_num,
                            'o_d' : order_date},
                    success: function(data){
       
                    },
                    error: function(jqXHR, textStatus, errorThrown){}
                })
            })

I would appreciate any help!
Thanks

Issue has been found:

print(list_items)

gives me output:

[' Salad', ' Beef Stake ', ' Chocolate']

There is a leading space character in each Item.name

1 Like

I appreciate you posted the solution. It will help one of us down the road. Thank you!

-Jorge

1 Like

Hi! Glad to hear you already solved it!

Just wanted to ask, why are you using *items with an asterisk here?

As I understand items cointains a Queryset of Item objects, but *items unpacks that queryset.


Reading this example from the docs I just learned that in this case it works both with items and *items.

For many-to-many relationships add() accepts either model instances or field values, normally primary keys, as the *objs argument.

item in order.items.add(…) needs to be a model object , or the primary key of that model, but not a queryset. You can however make use of iterable unpacking to pass the items wrapped in the QuerySet as individual parameters with the asterisk here.

I just wrote that sentence knowing that you can’t pass a queryset to add(), but in my head passing the items queryset in your case was correct, therefore I didn’t see the need to unpack it. :man_facepalming: