django-cities-light icon indicating copy to clipboard operation
django-cities-light copied to clipboard

'display_name' and 'name' fields are the same size

Open superzazu opened this issue 8 years ago • 5 comments

Hello,

Currently, if I try to create a City with a name of 200 characters (the max_length for this field), there is an exception raised on creation (DataError). Example :

country = Country.objects.get(code2='FR')
city_name = 'a' * 200
city = City(country=self.country, name=city_name)

city.save() # DataError: value too long for type character varying(200)

It seems to be because display_name and name fields have the same max_length (200), and the display_name consists of the name + the country name. Is there a way to avoid this problem ?

Best regards

superzazu avatar Apr 27 '16 11:04 superzazu

Thanks for your feedback !

Could you post the full traceback please ?

jpic avatar Apr 27 '16 12:04 jpic

Here's the full error:

In [3]: city = City(country=country, name='a' * 250)

In [4]: city.save()
---------------------------------------------------------------------------
DataError                                 Traceback (most recent call last)
/root/.local/lib/python3.4/site-packages/django/db/backends/utils.py in execute(self, sql, params)
     63             else:
---> 64                 return self.cursor.execute(sql, params)
     65 

DataError: value too long for type character varying(200)


The above exception was the direct cause of the following exception:

DataError                                 Traceback (most recent call last)
<ipython-input-4-1ed4f2ba6510> in <module>()
----> 1 city.save()

/root/.local/lib/python3.4/site-packages/django/db/models/base.py in save(self, force_insert, force_update, using, update_fields)
    706 
    707         self.save_base(using=using, force_insert=force_insert,
--> 708                        force_update=force_update, update_fields=update_fields)
    709     save.alters_data = True
    710 

/root/.local/lib/python3.4/site-packages/django/db/models/base.py in save_base(self, raw, force_insert, force_update, using, update_fields)
    734             if not raw:
    735                 self._save_parents(cls, using, update_fields)
--> 736             updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
    737         # Store the database on which the object was saved
    738         self._state.db = using

/root/.local/lib/python3.4/site-packages/django/db/models/base.py in _save_table(self, raw, cls, force_insert, force_update, using, update_fields)
    818 
    819             update_pk = bool(meta.has_auto_field and not pk_set)
--> 820             result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
    821             if update_pk:
    822                 setattr(self, meta.pk.attname, result)

/root/.local/lib/python3.4/site-packages/django/db/models/base.py in _do_insert(self, manager, using, fields, update_pk, raw)
    857         """
    858         return manager._insert([self], fields=fields, return_id=update_pk,
--> 859                                using=using, raw=raw)
    860 
    861     def delete(self, using=None, keep_parents=False):

/root/.local/lib/python3.4/site-packages/django/db/models/manager.py in manager_method(self, *args, **kwargs)
    120         def create_method(name, method):
    121             def manager_method(self, *args, **kwargs):
--> 122                 return getattr(self.get_queryset(), name)(*args, **kwargs)
    123             manager_method.__name__ = method.__name__
    124             manager_method.__doc__ = method.__doc__

/root/.local/lib/python3.4/site-packages/django/db/models/query.py in _insert(self, objs, fields, return_id, raw, using)
   1037         query = sql.InsertQuery(self.model)
   1038         query.insert_values(fields, objs, raw=raw)
-> 1039         return query.get_compiler(using=using).execute_sql(return_id)
   1040     _insert.alters_data = True
   1041     _insert.queryset_only = False

/root/.local/lib/python3.4/site-packages/django/db/models/sql/compiler.py in execute_sql(self, return_id)
   1058         with self.connection.cursor() as cursor:
   1059             for sql, params in self.as_sql():
-> 1060                 cursor.execute(sql, params)
   1061             if not (return_id and cursor):
   1062                 return

/root/.local/lib/python3.4/site-packages/django/db/backends/utils.py in execute(self, sql, params)
     77         start = time()
     78         try:
---> 79             return super(CursorDebugWrapper, self).execute(sql, params)
     80         finally:
     81             stop = time()

/root/.local/lib/python3.4/site-packages/django/db/backends/utils.py in execute(self, sql, params)
     62                 return self.cursor.execute(sql)
     63             else:
---> 64                 return self.cursor.execute(sql, params)
     65 
     66     def executemany(self, sql, param_list):

/root/.local/lib/python3.4/site-packages/django/db/utils.py in __exit__(self, exc_type, exc_value, traceback)
     93                 if dj_exc_type not in (DataError, IntegrityError):
     94                     self.wrapper.errors_occurred = True
---> 95                 six.reraise(dj_exc_type, dj_exc_value, traceback)
     96 
     97     def __call__(self, func):

/root/.local/lib/python3.4/site-packages/django/utils/six.py in reraise(tp, value, tb)
    683             value = tp()
    684         if value.__traceback__ is not tb:
--> 685             raise value.with_traceback(tb)
    686         raise value
    687 

/root/.local/lib/python3.4/site-packages/django/db/backends/utils.py in execute(self, sql, params)
     62                 return self.cursor.execute(sql)
     63             else:
---> 64                 return self.cursor.execute(sql, params)
     65 
     66     def executemany(self, sql, param_list):

DataError: value too long for type character varying(200)

superzazu avatar Apr 27 '16 12:04 superzazu

Thanks a lot for your feedback ! This is very interresting, note that your example code works fine here:

In [1]: from cities_light.models import City, Country

In [2]: country = Country.objects.get(code2='FR')

In [3]: city_name = 'b' * 200

In [4]: city = City(country=country, name=city_name)

In [5]: city.save()
/home/jpic/env/lib/python2.7/site-packages/autoslug/utils.py:31: RuntimeWarning: Argument <type 'str'> is not an unicode object. Passing an encoded string will likely have unexpected results.
  return django_slugify(unidecode(value))


In [6]: City.objects.get(name=city_name).name
Out[6]: u'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'

In [7]: City.objects.get(name=city_name).pk
Out[7]: 23223

In your example, 'a' * 250 is used.

Could you please re-explain what the problem exactly is here ?

Thanks !!

Note that I have nothing against incrementing the size of this column, if we have an actual use case.

jpic avatar Apr 27 '16 21:04 jpic

Hello,

Sorry for the delay. I have been doing a lot of tests, and I can't reproduce the bug with a fresh install of django (with python 2 or python 3). It seems the bug comes from my code, or a migration I wrote. I'll get back to you when I know more about this.

Thank you, Best regards

superzazu avatar May 06 '16 10:05 superzazu

I ran into this issue while using model-mommy to generate fixtures for unit testing. The default Region and City have a pre_save signal that generates the display_name by concatenating the Region+County names, and the City+Region+Country names, respectively. If using max lengths, it results in 400 and 600 chars, way over the max 200. django.db.utils.DataError: value too long for type character varying(200)

Pepedou avatar Sep 26 '18 02:09 Pepedou