Django | Factory boy | faking a boolean field | django.db.utils.DataError: value too long for type character varying(1)
Asked Answered
P

3

6

I am trying to use factory boy to generate fake entries but I'm stepping on an issue related with the boolean field.

Follows the Model and ModelFactory:

# models.py

class Record(models.Model):
    date_creation = models.DateTimeField()
    rec_type = models.CharField(max_length=1, choices=RECORD_TYPES)
    direction = models.BooleanField()
# factories.py

class RecordFactory(DjangoModelFactory):

    class Meta:
        model = Record

    date_creation = factory.Faker('date_time')
    rec_type = factory.Faker('random_choices', elements=[x[1] for x in Record.RECORD_TYPES])
    direction = factory.Faker('pybool')

How do I fix this issue? Seems to be related with the boolean field.

/usr/local/lib/python3.7/site-packages/django/db/models/fields/__init__.py:1427: RuntimeWarning: DateTimeField Record.date_creation received a naive datetime (1
977-11-24 14:21:26) while time zone support is active.
  RuntimeWarning)
Traceback (most recent call last):
  File "/usr/local/lib/python3.7/site-packages/django/db/backends/utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
psycopg2.errors.StringDataRightTruncation: value too long for type character varying(1)


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

Traceback (most recent call last):
  File "manage.py", line 30, in <module>   
    execute_from_command_line(sys.argv)
  File "/usr/local/lib/python3.7/site-packages/django/core/management/__init__.py", line 381, in execute_from_command_line
    utility.execute()
  File "/usr/local/lib/python3.7/site-packages/django/core/management/__init__.py", line 375, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/usr/local/lib/python3.7/site-packages/django/core/management/base.py", line 323, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/usr/local/lib/python3.7/site-packages/django/core/management/base.py", line 364, in execute
    output = self.handle(*args, **options) 
File "/app/iur/core/management/commands/seed.py", line 60, in handle
    self.create(options["records"], RecordFactory)
  File "/app/iur/core/management/commands/seed.py", line 47, in create
    factory_class.create()
  File "/usr/local/lib/python3.7/site-packages/factory/base.py", line 564, in create
    return cls._generate(enums.CREATE_STRATEGY, kwargs)
  File "/usr/local/lib/python3.7/site-packages/factory/django.py", line 141, in _generate
    return super(DjangoModelFactory, cls)._generate(strategy, params)
  File "/usr/local/lib/python3.7/site-packages/factory/base.py", line 501, in _generate
    return step.build()
  File "/usr/local/lib/python3.7/site-packages/factory/builder.py", line 279, in build
    kwargs=kwargs,
  File "/usr/local/lib/python3.7/site-packages/factory/base.py", line 315, in instantiate
    return self.factory._create(model, *args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/factory/django.py", line 185, in _create
    return manager.create(*args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/django/db/models/manager.py", line 82, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/django/db/models/query.py", line 422, in create
    obj.save(force_insert=True, using=self.db)
  File "/usr/local/lib/python3.7/site-packages/django/db/models/base.py", line 741, in save
    force_update=force_update, update_fields=update_fields)
  File "/usr/local/lib/python3.7/site-packages/django/db/models/base.py", line 779, in save_base
    force_update, using, update_fields,
  File "/usr/local/lib/python3.7/site-packages/django/db/models/base.py", line 870, in _save_table
    result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
  File "/usr/local/lib/python3.7/site-packages/django/db/models/base.py", line 908, in _do_insert
    using=using, raw=raw)
  File "/usr/local/lib/python3.7/site-packages/django/db/models/manager.py", line 82, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/usr/local/lib/python3.7/site-packages/django/db/models/query.py", line 1186, in _insert
    return query.get_compiler(using=using).execute_sql(return_id)
  File "/usr/local/lib/python3.7/site-packages/django/db/models/sql/compiler.py", line 1335, in execute_sql
    cursor.execute(sql, params)
  File "/usr/local/lib/python3.7/site-packages/django/db/backends/utils.py", line 99, in execute
    return super().execute(sql, params)
  File "/usr/local/lib/python3.7/site-packages/django/db/backends/utils.py", line 67, in execute
    return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
  File "/usr/local/lib/python3.7/site-packages/django/db/backends/utils.py", line 76, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "/usr/local/lib/python3.7/site-packages/django/db/backends/utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
  File "/usr/local/lib/python3.7/site-packages/django/db/utils.py", line 89, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "/usr/local/lib/python3.7/site-packages/django/db/backends/utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
django.db.utils.DataError: value too long for type character varying(1)
Pauiie answered 8/12, 2019 at 20:50 Comment(1)
It's might not be the boolean field that fails but rec_type = models.CharField(max_length=1, choices=RECORD_TYPES) as it's max_length is 1. Can you confirm that RECORD_TYPES are max 1 character?Twosided
P
2

The major issue was that I was using the wrong Faker. This one did what I expected:

# factories.py

...

rec_type = factory.Faker('random_element', elements=[x[0] for x in Record.RECORD_TYPES])

...
Pauiie answered 15/12, 2019 at 14:48 Comment(0)
T
2

It might not be the boolean field that cause the error but

rec_type = models.CharField(max_length=1, choices=RECORD_TYPES)

As it's max_length is 1. Can you confirm that RECORD_TYPES are max 1 character?

django.db.utils.DataError: value too long for type character varying(1)

This should indicate that it's a VARCHAR of max length 1. And from what I can see from the trace, you're db backend is postgres where there is a native boolean field.

Twosided answered 8/12, 2019 at 22:46 Comment(0)
P
2

The major issue was that I was using the wrong Faker. This one did what I expected:

# factories.py

...

rec_type = factory.Faker('random_element', elements=[x[0] for x in Record.RECORD_TYPES])

...
Pauiie answered 15/12, 2019 at 14:48 Comment(0)
A
1

Just set e.g. direction = False in RecordFactory. Or, if you want to use faker, you can do direction = Faker().pybool()

I think the error is telling you that your DB backend uses a one letter varchar for representing booleans (most probably "t" and "f").

Ain answered 8/12, 2019 at 21:16 Comment(3)
> "Or, if you want to use faker, you can do direction = factory.Faker().pybool()", did you mean direction = fake.pybool()? If that's what you meant, how is that different? The output object is still a bool type object, not a "t" nor "f". (Genuine question)Sevenup
I did my testing directly with Faker so it's possible factoryboy usage is different (I don't know what is fake). Django' ORM will take care of properly storing the bool value in DB.Syntax
By fake I mean fake = Faker(). I should have been more explicit. So the question should have been: did you mean direction = Faker().pybool()?Sevenup

© 2022 - 2024 — McMap. All rights reserved.