Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django model inheritance error with PostgreSQL

I'm switching from a MySQL backend to a PostgreSQL backend and am running into some model inheritance issues. Here is an example of the models:

class Parent(models.Model):
   key = models.Charfield(...)
   value = models.Charfield(...)
   content_type = models.ForeignKey(ContentType)
   object_id = models.CharField(max_length=200)
   content_object = generic.GenericForeignKey('content_type', 'object_id')

class Child1(Parent):
   pass 

class Child2(Parent):
   pass

The reason we have two child classes like this is, we're simulating two key/value pairs in another model, and wanted to separated them into two tables for an easier lookup. The Generic FKs were also for attaching this to other models. This inheritance setup works fine in MySQL, but when I switched it to PostgreSQL, I get an error when trying to run our tests (but syncdb works fine). It's as if Django is OK with the relationship but PostgreSQL doesn't like the SQL being generated. When I look at what's being generated from syncdb I see this:

CREATE TABLE "myapp_parent" (
"id" serial NOT NULL PRIMARY KEY,
"key" varchar(200) NOT NULL,
"value" varchar(200) NOT NULL,
"content_type_id" integer NOT NULL REFERENCES "django_content_type" ("id") DEFERRABLE  INITIALLY DEFERRED,
"object_id" varchar(200) NOT NULL);

CREATE TABLE "myapp_child1" (
"parent_ptr_id" integer NOT NULL PRIMARY KEY REFERENCES "myapp_parent" ("id") DEFERRABLE INITIALLY DEFERRED);

CREATE TABLE "myapp_child2" (
"parent_ptr_id" integer NOT NULL PRIMARY KEY REFERENCES "myapp_parent" ("id")    DEFERRABLE INITIALLY DEFERRED);

So everything looks right, then when I run my tests I get this:

Error: Database test_myapp couldn't be flushed. Possible reasons:
* The database isn't running or isn't configured correctly.
* At least one of the expected database tables doesn't exist.
* The SQL was invalid.
Hint: Look at the output of 'django-admin.py sqlflush'. That's the SQL this command    wasn't able to run.
The full error: column "id" of relation "myapp_child1" does not exist

When I run flush:

SELECT setval(pg_get_serial_sequence('"myapp_child1"','id'), 1, false);

I've tried manually adding an ID field as the primary key in the child model but Django throws an error saying it conflicts with the Parent's ID field. How do I fix this so PostgreSQL likes it? And thanks in advance.

like image 233
user994013 Avatar asked Jan 02 '13 16:01

user994013


2 Answers

If you're using model inheritance in django, you should declare class Parent to be abstract

class Parent(models.Model):
    ...
    class Meta:
        abstract = True

See the docs. I imagine that some postgres / mysql differences have only been tested against standard conforming code - which could be why you're having problems here. I'd also recommend ./manage.py syncdb after making these changes ;-)

If in doubt, and on in a testing environment, you can drop your tables and start again with

$ ./manage.py sqlclear | ./manage.py dbshell
like image 183
danodonovan Avatar answered Oct 23 '22 08:10

danodonovan


Your model must contain one - and only one - foreign key to the target model. If you have more than one foreign key, a validation error will be raised. This is one of the restrictions of django.

like image 29
catherine Avatar answered Oct 23 '22 10:10

catherine