ValueError on creating auto migration for field with function call as default value -

4,037 views
Skip to first unread message

Graeme West

unread,
May 21, 2012, 12:08:19 PM5/21/12
to South Users
Hello all - I'm having a bit of trouble getting South to auto-generate
a migration for one of my apps. The model in question is a subclass of
a model (in another app) which has a custom UUID field. Here's the
superclass:

from uuid import uuid4
class MyThing(models.Model):
uuid = models.CharField(default=uuid4, unique=True)

When I run ./manage.py schemamigration MyApp --auto , I get:

"ValueError: Cannot successfully create field 'uuid' for model
'MySubThing': name 'UUID' is not defined."

'MyThing' is the superclass, and 'MySubThing' is a subclass of it, and
is in the app I want to migrate.

I suspect it might be because the default value of MyThing.uuid is to
run 'uuid4()' - so I need a way to teach South to ignore this or
something like that. FYI, 'manage.py syncdb' runs fine.

Any ideas on how I can get South to not choke on this? Thanks!

I'm using South 0.7.5 with Django 1.3.1 on MySQL.

Graeme

Andrew Godwin

unread,
May 21, 2012, 12:54:57 PM5/21/12
to south...@googlegroups.com
If you're using a custom field, you most likely need to educate South
about it by extending the introspection engine so you can tell it to
leave off the default.

There are some rather confusing details in the docs on how to accomplish
this - you might be better served by finding one of the examples we've
posted here on the list or elsewhere. I really need to improve that
whole system so it's not crazy.

Andrew

Shai Berger

unread,
May 22, 2012, 3:28:59 AM5/22/12
to south...@googlegroups.com
On Monday, May 21, 2012 07:54:57 PM Andrew Godwin wrote:
> On 21/05/12 17:08, Graeme West wrote:
> > Hello all - I'm having a bit of trouble getting South to auto-generate
> > a migration for one of my apps. The model in question is a subclass of
> > a model (in another app) which has a custom UUID field. Here's the
> > superclass:
> >
> > from uuid import uuid4
> >
> > class MyThing(models.Model):
> > uuid = models.CharField(default=uuid4, unique=True)
> >
> > When I run ./manage.py schemamigration MyApp --auto , I get:
> >
> > "ValueError: Cannot successfully create field 'uuid' for model
> > 'MySubThing': name 'UUID' is not defined."
> >
> > 'MyThing' is the superclass, and 'MySubThing' is a subclass of it, and
> > is in the app I want to migrate.
> >
> > I suspect it might be because the default value of MyThing.uuid is to
> > run 'uuid4()' - so I need a way to teach South to ignore this or
> > something like that. FYI, 'manage.py syncdb' runs fine.
> >
> > Any ideas on how I can get South to not choke on this? Thanks!
>
> If you're using a custom field, ...

He's not using a custom field, it's a CharField.

Graeme, by the error, it seems that MyThing is an abstract parent; this is
important, and you should have mentioned it.

Also, please include a fuller stack-trace; the name UUID (in all caps)
mentioned in the error is not mentioned anywhere in the code.

Shai.

Graeme West

unread,
May 22, 2012, 4:43:12 AM5/22/12
to South Users
Andrew, Shai,
Thanks for your replies and assistance. As Shai noted it's not a
custom field type but rather an unusual type of default value.

Here's a fuller traceback (I've changed the model and app names for
the purposes of the examples I've posted, by the way):


% ./manage.py schemamigration MyApp --auto
Traceback (most recent call last):
File "./manage.py", line 11, in <module>
execute_manager(settings)
File "/u/virtualenvs/django131/lib/python2.7/site-packages/django/
core/management/__init__.py", line 438, in execute_manager
utility.execute()
File "/u/virtualenvs/django131/lib/python2.7/site-packages/django/
core/management/__init__.py", line 379, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/u/virtualenvs/django131/lib/python2.7/site-packages/django/
core/management/base.py", line 191, in run_from_argv
self.execute(*args, **options.__dict__)
File "/u/virtualenvs/django131/lib/python2.7/site-packages/django/
core/management/base.py", line 220, in execute
output = self.handle(*args, **options)
File "/u/virtualenvs/django131/lib/python2.7/site-packages/south/
management/commands/schemamigration.py", line 97, in handle
old_orm = last_migration.orm(),
File "/u/virtualenvs/django131/lib/python2.7/site-packages/south/
utils/__init__.py", line 62, in method
value = function(self)
File "/u/virtualenvs/django131/lib/python2.7/site-packages/south/
migration/base.py", line 427, in orm
return FakeORM(self.migration_class(), self.app_label())
File "/u/virtualenvs/django131/lib/python2.7/site-packages/south/
orm.py", line 45, in FakeORM
_orm_cache[args] = _FakeORM(*args)
File "/u/virtualenvs/django131/lib/python2.7/site-packages/south/
orm.py", line 131, in __init__
self.retry_failed_fields()
File "/u/virtualenvs/django131/lib/python2.7/site-packages/south/
orm.py", line 370, in retry_failed_fields
fname, modelname, e
ValueError: Cannot successfully create field 'uuid' for model
'MySubThing': name 'UUID' is not defined.


My models work like this:

MyOtherApp/models.py:

from uuid import uuid4
class MyThing(models.Model):
uuid = models.CharField(default=uuid4, unique=True)
...


class MySubThing(MyThing):
temperature = models.CharField(max_length=40, blank=True,
editable=False, verbose_name="temperature")
...


The two models above are stored in a different app to the one I'm
migrating, but the app that I'm migrating has a model with MySubThing
as a OneToOneField, so South is traversing MyOtherApp in the process
of writing the migration for MyApp:

MyApp/models.py:

from Sprockets.MyOtherApp.models import Widget

class SuperAwesomeItem(models.Model):
widget = models.OneToOneField(Widget)


I can't find 'UUID' (in uppercase) anywhere in my models, however when
I run 'uuid4()' on the shell, I get a UUID object whose normal
representation appears to start with 'UUID':

>>> from uuid import uuid4
>>> uuid4()
UUID('99adae06-2215-4fab-b6e3-09db25ea4108')
>>> str(uuid4())
'9b851075-58cc-482b-9ab5-17a04ac36cd6'
>>>

I wonder if that's where South is choking.


Regards,

Graeme

Shai Berger

unread,
May 23, 2012, 2:29:22 AM5/23/12
to south...@googlegroups.com
On Tuesday, May 22, 2012 11:43:12 AM Graeme West wrote:
> Andrew, Shai,
> Thanks for your replies and assistance. As Shai noted it's not a
> custom field type but rather an unusual type of default value.
>
I'm not sure what in South causes the exception, but keep in mind that the
migration is not going to use the unusual default -- it creates database
objects, and your default is a Python object. So an obvious workaround --
assuming that MyThing is, indeed, under your control -- is just to change its
default (to any distinctive string, or to None), generate the migration, and
restore the default.

Note that the automatic migration may be a little different than what you need;
you are encouraged to look at it and edit it if necessary (always true, but
more so when you've had to mess with other models for it to be generated).

Shai.

Shai Berger

unread,
Dec 17, 2012, 8:38:41 AM12/17/12
to south...@googlegroups.com
On Monday 17 December 2012 10:42:06 Maxym Kutsevol wrote:
> Got the same error.
>
> Fixed it by adding
>
> from uuid import UUID
>
> to migrations/0001_initial.py file.

That's not the same error, then: Graeme was facing it in the generation of the
migration, so he didn't have a file to add an import to.

Shai.

Maxym Kutsevol

unread,
Dec 18, 2012, 2:29:03 AM12/18/12
to south...@googlegroups.com
What I posted earlier didn't help to the end. 

The error I faced is the same, South does --initial without error, but when I do --auto I get quite the same error,
And I have a very similar models.
I have solved it.

The 0001_initial file had UUID('long-uuid-string') in the model constructor. 
Something like that:

db.create_table('pos', (
            ('uuid', self.gf('engine.orm.common.UUIDField')(default=UUID('long-uuid-string'), primary_key=True)),

It is the place from where South could not import UUID, I have fixed it by adding this to introspestion rules:

add_introspection_rules([(
                          [UUIDField],
                          [],
                          {
                           "default": ["uuid_generate_v4()", {"is_value": True}]
                           },
                        )], ["^engine\.orm\.common\.UUIDField"])

Now South generates:

        db.create_table('pos', (
            ('uuid', self.gf('engine.orm.common.UUIDField')(default=u'uuid_generate_v4()', primary_key=True)),

uuid_generate_v4() goes to DDL. What should be placed in the default depends on the needs. As django by itself cannot add default values to DDL Graeme should place "None" there.

Cheers.

Maxym Kutsevol

unread,
Dec 18, 2012, 2:30:12 AM12/18/12
to south...@googlegroups.com
And the problem is that South doesn't understand a callable in default. It evaluates it.

Andrew Godwin

unread,
Dec 18, 2012, 3:55:26 AM12/18/12
to south...@googlegroups.com
You can't really have callables in defaults for South operations, since they don't map to SQL - perhaps in the best case they will, but in most cases we need a single value to put there. Of course, this doesn't work for UUIDs as the whole point is that they need to be unique, so if you're adding a UUID column to a table after it's been made it has to be nullable currently.

Not sure why create table doesn't work though - I suspect it just needs a better custom field definition, since you can't use random callables in a field definition and expect them to work (the default value is evaluated in a pretty limited context, with datetime being the only available module). It might be that we need to add uuid to the available modules in there.

Andrew


On Tue, Dec 18, 2012 at 7:30 AM, Maxym Kutsevol <m...@kutsevol.com> wrote:
And the problem is that South doesn't understand a callable in default. It evaluates it.

--
You received this message because you are subscribed to the Google Groups "South Users" group.
To view this discussion on the web visit https://groups.google.com/d/msg/south-users/-/uLkLZa3agj0J.

To post to this group, send email to south...@googlegroups.com.
To unsubscribe from this group, send email to south-users...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/south-users?hl=en.

Reply all
Reply to author
Forward
0 new messages