I have a model with a foreign key field. I want to remove the foreign key reference. However, migration fails because of the following error:
Cannot delete or update a parent row: a foreign key constraint fails
I understand what is going on, but I don't know how to resolve this properly with Django. Right now (since I'm at the beginning of my project), I go into the MySQL database manually and delete the tables and re-migrate as if it was the first migration.
Is there a way, using Django, to get around this foreign key constraint issue?
I'm using Django 1.7
Database backend is MySQL
EDIT - Models Before/After migrations
Before:
class Skills(models.Model):
# fields here...
class Project(models.Model):
skills = models.ForeignKey(Skills, verbose_name = "Required Skills", blank = True, null = True)
After:
class Skill(models.Model):
# fields here...
class Project(models.Model):
skills = models.ForeignKey(Skill, verbose_name = "Required Skills", blank = True, null = True)
I'm pretty sure all I've done is removed the "Plural" from the Skill model. The the makemigrations command works fine, but the migrate command fails with the above noted error.
EDIT 2
Hit the same error:
Cannot drop column 'skills_id': needed in a foreign key constraint 'projects_project_skills_id_4cc7e00883ac4de2_fk_projects_skill_id'
This time I dropped the field skill from model Project
A little hack I used:
Add a migration operations that first alters the field to say IntegerField before other operations i.e
operations = [
migrations.AlterField(
model_name='projects_project',
name='skills',
field=models.IntegerField(default=0)
),
..... other migration entries now after this.
]
This is my SOLUTION (do this manually first)
ALTER TABLE forms_formentry DROP FOREIGN KEY
forms_formentry_form_id_d0f23912_fk_forms_form_page_ptr_id
This is the ERROR
django.db.utils.OperationalError: (1833, "Cannot change column 'page_ptr_id': used in a foreign key constraint 'forms_formentry_form_id_d0f23912_fk_forms_form_page_ptr_id' of table 'dbname.forms_formentry'")
Related
I'm using Django 3.0.2 and sqlite3 DB.
I set following simple models:
from django.db import models
class Description(models.Model):
IDENTIFIER_LENGTH = 30
identifier = models.CharField(max_length=IDENTIFIER_LENGTH, blank=False, unique=True, primary_key=True)
Strangely, the unique=True seems not working. Following code run in shell mode
from testunique.models import Description
object = Description('first-object')
object.save()
object.save()
doesn't raise any error. For the record, here is the SQL code of the migrations:
BEGIN;
--
-- Create model Description
--
CREATE TABLE "testunique_description" ("identifier" varchar(30) NOT NULL PRIMARY KEY);
COMMIT;
What is wrong here? Thanks for the answer.
Django considers records with a set primary key as records already in the database. Therefore it will not perform a INSERT … query, but an UPDATE …. It is sometimes used as a trick to set the primary key in Django to None to make a copy of a given record (since then Django will make another INSERT … query).
You can force insertion with:
Description.objects.create(name='first-object')
Description.objects.create(name='first-object') # raises an error
or you can work with force_insert=True:
Description(name='first-object').save(force_insert=True)
Description(name='first-object').save(force_insert=True) # raises an error
ProgrammingError at /app-name/url-name
relation "TableName" does not exist
LINE 1: SELECT (1) AS "a" FROM "TableName" WHERE "TableName..."
I have done an inspectdb, confirmed the mapping matches what is automatically set when running makemigrations, and deleted all migrations from the django_migrations table and re-ran migrate. I also checked that the migrations are successfully imported, by looking at the django_migrations table,as well as running showmigrations.
I wonder why I see the double quotes around the table names, is that why new models cannot be used? Interestingly, if I reference the model to be used in a form (not a view) it does seem to work okay, I see the correct inputs in the form coming from the database. The error happens when I query using Django - this query is setup within the same model 'TableName' itself, is that referenced correctly? (instead of doing importing TableName from app-name.models)
TableName.objects.using('CUSTOMDBSETTING').filter(colid='value')
Note that this works when I try using the shell directly, just not through Django. I also don't have a primary key for this table, and when I try setting up a non-default (not id), it gives me another error.
So it does give me the error when I try to reference what should be the primary key (but isn't) in the table mapping. When I try removing the primary key for the specific id (only in models, not in the migrations)
('42S22', "[42S22] [Microsoft][ODBC Driver 17 for SQL Server][SQL
Server]Invalid column name 'id'. (207) (SQLExecDirectW); [42S22]
[Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Statement(s)
could not be prepared. (8180)")
So, the answer to this question is that if one doesn't assign a specific unique/primary key in the model in question, the default 'id' mapped in Django would apply.
That is, expect your migrations to have a primary key like this (the model mapping wouldn't explicitly show this):
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
...
]
To fix this issue, either use the primary key 'id' from Django or setup a primary key - doesn't have to done for the actual table, just the Django model. Then re-run the migrations and make sure they applied to catch this change...
Now, migrations should look like this (and no 'id' key would be used)
('tableid', models.CharField(blank=True, db_column='TableID', max_length=255, primary_key=True, serialize=False)),
or something like this if it's auto incremented
customid = models.AutoField(db_column='CustomID', null=False, primary_key=True, max_length=10)
I have a unmanaged model Client
class Client(models.Model):
client_id = models.IntegerField('ID', primary_key=True)
name = models.CharField()
class meta:
manage = False
I use Client to extend User:
class Account(models.Model):
user = models.OneToOneField(User)
client = models.OneToOneField(Client, to_field='client_id')
I thought Django will create foreign key reference to Client.client_id instead of Client.id even without explicit to_field='client_id' because of the definition of Client model. But sqlmigrate shows:
BEGIN;
CREATE TABLE `pubsite_account` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `deg_client_id` integer NOT NULL UNIQUE, `user_id` integer NOT NULL UNIQUE);
ALTER TABLE `pubsite_account` ADD CONSTRAINT pubsite_account_deg_client_id_73086fddd308cd6f_fk_Clients_id FOREIGN KEY (`deg_client_id`) REFERENCES `Clients` (`id`);
ALTER TABLE `pubsite_account` ADD CONSTRAINT pubsite_account_user_id_33ed558985f73b32_fk_auth_user_id FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`);
COMMIT;
And nothing changes with setting to_field='client_id'. Any thoughts would be appreciated.
Django version: 1.8, 1.7 (Yep, I tried both)
Databse: mysql
I cant try right now but I think db_column is what you are looking for
client = models.OneToOneField(Client, db_column='client_id')
After discuss in #django-dev, it turns out to be a bug.
While a ticket has been opened, a developer MarkusH offers a temporary work around:
change managed = False on the model to =True
once you have new migration files, change the managed option on the model back to False
and in the corresponding migration file add 'managed': False, to the options array in the CreateModel operation.
-------edit---------
From the ticket page, this bug has been fixed. So if you come to here for the same thing, just update Django.
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.
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
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.
I have two models: UserProfile (extended from user) and Cv. I created another model that have two foreign key that come from theses models.
class cv(models.Model):
user = models.ForeignKey(User, unique=True)
cv_d= models.TextField(max_length=1100)
...
class cvv(models.Model):
user = models.ForeignKey(User)
cv= models.ForeignKey(cv)
date = models.DateTimeField(auto_now=True)
In my view, I am trying to insert value on cvv:
...
obj = cv.objects.get(pk=id,active=True)
add=cvv(user=request.user, cv=obj)
add.save()
But, I am getting the following error:
(1452, 'Cannot add or update a child row: a foreign key constraint fails
How can I insert theses 2 foreign key on my model?
Welcome to one of the many reasons why you shouldn't use MySQL. This happens most often when you have one table that is MyISAM and one table that is InnoDB. Since myISAM doesn't support FK constraints all hell breaks loose when django creates a FK between the tables.
The fix is to either make both tables InnoDB or MyISAM and not to mix them. Or even better drop the bad RDMS for something not MySQL.