Opened 7 years ago

Closed 6 years ago

Last modified 6 years ago

#9457 closed (invalid)

ContextType in of limit_choices_to clause causing error during initial syncdb

Reported by: bnospam@… Owned by: nobody
Component: Database layer (models, ORM) Version: 1.0
Severity: Keywords: contexttype, database
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: UI/UX:

Description

I'm getting the following error (on an empty database):

$ python manage.py syncdb
... (traceback) ...
sqlite3.OperationalError: no such table: django_content_type

My INSTALLED_APPS includes ('django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.admin', 'django.contrib.sites', ..., 'Pl', 'Proc')

The offending line seems to be:

   # pl/models.py
   proc = models.ForeignKey(BaseModel,
       limit_choices_to={ 'content_type': ContentType.objects.get_for_model(Proc) })
# where
   class Proc(BaseModel):
       # ...

The traceback is as follows (modified slightly to simplify class names):

Traceback (most recent call last):
 File "./manage.py", line 11, in <module>
   execute_manager(settings_web)
 File "/Library/Python/2.5/site-packages/django/core/management/__init__.py", line 340, in execute_manager
   utility.execute()
 File "/Library/Python/2.5/site-packages/django/core/management/__init__.py", line 295, in execute
   self.fetch_command(subcommand).run_from_argv(self.argv)
 File "/Library/Python/2.5/site-packages/django/core/management/base.py", line 77, in run_from_argv
   self.execute(*args, **options.__dict__)
 File "/Library/Python/2.5/site-packages/django/core/management/base.py", line 95, in execute
   self.validate()
 File "/Library/Python/2.5/site-packages/django/core/management/base.py", line 122, in validate
   num_errors = get_validation_errors(s, app)
 File "/Library/Python/2.5/site-packages/django/core/management/validation.py", line 28, in get_validation_errors
   for (app_name, error) in get_app_errors().items():
 File "/Library/Python/2.5/site-packages/django/db/models/loading.py", line 128, in get_app_errors
   self._populate()
 File "/Library/Python/2.5/site-packages/django/db/models/loading.py", line 57, in _populate
   self.load_app(app_name, True)
 File "/Library/Python/2.5/site-packages/django/db/models/loading.py", line 72, in load_app
   mod = __import__(app_name, {}, {}, ['models'])
 File "/Users/brian/dev/trunk/apps/ple/models.py", line 238, in <module>
   class Ple(models.Model):
 File "/Users/brian/dev/trunk/apps/ple/models.py", line 246, in Pl
   limit_choices_to={ 'content_type': ContentType.objects.get_for_model(Proc) })
 File "/Library/Python/2.5/site-packages/django/contrib/contenttypes/models.py", line 28, in get_for_model
   defaults = {'name': smart_unicode(opts.verbose_name_raw)},
 File "/Library/Python/2.5/site-packages/django/db/models/manager.py", line 96, 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 326, in get_or_create
   return self.get(**kwargs), False
 File "/Library/Python/2.5/site-packages/django/db/models/query.py", line 298, in get
   num = len(clone)
 File "/Library/Python/2.5/site-packages/django/db/models/query.py", line 154, 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 self.query.results_iter():
 File "/Library/Python/2.5/site-packages/django/db/models/sql/query.py", line 206, in results_iter
   for rows in self.execute_sql(MULTI):
 File "/Library/Python/2.5/site-packages/django/db/models/sql/query.py", line 1700, in execute_sql
   cursor.execute(sql, params)
 File "/Library/Python/2.5/site-packages/django/db/backends/util.py", line 19, in execute
   return self.cursor.execute(sql, params)
 File "/Library/Python/2.5/site-packages/django/db/backends/sqlite3/base.py", line 167, in execute
   return Database.Cursor.execute(self, query, params)
sqlite3.OperationalError: no such table: django_content_type

Python: 2.5.1
OS: OS X

Cheers!

Change History (7)

comment:1 Changed 6 years ago by oggy

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset

Confirmed. You can get around it by removing your custom apps from the INSTALLED_APPS first, creating the db, putting your apps back in and syncdb-ing again.

comment:2 Changed 6 years ago by oggy

Ugh. Neglect the last comment. You can't get around it this way, you need to add the limit_choices_to *after* you create the target models. And, frankly, it wouldn't make sense any other way because the content types framework has to look it up in the db, this ticket should probably be closed as invalid.

comment:3 Changed 6 years ago by ubernostrum

  • Resolution set to invalid
  • Status changed from new to closed

If your own apps require something else to be installed/set up before they can work, then the solution is to set up that thing before you try to use or install your apps.

comment:4 Changed 6 years ago by bnospam@…

For what it's worth, I strongly disagree with the notion that initializing a database should result in a catastrophic error because there are tables with fields that use limit_choices_to. It obliges developers using Django to implement extra (and arguably arbitrary) development and deployment procedures. In other words, it pushes onto users of Django a dependency check and order of table creation that I believe ought to be automatically taken care of by Django. That being said, I don't think it's within my discretion to reopen this bug, and I don't know enough about Django's innards to know if a solution is either easy or obvious.

Regardless of the above, would it be possible to reopen this bug on the basis that a helpful error message is desired?

Cheers.

comment:5 Changed 6 years ago by ubernostrum

"Initializing a database" does not result in an error. The problem here is that in order to even define your model class like this, you have assumed that the ContentType table already exists and contains records, and then you are attempting to use this definition before creating any database tables. There's no way around this: you'll need to install the tables in two steps (one to get the tables you depend on, like the one for the ContentType model, and a second to install your applications which depend on those tables existing and being populated).

There's also no easy way to try to special-case this in Django, since you're just using the plain database API and that API (deliberately) has no way of knowing that it's being used, say, while syncdb is being run and so should refuse to query or raise a different error message. This is really a situation where we have to trust you, the application developer, to know what you're doing and to think through the consequences of how you're setting things up.

comment:6 Changed 6 years ago by bmh <bnospam@…>

Thanks for the reply, ubernostrum. I trust that the designers of Django have balanced the issues and made the right choices.

If this is an application developer issue, I believe a note in the documentation for application developers on this pre-existing database requirement of limit_choices_to would be valuable.

comment:7 Changed 6 years ago by ubernostrum

Again, this is not a "requirement" of limit_choices_to, which works just fine. The specific problem you are encountering is solely because you have chosen to set limit_choices_to by running a database query and it's hopefully clear that trying to run a database query before the database is set up simply can't work.

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