Opened 14 years ago

Closed 14 years ago

#13868 closed (duplicate)

Inability to create superuser during syncdb when using GIS fields in AUTH_PROFILE_MODULE

Reported by: Jason Skicewicz Owned by: jbronn
Component: GIS Version: 1.2
Severity: Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Overview

I have an AUTH_PROFILE_MODULE that contains a GIS PointField for maintaining a users current location. When a new user is created, I have a post_save signal handler that creates a UserProfile object for the new user. When I run syncdb, and try to create a superuser during the process, I get the following traceback:

Traceback (most recent call last):
  File "manage.py", line 11, in <module>
    execute_manager(settings)
  File "/Library/Python/2.5/site-packages/django/core/management/__init__.py", line 438, in execute_manager
    utility.execute()
  File "/Library/Python/2.5/site-packages/django/core/management/__init__.py", line 379, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/Library/Python/2.5/site-packages/django/core/management/base.py", line 191, in run_from_argv
    self.execute(*args, **options.__dict__)
  File "/Library/Python/2.5/site-packages/django/core/management/base.py", line 218, in execute
    output = self.handle(*args, **options)
  File "/Library/Python/2.5/site-packages/django/core/management/base.py", line 347, in handle
    return self.handle_noargs(**options)
  File "/Library/Python/2.5/site-packages/django/core/management/commands/syncdb.py", line 103, in handle_noargs
    emit_post_sync_signal(created_models, verbosity, interactive, db)
  File "/Library/Python/2.5/site-packages/django/core/management/sql.py", line 185, in emit_post_sync_signal
    interactive=interactive, db=db)
  File "/Library/Python/2.5/site-packages/django/dispatch/dispatcher.py", line 162, in send
    response = receiver(signal=self, sender=sender, **named)
  File "/Library/Python/2.5/site-packages/django/contrib/auth/management/__init__.py", line 44, in create_superuser
    call_command("createsuperuser", interactive=True)
  File "/Library/Python/2.5/site-packages/django/core/management/__init__.py", line 166, in call_command
    return klass.execute(*args, **defaults)
  File "/Library/Python/2.5/site-packages/django/core/management/base.py", line 218, in execute
    output = self.handle(*args, **options)
  File "/Library/Python/2.5/site-packages/django/contrib/auth/management/commands/createsuperuser.py", line 134, in handle
    User.objects.create_superuser(username, email, password)
  File "/Library/Python/2.5/site-packages/django/contrib/auth/models.py", line 133, in create_superuser
    u = self.create_user(username, email, password)
  File "/Library/Python/2.5/site-packages/django/contrib/auth/models.py", line 129, in create_user
    user.save(using=self._db)
  File "/Library/Python/2.5/site-packages/django/db/models/base.py", line 435, in save
    self.save_base(using=using, force_insert=force_insert, force_update=force_update)
  File "/Library/Python/2.5/site-packages/django/db/models/base.py", line 543, in save_base
    created=(not record_exists), raw=raw)
  File "/Library/Python/2.5/site-packages/django/dispatch/dispatcher.py", line 162, in send
    response = receiver(signal=self, sender=sender, **named)
  File "/usr/local/findmefit/../findmefit/accounts/models.py", line 25, in profile_creation_handler
    profile, created = UserProfile.objects.get_or_create(user=instance)
  File "/Library/Python/2.5/site-packages/django/db/models/manager.py", line 135, in get_or_create
    return self.get_query_set().get_or_create(**kwargs)
  File "/Library/Python/2.5/site-packages/django/db/models/query.py", line 366, in get_or_create
    return self.get(**kwargs), False
  File "/Library/Python/2.5/site-packages/django/db/models/query.py", line 336, in get
    num = len(clone)
  File "/Library/Python/2.5/site-packages/django/db/models/query.py", line 81, in __len__
    self._result_cache = list(self.iterator())
  File "/Library/Python/2.5/site-packages/django/db/models/query.py", line 269, in iterator
    for row in compiler.results_iter():
  File "/Library/Python/2.5/site-packages/django/db/models/sql/compiler.py", line 672, in results_iter
    for rows in self.execute_sql(MULTI):
  File "/Library/Python/2.5/site-packages/django/db/models/sql/compiler.py", line 727, in execute_sql
    cursor.execute(sql, params)
  File "/Library/Python/2.5/site-packages/django/db/backends/util.py", line 15, in execute
    return self.cursor.execute(sql, params)
  File "/Library/Python/2.5/site-packages/django/db/backends/postgresql_psycopg2/base.py", line 44, in execute
    return self.cursor.execute(query, args)
django.db.utils.DatabaseError: column accounts_userprofile.current_location does not exist
LINE 1: ...ion_name", "accounts_userprofile"."friends_list", "accounts_...
                                                             ^

This is due to the fact that the custom SQL commands have not been run yet. If I do a syncdb without creating the superuser in the process, and then create superusers from the command line after a successful syncdb, everything works correctly.

I am using PostgreSQL 8.4.3-1 and PostGIS 1.5.1-1.

Setup

The following assumes that you have a working GeoDjango installation, which I have. This was verified by running the GeoDjango tutorial without fail.

  • In settings.py add a profile model
    AUTH_PROFILE_MODULE = 'accounts.UserProfile'
    
  • In the application accounts, add the following simple UserProfile model
    from django.contrib.auth.models import User
    from django.contrib.gis.db import models
    from django.db.models.signals import post_save
    
    def profile_creation_handler(sender, instance, created, **kwargs):
        """
        This is a post_save handler on the User class so that we create a user's profile whenever a
        new User is created.
    
        """
        if created:
            profile, created = UserProfile.objects.get_or_create(user=instance)
        
    
    class UserProfile(models.Model):
        """
        UserProfile model with PointField for a users current_location
           
        """
        user = models.ForeignKey(User, unique=True, editable=False)
        profile_url = models.URLField(verify_exists=False, blank=True)
        current_location = models.PointField(blank=True, null=True)    
        
        objects = models.GeoManager()
        
        class Meta:
            pass
        
        def __unicode__(self):
            return u'%s (%s)' % (self.user, self.profile_url,)
        
        def __repr__(self):
            return '<%s Object: %s (%s)>' % (self.__class__.__name__, self.user, self.profile_url,)
        
    post_save.connect(profile_creation_handler, sender=User)
    

I believe the reason the problem happens is that custom SQL is done after the prompt for creating a super user, which means that the geometry column in UserProfile has not been created yet. This is why if I create super users after syncdb has properly run, everything works correctly. I assigned this to the component GIS, but I believe it could be more related to the order in which things happen during syncdb.

Change History (4)

comment:1 by anonymous, 14 years ago

test

comment:2 by jbronn, 14 years ago

Owner: changed from nobody to jbronn
Status: newassigned

I'll accept the ticket for now, but I'm not sure if there will be a patch acceptable for this edge-case scenario that has an easy work-around (run syncdb first, and create the superuser afterwards):

$ ./manage.py syncdb --noinput
$ ./manage.py createsuperuser

From my brief review, the only way to fix this would be to change when the post_syncdb is emitted, as it is done before the index creation SQL (which is now where the AddGeometryColumn SQL is actually generated). The side-effects of this 'fix' could be far-reaching have many backwards-incompatible consequences, so for now I would recommend the workaround given above.

comment:3 by jbronn, 14 years ago

See also #7561.

comment:4 by jbronn, 14 years ago

Resolution: duplicate
Status: assignedclosed

Actually, this ticket is a duplicate of #13826 because it's the same root issue.

Note: See TracTickets for help on using tickets.
Back to Top