TypeError: int() argument must be a string or a number, not 'Model Instance'
Asked Answered
K

2

6

Here's my models.py:

from django.db import models

class Location(models.Model):
   location_name = models.CharField(max_length=100)
   def __unicode__(self):
      return self.location_name

class Menu(models.Model):
   location = models.ManyToManyField(Location)
   restaurant_name = models.CharField(max_length=200)
   dish_category = models.CharField(max_length=100)
   dish_name = models.CharField(max_length=200)
   VNV_tag = models.CharField(max_length=100)
   quantity = models.CharField(max_length=10, default='FULL')
   price = models.CharField(max_length=5, default=0)
   def __unicode__(self):
       return self.restaurant_name

I am trying to populate my database from an excel file using xlrd python module. Here's my populate_db.py script:

import os
import xlrd
from menusearch.models import Menu, Location
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'midnitepro.settings')
import django
django.setup()

def populate():
    book = xlrd.open_workbook('/Users/Sahil/Desktop/MNFP1.xlsx')
    sheet = book.sheet_by_index(0)
    count1 = 0
    while count1<sheet.nrows:
        value_list = []
        count2 = 0
        while count2<sheet.ncols:
            value_list.append(sheet.row_values(count1, start_colx=count2, end_colx=count2+1))
            count2 +=1
        add_menuitem(value_list)
        count1 += 1

def add_menuitem(value_list):
    split_query = []
    m = Menu.objects.create()
    value_list = [str(x[0]).encode('utf-8') for x in value_list if x]

    m.restaurant_name = (value_list[0])
    m.dish_category = (value_list[1])
    m.dish_name = (value_list[2])
    m.VNV_tag = (value_list[3])
    m.quantity = (value_list[4])
    m.price = (value_list[5])
    # m.location.add(int(value_list[6]))

    split_query = (value_list[6]).split(",")
    for sq in split_query:
        l = Location.objects.get_or_create(location_name=sq)
        try:
            m.location.add(l)
        except ValueError:
            print "Problem Adding Location to Menu."

    m.save()

if __name__ == '__main__':
    print "Starting population script..."
    from menusearch.models import Menu, Location
    populate()

Now when I run the populate_db.py script, the output on the terminal reads: "Problem Adding Location to Menu.". I see that the problem exists here in the populate_db script: m.location.add(l) But this queryset is in line with the syntax given here: https://docs.djangoproject.com/en/1.8/topics/db/examples/many_to_many/

After removing the try/except, my traceback reads:

TypeError: int() argument must be a string or a number, not 'Location' 

Please explain what is happening here. And how to properly add a a value to the ManyToManyField via a queryset.

Possible duplicate: Django Error: TypeError: int() argument must be a string or a number, not 'BuildsTable' But I would still like to know the answer in my case as I'm using a ManyToManyField.

Full traceback:

l= (<Location: Indiranagar>, False)

Inside Loop - sq=  Indiranagar
Traceback (most recent call last):
  File "populate_db.py", line 62, in <module>
populate()
  File "populate_db.py", line 23, in populate
add_menuitem(value_list)
  File "populate_db.py", line 50, in add_menuitem
m.location.add(l)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/fields/related.py", line 973, in add
self._add_items(self.source_field_name, self.target_field_name, *objs)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/fields/related.py", line 1079, in _add_items
'%s__in' % target_field_name: new_ids,
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/query.py", line 679, in filter
return self._filter_or_exclude(False, *args, **kwargs)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/query.py", line 697, in _filter_or_exclude
clone.query.add_q(Q(*args, **kwargs))
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1304, in add_q
clause, require_inner = self._add_q(where_part, self.used_aliases)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1332, in _add_q
allow_joins=allow_joins, split_subq=split_subq,
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1194, in build_filter
lookups, value)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/fields/related.py", line 1745, in get_lookup_constraint
root_constraint.add(lookup_class(targets[0].get_col(alias, sources[0]), value), AND)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/lookups.py", line 96, in __init__
self.rhs = self.get_prep_lookup()
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/lookups.py", line 134, in get_prep_lookup
return self.lhs.output_field.get_prep_lookup(self.lookup_name, self.rhs)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/fields/__init__.py", line 729, in get_prep_lookup
return [self.get_prep_value(v) for v in value]
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/django/db/models/fields/__init__.py", line 985, in get_prep_value
return int(value)
TypeError: int() argument must be a string or a number, not 'Location'.
Kado answered 10/7, 2015 at 18:38 Comment(3)
Please show the full traceback. If you removed the try/except here, I would expect to see an error about a tuple, because get_or_create returns (instance, created).Ferullo
Yes totally, Updated.Kado
l= (<Location: Indiranagar>, False) This is the output from get_or_createKado
S
4

To add a value to a ManyToManyField, you need to add the objects by passing them as arguments.

add(obj1, obj2, obj3, ...)

This will add the specified objects to the related object set.

You can call the add() like below:

menu_object.location.add(loc_obj1, loc_obj2, ...) 

In your case, you need to do:

l = Location.objects.get_or_create(location_name=sq)[0]

You need to access the instance by index 0 as get_or_create returns a tuple (instance, created). Then pass this instance to the add() method.

Note:
Using add() with a many-to-many relationship will not call any .save() for each object, but rather create the relationships using .bulk_create().

Smelt answered 10/7, 2015 at 19:16 Comment(5)
This is exactly what I am doing. Does Not Work.Kado
You are doing m.location.add(int(value_list[6])). Whats value_list[6]? Is it the location objectSmelt
That statement is a comment. That's not what I'm doing. On the other hand I am trying this: m.location.add(l) where l = Location.objects.get_or_create(location_name=sq)Kado
Try this: l = Location.objects.get_or_create(location_name=sq)[0]Smelt
It worked Rahul. Pls edit in the Main answer so I can accept it.Kado
P
4

I understand that Rahul Gupta has answered this already. But on a more theoretical level I think this is what happened when you use get_or_create here:

l = Location.objects.get_or_create(location_name=sq)

It returns a Tuple, and hence you have to call it's first element by modifying it to:

l = Location.objects.get_or_create(location_name=sq)[0]

Which returns only the index element of the tuple/dictionary!

Paragrapher answered 11/7, 2015 at 19:47 Comment(1)
Yup. I agree. This is precisely what is happening.Kado

© 2022 - 2024 — McMap. All rights reserved.