IntegrityError using Django's loaddata when switching to Postgres - python

I am getting the following error:
IntegrityError: duplicate key value violates unique constraint "users_userprofile_pkey"
I am migrating from MySQL to Postgres, so I am dumping the data from the MySQL database using:
python2.7 manage.py dumpdata --indent=4 --natural > dump.json
I get the error when I attempt to load the dump.json into the Postgresql database:
python manage.py loaddata dump.json
I have the following signals in my users/model:
post_save.connect(create_user_profile, sender=User, dispatch_uid="user_create_profile")
post_save.connect(create_api_key, sender=User, dispatch_uid="user_create_api_key")

I had to comment out the post_save signals and then do the loaddata.

the problem may be because of the --natural keyword, if you read the docs about dumpdata natural keys here you will see it has some problems that apply to your database migration.
Also here they talk about a solution to this problem which seems to be pretty interesting (and tedious).
You can always try to add first the models that doesn't depend on each other so you can be sure they exists before trying to create another one. i.e:
if you have this models:
class Person(models.Model):
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
birthdate = models.DateField()
class Meta:
unique_together = (('first_name', 'last_name'),)
class Book(models.Model):
name = models.CharField(max_length=100)
author = models.ForeignKey(Person)
Then migrate the Person class first and then the book class.
Also if you can post the error it would be very helpful (since I could be more specific) but I am pretty certain the problem is a primary key issue

Related

Why Django is not creating Foreign Key constraint on MySQL?

I'm not new to Python nor Django, but this is the first time I'm creating a completely new big project from scratch, and also the first time I'm actually creating the models for the whole database and I'm kinda confused here.
Does Django does not really create the ForeignKey constraints on the Database to check if ID exists? It is just a logical python thing that works only when the server is running? Or is it a problem that happens on MySQL?
Just to be clear what I'm talking about, the first thing I noticed because as a Laravel developer on PHP side, I'm used to always check the database diagram that PhpStorm/PyCharm generates by connecting to the database, and on Laravel migrated tables, we can see the arrows pointing to the respective foreign key tables relationships, but on the Django created database there is not a single arrow on the database diagram generated by the JetBrains IDE. So I went testing.
For example, I have the following models:
class Series(models.Model):
class Meta:
app_label = 'core'
db_table = 'km_series'
verbose_name_plural = 'series' # added this to avoid plural being "seriess"
name = models.CharField(max_length=200)
description = models.TextField(default=None, blank=True, null=True)
cover_img = models.CharField(max_length=100, default=None, blank=True, null=True)
on_going = models.BooleanField(default=False)
date_added = models.DateTimeField(auto_now_add=True)
date_updated = models.DateTimeField(auto_now=True)
def __str__(self):
return "{} - ID #{}".format(self.name, self.id)
class Chapter(models.Model):
class Meta:
app_label = 'core'
db_table = 'km_chapter'
series = models.ForeignKey(Series, on_delete=models.CASCADE)
number = models.IntegerField(validators=[MinValueValidator(0)])
name = models.CharField(max_length=150, default=None, blank=True, null=True)
date_added = models.DateTimeField(auto_now_add=True)
date_updated = models.DateTimeField(auto_now=True)
def __str__(self):
return "#{} - {}".format(self.number, self.name)
I have more than 15 models created already using models.ForeignKey along other fields. I just tried creating a new row on MySQL using the python manage.py shell.
$ python manage.py shell
>>> from core.models import *
>>> Series
<class 'core.models.base_models.Series'>
>>> one = Series.objects.create(name='Test')
>>> one
<Series: Test - ID #1>
>>> one.id
1
>>> chapter = Chapter.objects.create(number=1)
MySQLdb.OperationalError: (1048, "Column 'series_id' cannot be null")
>>> chapter = Chapter.objects.create(number=1, series_id=2)
>>> chapter
<Chapter: #1 - None>
>>> chapter_1 = Chapter.objects.create(number=1, series=one)
>>> chapter_1
<Chapter: #1 - None>
>>> chapter = Chapter.objects.create(number=1, series_id=25)
There is only one ID on database, where the ID is "1"
So how can I be able to add any ID when manually assigning, and not passing the whole instantiated object as foreign_key value?
Why Django allows me to set the ID to non-existing IDs on the database? Shouldn't this result in an error? Am I missing something on my models? Why there is no constraint and validations for this kind of thing?
After digging a little on why MySQL would have a problem with FK contraints, and after using the python manage.py dbshell command to check the table creation as I was recommended doing on a comment, by using SHOW CREATE TABLE core_chapter; , I discovered the problem.
For some reason that I don't really know why, my Database was created using MyISAM, which is a MySQL storage engine that does not support FK constraints. I had to change the default to InnoDB, as it works with this types of validations for relationships between tables.
On my my.cnf file which holds the confs for MySQL, I enforced InnoDB as default by adding the default-storage-engine property
[mysqld]
default-storage-engine = InnoDB
And on Django settings, I also added the DATABASE "OPTIONS", as stated on the Django documentation for databases, so my DATABASES value was changed to:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'database_name',
'USER': 'database_user',
'PASSWORD': '****',
'HOST': 'localhost',
'PORT': '3306',
'OPTIONS': {'init_command': 'SET default_storage_engine=INNODB'},
}
}
After changing all that, dropping all database tables and then calling the python manage.py migrate again, the constraints were created as expected, and now my PyCharm generated database diagram shows all the arrows showing the relationships flawlessly.

Django creates a migration that seems already reflected in original postgresql schema

I've modified the foreign key calendar as nullable in my Django model CalendarAssign. \
# ---------------------------------------------------------------------------- #
class Calendars(models.Model):
id = models.CharField(primary_key=True, max_length=100)
cms_id = models.CharField(max_length=100)
default_program = models.ForeignKey(ControlPrograms, models.CASCADE, blank=True, null=True)
timestamp = models.DateTimeField(auto_now_add=True)
class Meta:
managed = True
db_table = 'calendars'
# ---------------------------------------------------------------------------- #
class CalendarAssign(models.Model):
device_mac = models.ForeignKey(Device, models.CASCADE)
calendar = models.ForeignKey(Calendars, models.CASCADE, null=True)
timestamp = models.DateTimeField(auto_now_add=True)
class Meta:
managed = True
db_table = 'calendar_assign'
When applying the migration generated by Django it gives me an error.
operations = [
migrations.AlterField(
model_name='calendarassign',
name='calendar',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='smartbridge.Calendars'),
)
Generated sql code uses unsupported feature 'WITH ORDINALITY'.
It's because Django doesn't support the Postrges version we are using.
WITH ORDINALITY appears in psql 9.4 but we use version 9.1.
Both Postgres and Django cannot be upgraded right now. So I need to write the migration manually (without 'WITH ORDINALITY' feature).
migrations.RunSQL("DO $$DECLARE r record;\
BEGIN\
FOR r IN SELECT table_name,constraint_name \
FROM information_schema.constraint_table_usage \
WHERE table_name IN ('calendars') AND constraint_name like '%calendar_assign_calendar_id%'\
LOOP\
EXECUTE 'ALTER TABLE calendar_assign DROP CONSTRAINT '|| quote_ident(r.constraint_name) || ';';\
END LOOP;\
ALTER TABLE calendar_assign ALTER COLUMN calendar_id DROP NOT NULL; \
ALTER TABLE calendar_assign \
ADD CONSTRAINT calendar_assign_calendar_id_fk_calendars_id FOREIGN KEY (calendar_id) REFERENCES calendars(id);\
END$$;")
Migration seems to work fine.
calendar is now nullable but Django still detect some difference.
If a ask Django to generate the migration corresponding to the difference it generates the same as before my manual migration.
I would like Django to see no difference after my migration.
Thanks
I think you will have to set managed = False for the time being, otherwise the makemigrations command will each time think it has not been made nullable yet.
The migration construction command looks to the previous migration files, and thus constructs a conceptual model how a table will look like in the database if all the previous migrations took place. Based on that model it will look for differences with your Django model that you constructed, and thus create a migration file for that.
As long as you thus do not migrate with the AlterField command, Django will think you did not make the field nullable. It can not parse SQL so even if you made it nullable over there, it will still assume that that the field is non-NULLable.
By setting it to managed=False [Django-doc], Django will no longer manage the migrations of that file. You can create an empty migration [Django-doc] with:
python3 manage.py makemigrations --empty
and use this to define SQL queries to perform on the table.

ValueError while making db migrations in django

I am new to django and i tried changing tag field from char field to TaggableManager()
models.py
class UserBookmark(models.Model):
user = models.ForeignKey(User)
bookmark = models.URLField()
tag = TaggableManager()
def __str__(self):
return '%i %s %s'%(self.id,self.user,self.bookmark)
when i run python manage.py migrate, i get this error:
ValueError: Cannot alter field bookmark.UserBookmark.tags into
bookmark.UserBookmark.tags - they are not compatible types (you cannot
alter to or from M2M fields, or add or remove through= on M2M fields)
How can i remove this error?
I was able to solve similar issue by deleting the migration files and sqlite db.
Make sure to backup your db before deleting

Multiple default values specified for column "id" of the table

I use to run my website on my laptop and its database was Sqlite, recently I wanted to transfer it to DigitalOcean and I changed its database to Postgresql, but when I migrate I encounters with some problems.
Python 3.4
Django 1.8
Error
django.db.utils.ProgrammingError: multiple default values specified for column "id" of table "profiles_userprofile"
My Model
class UserProfile(models.Model):
user = models.OneToOneField(User)
avatar = models.ImageField(blank=True, upload_to=get_image_path, default='/static/image/avatar/male.png')
age = models.IntegerField(default=4, validators=[MinValueValidator(3), MaxValueValidator(99)])
What should I do?
Try explicitly specifying the id field and marking it as the primary key:
class UserProfile(models.Model):
id = models.BigIntegerField(primary_key = True)
user = models.OneToOneField(User)
avatar = models.ImageField(blank=True, upload_to=get_image_path, default='/static/image/avatar/male.png')
age = models.IntegerField(default=4, validators=[MinValueValidator(3), MaxValueValidator(99)])
Django should automatically create a sequence for this field.
It may be that the User foreign key without an explicitly defined primary key is confusing the ORM, although that's just a theory.
If you are developing locally, and don't care about your migration history, and you just need a quick-fix, you could do this:
manage.py migrate <your app name> zero
Then delete the migration files except for the __init__.py in <your app name>.
Finally:
manage.py makemigrations <your app name>
manage.py migrate
A more complicated approach would be learning how to write and modify migration files to populate existing rows.

Tango with Django tutorial: "table rango_category has no column named views"

I've been stuck on this for a while and have gone through all of the suggestions already posted on here and it still won't recognize the column.
So I'm getting this:
DatabaseError at /admin/rango/category/add/
table rango_category has no column named views
Request Method: POST
Request URL: http://127.0.0.1:8000/admin/rango/category/add/
Django Version: 1.5.4
Exception Type: DatabaseError
Exception Value:
table rango_category has no column named views
Here is my models.py for rango
from django.db import models
class Category(models.Model):
name = models.CharField(max_length=128, unique=True)
views = models.IntegerField(default=0)
likes = models.IntegerField(default=0)
class Meta:
verbose_name_plural = "Categories" # otherwise writes "Categorys"
def __unicode__(self):
return self.name
class Page(models.Model):
category = models.ForeignKey(Category)
title = models.CharField(max_length=128)
url = models.URLField() # can include max_length if desired
views = models.IntegerField(default=0)
def __unicode__(self):
return self.title
I've already tried deleting the DB using python manage.py flush then doing python manage.py syncdb and it gives the same error. When I do python manage.py sql rango, I get:
BEGIN;
CREATE TABLE "rango_category" (
"id" integer NOT NULL PRIMARY KEY,
"name" varchar(128) NOT NULL UNIQUE,
"views" integer NOT NULL,
"likes" integer NOT NULL
)
;
CREATE TABLE "rango_page" (
"id" integer NOT NULL PRIMARY KEY,
"category_id" integer NOT NULL REFERENCES "rango_category" ("id"),
"title" varchar(128) NOT NULL,
"url" varchar(200) NOT NULL,
"views" integer NOT NULL
)
;
... so I'm pretty sure the column named "views" is there. Any help would be much appreciated!
Are you using SQLite? Look at the warning in this section of your tutorial:
http://www.tangowithdjango.com/book/chapters/models.html#creating-and-synchronising-the-database
Whenever you add to existing database models, you will have to delete the database file and then re-sync the database by running python manage.py syncb again. This is a drawback of Django 1.5.4, and can be quite frustrating. If you however add a new model, you can syncdb your database without having to delete and recreate it. You must therefore bear this in mind when tweaking your database: new models will be synchronised with syncdb - but changes to existing models will not be.
So, I'd delete the sqlite file, then run manage.py syncdb again.
Note: Django 1.7 is so much better, and there is a beta tutorial for it online.

Categories

Resources