django.db.utils.IntegrityError: (1062, "Duplicate entry '' for key 'slug'") - python

I'm trying to follow the tangowithdjango book and must add a slug to update the category table. However I'm getting an error after trying to migrate the databases.
http://www.tangowithdjango.com/book17/chapters/models_templates.html#creating-a-details-page
I didn't provide a default value for the slug, so Django asked me to provide one and as the book instructed I type in ''.
It's worth noticing that instead of using sqlite as in the original book I'm using mysql.
models.py
from django.db import models
from django.template.defaultfilters import slugify
# Create your models here.
class Category(models.Model):
name = models.CharField(max_length=128, unique=True)
views = models.IntegerField(default=0)
likes = models.IntegerField(default=0)
slug = models.SlugField(unique=True)
def save(self, *args, **kwargs):
self.slug = slugify(self.name)
super(Category, self).save(*args, **kwargs)
class Meta:
verbose_name_plural = "Categories"
def __unicode__(self):
return self.name
class Page(models.Model):
category = models.ForeignKey(Category)
title = models.CharField(max_length=128)
url = models.URLField()
views = models.IntegerField(default=0)
def __unicode__(self):
return self.title
The command prompt
sudo python manage.py migrate
Operations to perform:
Apply all migrations: admin, rango, contenttypes, auth, sessions
Running migrations:
Applying rango.0003_category_slug...Traceback (most recent call last):
File "manage.py", line 10, in <module>
execute_from_command_line(sys.argv)
File "/usr/local/lib/python2.7/dist-packages/django/core/management/__init__.py", line 385, in execute_from_command_line
utility.execute()
File "/usr/local/lib/python2.7/dist-packages/django/core/management/__init__.py", line 377, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/usr/local/lib/python2.7/dist-packages/django/core/management/base.py", line 288, in run_from_argv
self.execute(*args, **options.__dict__)
File "/usr/local/lib/python2.7/dist-packages/django/core/management/base.py", line 338, in execute
output = self.handle(*args, **options)
File "/usr/local/lib/python2.7/dist-packages/django/core/management/commands/migrate.py", line 160, in handle
executor.migrate(targets, plan, fake=options.get("fake", False))
File "/usr/local/lib/python2.7/dist-packages/django/db/migrations/executor.py", line 63, in migrate
self.apply_migration(migration, fake=fake)
File "/usr/local/lib/python2.7/dist-packages/django/db/migrations/executor.py", line 97, in apply_migration
migration.apply(project_state, schema_editor)
File "/usr/local/lib/python2.7/dist-packages/django/db/migrations/migration.py", line 107, in apply
operation.database_forwards(self.app_label, schema_editor, project_state, new_state)
File "/usr/local/lib/python2.7/dist-packages/django/db/migrations/operations/fields.py", line 37, in database_forwards
field,
File "/usr/local/lib/python2.7/dist-packages/django/db/backends/mysql/schema.py", line 42, in add_field
super(DatabaseSchemaEditor, self).add_field(model, field)
File "/usr/local/lib/python2.7/dist-packages/django/db/backends/schema.py", line 411, in add_field
self.execute(sql, params)
File "/usr/local/lib/python2.7/dist-packages/django/db/backends/schema.py", line 98, in execute
cursor.execute(sql, params)
File "/usr/local/lib/python2.7/dist-packages/django/db/backends/utils.py", line 81, in execute
return super(CursorDebugWrapper, self).execute(sql, params)
File "/usr/local/lib/python2.7/dist-packages/django/db/backends/utils.py", line 65, in execute
return self.cursor.execute(sql, params)
File "/usr/local/lib/python2.7/dist-packages/django/db/utils.py", line 94, in __exit__
six.reraise(dj_exc_type, dj_exc_value, traceback)
File "/usr/local/lib/python2.7/dist-packages/django/db/backends/utils.py", line 65, in execute
return self.cursor.execute(sql, params)
File "/usr/local/lib/python2.7/dist-packages/django/db/backends/mysql/base.py", line 128, in execute
return self.cursor.execute(query, args)
File "/usr/local/lib/python2.7/dist-packages/MySQLdb/cursors.py", line 205, in execute
self.errorhandler(self, exc, value)
File "/usr/local/lib/python2.7/dist-packages/MySQLdb/connections.py", line 36, in defaulterrorhandler
raise errorclass, errorvalue
django.db.utils.IntegrityError: (1062, "Duplicate entry '' for key 'slug'")

Let's analyse it step by step:
You're adding slug field with unique = True, that means: each record must have different value, there can't be two records with same value in slug
You're creating migration: django asks you for default value for fields that exists already in database, so you provided '' (empty string) as that value.
Now django is trying to migrate your database. In database we have at least 2 records
First record is migrated, slug column is populated with empty string. That's good because no other record is having empty string in slug field
Second record is migrated, slug column is populated with empty string. That fails, because first record already have empty string in slug field. Exception is raised and migration is aborted.
That's why your migration fails. All you should do is to edit migration, copy migrations.AlterField operation twice, in first operation remove unique=True. Between that operations you should put migrations.RunPython operation and provide 2 parameters into that: generate_slugs and migrations.RunPython.noop.
Now you must create inside your migration function BEFORE migration class, name that function generate_slugs. Function should take 2 arguments: apps and schema_editor. In your function put at first line:
Category = apps.get_model('your_app_name', 'Category')
and now use Category.objects.all() to loop all your records and provide unique slug for each of them.

If you have more than one category in your table, then you cannot have unique=True and default='', because then you will have more than one category with slug=''. If your tutorial says to do this, then it's bad advice, although it might work in SQLite.
The correct approach to add a unique field to a model is:
Delete your current migration that isn't working.
Add the slug field, with unique=False. Create a new migration and run it.
Set a unique slug for every category. It sounds like the rango populate script might do this. Alternatively, you could write a migration to set the slugs, or even set them manually in the Django admin.
Change the slug field to unique=True. Create a new migration and run it.
If that's too difficult, then you could delete all your categories from your database except one. Then your current migration will run without having problems with the unique constraint. You can add the categories again afterwards.

You must have rows in your table already with empty slugs, which is a violation of the mysql unique constraint you created. You can update them manually by running manage.py dbshell to get to the mysql client, then updating the offending rows, e.g.
update table rango_category set slug = name where slug = '';
(assuming the rows with blank slugs have names). Or you can delete the rows with
delete from rango_category where slug = '';
After that, you should be able to run your migrations.

Related

"auth_user does not exist" when doing unit testing in django

I've been trying to solve this error for a week now and I can't seem to figure out how to fix this error. No one else who is using this repository is having the same problem as I am (I am up to date with the origin), so it has to be some sort of local issue, but I can't figure out what it would be.
This happens everytime I try to run the django unit tests that we have written. There are no problems when I runserver or when I do migrations, only when testing:
python manage.py test
_______ERROR MESSAGE:_________
Liams-MBP:GrammieGram Liam2$ python manage.py test grams
Creating test database for alias 'default'...
Traceback (most recent call last):
File "/Users/Liam2/anaconda3/lib/python3.6/site-packages/django/db/backends/utils.py", line 64, in execute
return self.cursor.execute(sql, params)
psycopg2.ProgrammingError: relation "auth_user" does not exist
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "manage.py", line 22, in <module>
execute_from_command_line(sys.argv)
File "/Users/Liam2/anaconda3/lib/python3.6/site-packages/django/core/management/__init__.py", line 364, in execute_from_command_line
utility.execute()
File "/Users/Liam2/anaconda3/lib/python3.6/site-packages/django/core/management/__init__.py", line 356, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/Users/Liam2/anaconda3/lib/python3.6/site-packages/django/core/management/commands/test.py", line 29, in run_from_argv
super(Command, self).run_from_argv(argv)
File "/Users/Liam2/anaconda3/lib/python3.6/site-packages/django/core/management/base.py", line 283, in run_from_argv
self.execute(*args, **cmd_options)
File "/Users/Liam2/anaconda3/lib/python3.6/site-packages/django/core/management/base.py", line 330, in execute
output = self.handle(*args, **options)
File "/Users/Liam2/anaconda3/lib/python3.6/site-packages/django/core/management/commands/test.py", line 62, in handle
failures = test_runner.run_tests(test_labels)
File "/Users/Liam2/anaconda3/lib/python3.6/site-packages/django/test/runner.py", line 601, in run_tests
old_config = self.setup_databases()
File "/Users/Liam2/anaconda3/lib/python3.6/site-packages/django/test/runner.py", line 546, in setup_databases
self.parallel, **kwargs
File "/Users/Liam2/anaconda3/lib/python3.6/site-packages/django/test/utils.py", line 187, in setup_databases
serialize=connection.settings_dict.get('TEST', {}).get('SERIALIZE', True),
File "/Users/Liam2/anaconda3/lib/python3.6/site-packages/django/db/backends/base/creation.py", line 69, in create_test_db
run_syncdb=True,
File "/Users/Liam2/anaconda3/lib/python3.6/site-packages/django/core/management/__init__.py", line 131, in call_command
return command.execute(*args, **defaults)
File "/Users/Liam2/anaconda3/lib/python3.6/site-packages/django/core/management/base.py", line 330, in execute
output = self.handle(*args, **options)
File "/Users/Liam2/anaconda3/lib/python3.6/site-packages/django/core/management/commands/migrate.py", line 173, in handle
self.sync_apps(connection, executor.loader.unmigrated_apps)
File "/Users/Liam2/anaconda3/lib/python3.6/site-packages/django/core/management/commands/migrate.py", line 311, in sync_apps
self.stdout.write(" Running deferred SQL...\n")
File "/Users/Liam2/anaconda3/lib/python3.6/site-packages/django/db/backends/base/schema.py", line 93, in __exit__
self.execute(sql)
File "/Users/Liam2/anaconda3/lib/python3.6/site-packages/django/db/backends/base/schema.py", line 120, in execute
cursor.execute(sql, params)
File "/Users/Liam2/anaconda3/lib/python3.6/site-packages/django/db/backends/utils.py", line 64, in execute
return self.cursor.execute(sql, params)
File "/Users/Liam2/anaconda3/lib/python3.6/site-packages/django/db/utils.py", line 94, in __exit__
six.reraise(dj_exc_type, dj_exc_value, traceback)
File "/Users/Liam2/anaconda3/lib/python3.6/site-packages/django/utils/six.py", line 685, in reraise
raise value.with_traceback(tb)
File "/Users/Liam2/anaconda3/lib/python3.6/site-packages/django/db/backends/utils.py", line 64, in execute
return self.cursor.execute(sql, params)
django.db.utils.ProgrammingError: relation "auth_user" does not exist
My grams/models.py
from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
import datetime
import uuid
from django.contrib.postgres.fields import ArrayField
from django.db.models.signals import post_save
from django.dispatch import receiver
"""
#brief A class that describes a user profile.
#field user - the username of the user
#field usertype - the type of user profile (sender/receiver)
#filed contacts - the user's contact book, list of people they can contact
#field admins - and a list of admins, list of users who have admin
privileges over this Profile object
"""
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
usertype = models.CharField(max_length=30, default="sender")
contacts = ArrayField(models.CharField(max_length=150, default="default"), default=[])
admins = ArrayField(models.CharField(max_length=150, default="default"), default=[])
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
"""
#brief Describes a gram message that a sender type Profile is
able to send to a receiver type Profile.
#field send_username - the username of the sender profile
#field recp_username - the username of the receiver profile
#field sent_time - the time at which the Gram object was sent
#field display_until - the amount of time the Gram object will be visible
"""
class Gram(models.Model):
message = models.CharField(max_length=240)
send_username = models.CharField(max_length=150, default="default")
recp_username = models.CharField(max_length=150, default="default")
sent_time = models.DateTimeField(null=True)
display_until = models.DateTimeField(null=True)
def __str__(self):
return self.message
#function checks if another user can be added to the list of contacts
#active_user_type - logged in user; new_contact - the contact to be added
def validated_contact_add(active_user_type,new_contact):
#check if the contact exists in the list of users
if User.objects.filter(username=new_contact).exists():
#check if the type of the logged in user is different from the one being added
if active_user_type != Profile.objects.get(user=User.objects.get(username = new_contact)).usertype:
return "valid"
else:
return "wrong type"
else:
return "does not exist"
_________THINGS I'VE TRIED TO RESOLVE THIS (but failed):_______________
deleting db
deleting local repository and recloning, and deleting db
makemigrations auth and makemigrations (there were no
migrations to make)
using --fake (as suggested in
Django 1.8 test issue: ProgrammingError: relation "auth_user" does not exist)
turning computer on an off again (as you can see, I'm pretty desperate)
Ok, so it turned out that some migrations were being skipped (?) when calling python manage.py makemigrations so I had to specify which app that I wanted to make migrations for. Calling python manage.py makemigrations grams (my target app name) fixed the problem.

Django: dynamic model fields and migrations

I have problems understanding how django's model fields work. What I want to achieve is something like a PriceField (DecimalField), that dynamically creates/injects another model field, let's say a currency (CharField) field.
I have read an interesing blog posts about this topic at https://blog.elsdoerfer.name/2008/01/08/fuzzydates-or-one-django-model-field-multiple-database-columns/. I think (and hope) that I've understood the core messages of the articles. But as most of them are a little bit outdated, I don't know if they are still valid for current django versions and my below code.
I use Django 1.11.4, Python 3.6.2, and a clean app created with ./manage.py startapp testing. The code in models.py:
from django.db import models
from django.db.models import signals
_currency_field_name = lambda name: '{}_extension'.format(name)
class PriceField(models.DecimalField):
def contribute_to_class(self, cls, name):
# add the extra currency field (CharField) to the class
if not cls._meta.abstract:
currency_field = models.CharField(
max_length=3,
editable=False,
null=True,
blank=True
)
cls.add_to_class(_currency_field_name(name), currency_field)
# add the original price field (DecimalField) to the class
super().contribute_to_class(cls, name)
# TODO: set the descriptor
# setattr(cls, self.name, FooDescriptor(self))
class FooModel(models.Model):
price = PriceField('agrhhhhh', decimal_places=3, max_digits=10, blank=True, null=True)
The problems come if I try to create migrations for that models. If executing python manage.py makemigrations following message is shown:
Migrations for 'testing':
testing/migrations/0001_initial.py
- Create model FooModel
Migration file 0001_initial.py has the following content:
# Generated by Django 1.11.4 on 2017-09-11 18:02
from __future__ import unicode_literals
from django.db import migrations, models
import testing.models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='FooModel',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('price', testing.models.PriceField(blank=True, decimal_places=3, max_digits=10, null=True, verbose_name='agrhhhhh')),
('price_extension', models.CharField(blank=True, editable=False, max_length=3, null=True)),
],
),
]
For me this looks OK so far. But if I then execute ./manage.py migrate testing, django shouts:
Operations to perform:
Apply all migrations: testing
Running migrations:
Applying testing.0001_initial...Traceback (most recent call last):
File "/usr/local/var/pyenv/versions/stockmanagement-3.6.2/lib/python3.6/site-packages/django/db/backends/utils.py", line 63, in execute
return self.cursor.execute(sql)
File "/usr/local/var/pyenv/versions/stockmanagement-3.6.2/lib/python3.6/site-packages/django/db/backends/sqlite3/base.py", line 326, in execute
return Database.Cursor.execute(self, query)
sqlite3.OperationalError: duplicate column name: price_extension
Why does it error out on a duplicate column name: price_extension, when there is only one such field defined in the migrations file? Where does this duplicate field come from and is there a fix for this situation? Thanks!
Edit 1
This exception not only happens with an already existing database but also when I start with an empty database from scratch (deleting SQLite file). After the migrate command failed this is the structure of the DB:
./manage.py dbshell
sqlite> .tables
django_migrations
sqlite> .schema
CREATE TABLE "django_migrations" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, "app" varchar(255) NOT NULL, "name" varchar(255) NOT NULL, "applied" datetime NOT NULL);
sqlite> select * from django_migrations;
sqlite>
And full stacktrace:
./manage.py migrate testing
Operations to perform:
Apply all migrations: testing
Running migrations:
Applying testing.0001_initial...Traceback (most recent call last):
File "/usr/local/var/pyenv/versions/stockmanagement-3.6.2/lib/python3.6/site-packages/django/db/backends/utils.py", line 63, in execute
return self.cursor.execute(sql)
File "/usr/local/var/pyenv/versions/stockmanagement-3.6.2/lib/python3.6/site-packages/django/db/backends/sqlite3/base.py", line 326, in execute
return Database.Cursor.execute(self, query)
sqlite3.OperationalError: duplicate column name: price_extension
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "./manage.py", line 22, in <module>
execute_from_command_line(sys.argv)
File "/usr/local/var/pyenv/versions/stockmanagement-3.6.2/lib/python3.6/site-packages/django/core/management/__init__.py", line 363, in execute_from_command_line
utility.execute()
File "/usr/local/var/pyenv/versions/stockmanagement-3.6.2/lib/python3.6/site-packages/django/core/management/__init__.py", line 355, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/usr/local/var/pyenv/versions/stockmanagement-3.6.2/lib/python3.6/site-packages/django/core/management/base.py", line 283, in run_from_argv
self.execute(*args, **cmd_options)
File "/usr/local/var/pyenv/versions/stockmanagement-3.6.2/lib/python3.6/site-packages/django/core/management/base.py", line 330, in execute
output = self.handle(*args, **options)
File "/usr/local/var/pyenv/versions/stockmanagement-3.6.2/lib/python3.6/site-packages/django/core/management/commands/migrate.py", line 204, in handle
fake_initial=fake_initial,
File "/usr/local/var/pyenv/versions/stockmanagement-3.6.2/lib/python3.6/site-packages/django/db/migrations/executor.py", line 115, in migrate
state = self._migrate_all_forwards(state, plan, full_plan, fake=fake, fake_initial=fake_initial)
File "/usr/local/var/pyenv/versions/stockmanagement-3.6.2/lib/python3.6/site-packages/django/db/migrations/executor.py", line 145, in _migrate_all_forwards
state = self.apply_migration(state, migration, fake=fake, fake_initial=fake_initial)
File "/usr/local/var/pyenv/versions/stockmanagement-3.6.2/lib/python3.6/site-packages/django/db/migrations/executor.py", line 244, in apply_migration
state = migration.apply(state, schema_editor)
File "/usr/local/var/pyenv/versions/stockmanagement-3.6.2/lib/python3.6/site-packages/django/db/migrations/migration.py", line 129, in apply
operation.database_forwards(self.app_label, schema_editor, old_state, project_state)
File "/usr/local/var/pyenv/versions/stockmanagement-3.6.2/lib/python3.6/site-packages/django/db/migrations/operations/models.py", line 97, in database_forwards
schema_editor.create_model(model)
File "/usr/local/var/pyenv/versions/stockmanagement-3.6.2/lib/python3.6/site-packages/django/db/backends/base/schema.py", line 303, in create_model
self.execute(sql, params or None)
File "/usr/local/var/pyenv/versions/stockmanagement-3.6.2/lib/python3.6/site-packages/django/db/backends/base/schema.py", line 120, in execute
cursor.execute(sql, params)
File "/usr/local/var/pyenv/versions/stockmanagement-3.6.2/lib/python3.6/site-packages/django/db/backends/utils.py", line 80, in execute
return super(CursorDebugWrapper, self).execute(sql, params)
File "/usr/local/var/pyenv/versions/stockmanagement-3.6.2/lib/python3.6/site-packages/cachalot/monkey_patch.py", line 113, in inner
out = original(cursor, sql, *args, **kwargs)
File "/usr/local/var/pyenv/versions/stockmanagement-3.6.2/lib/python3.6/site-packages/django/db/backends/utils.py", line 65, in execute
return self.cursor.execute(sql, params)
File "/usr/local/var/pyenv/versions/stockmanagement-3.6.2/lib/python3.6/site-packages/django/db/utils.py", line 94, in __exit__
six.reraise(dj_exc_type, dj_exc_value, traceback)
File "/usr/local/var/pyenv/versions/stockmanagement-3.6.2/lib/python3.6/site-packages/django/utils/six.py", line 685, in reraise
raise value.with_traceback(tb)
File "/usr/local/var/pyenv/versions/stockmanagement-3.6.2/lib/python3.6/site-packages/django/db/backends/utils.py", line 63, in execute
return self.cursor.execute(sql)
File "/usr/local/var/pyenv/versions/stockmanagement-3.6.2/lib/python3.6/site-packages/django/db/backends/sqlite3/base.py", line 326, in execute
return Database.Cursor.execute(self, query)
django.db.utils.OperationalError: duplicate column name: price_extension
Edit 2
A git repository with the above code can be found under: https://github.com/hetsch/django_testing. This error happens also if one clones this repository (clean project without any DB), calls makemigrations and then migrate.
According to Django ticket #22555 https://code.djangoproject.com/ticket/22555, this method of adding fields is not officially supported. Nonetheless, I made it work with the following simple fix:
def contribute_to_class(self, cls, name):
# add the extra currency field (CharField) to the class
# and prevent adding another field instance if the
# field was allready attached.
if not cls._meta.abstract and not hasattr(cls, _currency_field_name(name)):
currency_field = models.CharField(
max_length=3,
editable=False,
null=True,
blank=True
)
cls.add_to_class(_currency_field_name(name), currency_field)

django.db.utils.OperationalError: 1005, 'Can't create table `xyz`.`#sql-600_237` (errno: 150 "Foreign key constraint is incorrectly formed")

I am trying to add One-to-One keys into my Django app, but I always get that error when I try to "migrate" process (makemigrations works great).
Applying xyzapp.0007_personne_extended_foreign...Traceback (most recent call last):
File "manage.py", line 29, in <module>
execute_from_command_line(sys.argv)
File "/opt/xyz/env/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 354, in execute_from_command_line
utility.execute()
File "/opt/xyz/env/local/lib/python2.7/site-packages/django/core/management/__init__.py", line 346, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/opt/xyz/env/local/lib/python2.7/site-packages/django/core/management/base.py", line 394, in run_from_argv
self.execute(*args, **cmd_options)
File "/opt/xyz/env/local/lib/python2.7/site-packages/django/core/management/base.py", line 445, in execute
output = self.handle(*args, **options)
File "/opt/xyz/env/local/lib/python2.7/site-packages/django/core/management/commands/migrate.py", line 222, in handle
executor.migrate(targets, plan, fake=fake, fake_initial=fake_initial)
File "/opt/xyz/env/local/lib/python2.7/site-packages/django/db/migrations/executor.py", line 110, in migrate
self.apply_migration(states[migration], migration, fake=fake, fake_initial=fake_initial)
File "/opt/xyz/env/local/lib/python2.7/site-packages/django/db/migrations/executor.py", line 148, in apply_migration
state = migration.apply(state, schema_editor)
File "/opt/xyz/env/local/lib/python2.7/site-packages/django/db/backends/base/schema.py", line 91, in __exit__
self.execute(sql)
File "/opt/xyz/env/local/lib/python2.7/site-packages/django/db/backends/base/schema.py", line 111, in execute
cursor.execute(sql, params)
File "/opt/xyz/env/local/lib/python2.7/site-packages/django/db/backends/utils.py", line 79, in execute
return super(CursorDebugWrapper, self).execute(sql, params)
File "/opt/xyz/env/local/lib/python2.7/site-packages/django/db/backends/utils.py", line 64, in execute
return self.cursor.execute(sql, params)
File "/opt/xyz/env/local/lib/python2.7/site-packages/django/db/utils.py", line 98, in __exit__
six.reraise(dj_exc_type, dj_exc_value, traceback)
File "/opt/xyz/env/local/lib/python2.7/site-packages/django/db/backends/utils.py", line 64, in execute
return self.cursor.execute(sql, params)
File "/opt/xyz/env/local/lib/python2.7/site-packages/django/db/backends/mysql/base.py", line 124, in execute
return self.cursor.execute(query, args)
File "/usr/lib/python2.7/dist-packages/MySQLdb/cursors.py", line 226, in execute
self.errorhandler(self, exc, value)
File "/usr/lib/python2.7/dist-packages/MySQLdb/connections.py", line 36, in defaulterrorhandler
raise errorvalue
django.db.utils.OperationalError: (1005, 'Can\'t create table `xyz`.`#sql-600_297` (errno: 150 "Foreign key constraint is incorrectly formed")')
That's what my models looks like :
class PersonVolunteer(models.Model):
person = models.OneToOneField(Person)
class Person(models.Model):
name = models.CharField(max_length=100)
And the migration process that cause the crash :
class Migration(migrations.Migration):
dependencies = [
('xyzapp', '0014_member_to_person'),
]
operations = [
migrations.CreateModel(
name='PersonVolunteer',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('personne', models.OneToOneField(to='xyzapp.Personne')),
],
),
]
However, all works correctly when I test it even after the migrate error. But if that error message appears during "migrate", that should not be something good happening. If there's no problem, it is possible to skip that last step which crash my migration ?
Can someone can say me why do I get that error message and how I can resolve it ?
Thank you very much and have a great day !
I have found a solution, may be not the cleaner, but god dammit it works, that's perfect for me.
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('cvmapp', '0006_person_extended'),
]
operations = [
migrations.AddField(
model_name='PersonVolunteer',
name='personne',
field=models.OneToOneField(related_name='info_volunteer', to='cvmapp.Person', db_constraint=False),
),
]
The trick was to add "db_constraint=False" as a parameter of the OneToOne field.
Please make sure all your MySQL tables are using the same storage engine (i.e. MyISM v. InnoDB). Especially tables that have ForeignKeys between them.
If you need more information about MySQL storage engines and how to know which one(s) are you using you will need to read the MySQL documentation, although the MySQL notes in our database docs also have some introductory information.
I suspect you had tables created with the MyISAM storage engine (the default for MySQL < 5.5) and since MySQL 5.5 defaults to InnoDB and you created new tables since then, you ended with a mix
You can change the table storage engine from phpMyadmin. Click on your teble name, go to the 'operations' tab, and change in the "Table Operation" box. Convert all or your storage engine to the same.
First thing to do should be checking table's storage engines. However, in my case storage engines were same (both INNODB). My issue was unmatched collation of tables. After setting default char-set of the Database, my problem has been solved.
You can check table details with;
SHOW TABLE STATUS WHERE Name = "yyyyyyy";
Once you figure out your table's (that will be ForeignKey) collation, you can set your database default char-set as shown here like this:
ALTER DATABASE my_db COLLATE = 'latin1_swedish_ci';
Look at the output of the command SHOW ENGINE INNODB STATUS in MySql or MariaDB console client (mariadb link, mysql link). It`s more informative than error message.
For example, it showed me this message:
...
------------------------
LATEST FOREIGN KEY ERROR
------------------------
2021-09-20 18:27:08 7faea3ad1700 Error in foreign key constraint of table `my_db`.`django_admin_log`:
Alter table `my_db`.`django_admin_log` with foreign key constraint failed. Referenced table `my_db`.`profiles_userprofile` not found in the data dictionary near ' FOREIGN KEY (`user_id`) REFERENCES `profiles_userprofile` (`id`)'.
...
It said to me that I forgot to create migrations.

Django: model OneToOneField with User can't add default value

I have an model and I want to add an OneToOneField to hold the creator of an object:
models.py
creator = models.OneToOneField(User, blank=True,
default=User.objects.filter(
username="antoni4040"))
I already have a database with items and just want the default value to be the admin user, which has the username "antoni4040". When I try to migrate without the default field it asks for a default value, so I can't get away with it. But here's what I get when running makemigrations:
Migrations for 'jokes_app':
0008_joke_creator.py:
- Add field creator to joke
Traceback (most recent call last):
File "./manage.py", line 10, in <module>
execute_from_command_line(sys.argv)
File "/home/antoni4040/Documents/Jokes_Website/django-jokes/venv/lib/python3.4/site-packages/django/core/management/__init__.py", line 353, in execute_from_command_line
utility.execute()
File "/home/antoni4040/Documents/Jokes_Website/django-jokes/venv/lib/python3.4/site-packages/django/core/management/__init__.py", line 345, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/home/antoni4040/Documents/Jokes_Website/django-jokes/venv/lib/python3.4/site-packages/django/core/management/base.py", line 348, in run_from_argv
self.execute(*args, **cmd_options)
File "/home/antoni4040/Documents/Jokes_Website/django-jokes/venv/lib/python3.4/site-packages/django/core/management/base.py", line 399, in execute
output = self.handle(*args, **options)
File "/home/antoni4040/Documents/Jokes_Website/django-jokes/venv/lib/python3.4/site-packages/django/core/management/commands/makemigrations.py", line 150, in handle
self.write_migration_files(changes)
File "/home/antoni4040/Documents/Jokes_Website/django-jokes/venv/lib/python3.4/site-packages/django/core/management/commands/makemigrations.py", line 178, in write_migration_files
migration_string = writer.as_string()
File "/home/antoni4040/Documents/Jokes_Website/django-jokes/venv/lib/python3.4/site-packages/django/db/migrations/writer.py", line 167, in as_string
operation_string, operation_imports = OperationWriter(operation).serialize()
File "/home/antoni4040/Documents/Jokes_Website/django-jokes/venv/lib/python3.4/site-packages/django/db/migrations/writer.py", line 124, in serialize
_write(arg_name, arg_value)
File "/home/antoni4040/Documents/Jokes_Website/django-jokes/venv/lib/python3.4/site-packages/django/db/migrations/writer.py", line 88, in _write
arg_string, arg_imports = MigrationWriter.serialize(_arg_value)
File "/home/antoni4040/Documents/Jokes_Website/django-jokes/venv/lib/python3.4/site-packages/django/db/migrations/writer.py", line 433, in serialize
return cls.serialize_deconstructed(path, args, kwargs)
File "/home/antoni4040/Documents/Jokes_Website/django-jokes/venv/lib/python3.4/site-packages/django/db/migrations/writer.py", line 318, in serialize_deconstructed
arg_string, arg_imports = cls.serialize(arg)
File "/home/antoni4040/Documents/Jokes_Website/django-jokes/venv/lib/python3.4/site-packages/django/db/migrations/writer.py", line 517, in serialize
item_string, item_imports = cls.serialize(item)
File "/home/antoni4040/Documents/Jokes_Website/django-jokes/venv/lib/python3.4/site-packages/django/db/migrations/writer.py", line 540, in serialize
"topics/migrations/#migration-serializing" % (value, get_docs_version())
ValueError: Cannot serialize: <User: antoni4040>
There are some values Django cannot serialize into migration files.
For more, see https://docs.djangoproject.com/en/1.9/topics/migrations/#migration-serializing
What am I doing wrong?
You are using the queryset User.objects.filter(username="antoni4040"). To get a model instance, you would use User.objects.get(username="antoni4040").
However, you shouldn't use a a model instance for as the default in the model field. There's no error handling if the user does not exist in the database. In fact, if models.py is loaded before you run the initial migrations, then the User table won't even exist so the query will give an error.
The logic to set the default user should go in the view (or Django admin) instead of the models file.
In the admin, you could define a custom form that sets the initial value for the creator field.
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
def __init__(self, *args, **kwargs):
try:
user = User.objects.get(username="antoni4040")
kwargs['initial']['creator'] = user
except MyModel.DoesNotExist:
pass
super(MyModelForm, self).__init__(*args, **kwargs)
Then use that model form in your admin.
class MyModelAdmin(admin.ModelAdmin):
form = MyModelForm
...
If you really wanted to do this you can open up a shell and get the id for that User, then set the default to that.
The problem is, why would you do that? The first time you add a model it will use the default correctly. The second time you try to do that, it will fail because it's one to one, not many to one, so it will fail.

Django how to add foreignkey - multiple choices

Hello i created two models and second must use this first, for example first model is product and second is shop which contains few products.
from django.db import models
# Create your models here.
class Product(models.Model):
name = models.CharField("name", max_length=40)
price = models.FloatField("price")
def __unicode__(self):
return self.name
class Shop(models.Model):
product = models.ForeignKey(Product, null = True)
name = models.CharField("shopname", max_length=40)
salary = models.FloatField("salary")
def __unicode__(self):
return self.name
Is it good start? I want create something which will give me possibility to add many Product.models to Shop.model. How to create it?
And second problem is - now when i click
python manage.py migrate homebudget
i have information
(venv) C:\Users\noname\nowe\budget>python manage.py makemigrations homebudget
Migrations for 'homebudget':
0011_auto_20150513_1817.py:
- Alter field price on product
- Alter field name on product
- Alter field name on shop
- Alter field salary on shop
(venv) C:\Users\noname\nowe\budget>python manage.py migrate homebudget
Operations to perform:
Apply all migrations: homebudget
Running migrations:
Rendering model states... DONE
Applying homebudget.0002_shop_product...Traceback (most recent call las
t):
File "manage.py", line 10, in <module>
execute_from_command_line(sys.argv)
File "C:\Users\noname\nowe\venv\lib\site-packages\django\core\management\__init_
_.py", line 338, in execute_from_command_line
utility.execute()
File "C:\Users\noname\nowe\venv\lib\site-packages\django\core\management\__init_
_.py", line 330, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "C:\Users\noname\nowe\venv\lib\site-packages\django\core\management\base.py
", line 390, in run_from_argv
self.execute(*args, **cmd_options)
File "C:\Users\noname\nowe\venv\lib\site-packages\django\core\management\base.py
", line 441, in execute
output = self.handle(*args, **options)
File "C:\Users\noname\nowe\venv\lib\site-packages\django\core\management\command
s\migrate.py", line 221, in handle
executor.migrate(targets, plan, fake=fake, fake_initial=fake_initial)
File "C:\Users\noname\nowe\venv\lib\site-packages\django\db\migrations\executor.
py", line 110, in migrate
self.apply_migration(states[migration], migration, fake=fake, fake_initial=f
ake_initial)
File "C:\Users\noname\nowe\venv\lib\site-packages\django\db\migrations\executor.
py", line 147, in apply_migration
state = migration.apply(state, schema_editor)
File "C:\Users\noname\nowe\venv\lib\site-packages\django\db\migrations\migration
.py", line 115, in apply
operation.database_forwards(self.app_label, schema_editor, old_state, projec
t_state)
File "C:\Users\noname\nowe\venv\lib\site-packages\django\db\migrations\operation
s\fields.py", line 62, in database_forwards
field,
File "C:\Users\noname\nowe\venv\lib\site-packages\django\db\backends\sqlite3\sch
ema.py", line 176, in add_field
self._remake_table(model, create_fields=[field])
File "C:\Users\noname\nowe\venv\lib\site-packages\django\db\backends\sqlite3\sch
ema.py", line 74, in _remake_table
self.effective_default(field)
File "C:\Users\noname\nowe\venv\lib\site-packages\django\db\backends\base\schema
.py", line 194, in effective_default
default = field.get_default()
File "C:\Users\noname\nowe\venv\lib\site-packages\django\db\models\fields\relate
d.py", line 1930, in get_default
if isinstance(field_default, self.rel.to):
TypeError: isinstance() arg 2 must be a class, type, or tuple of classes and typ
es
(venv) C:\Users\noname\nowe\budget>
Running this code doesn't give me any errors, but it looks like nofinator has a point that the field calls don't expect names as positional arguments. If you want them it would probably be better to use verbose_name e.g.,
salary = models.FloatField(verbose_name="salary")
But it doesn't make a lot of sense until you use it to give a more human readable name.
I think you need quotes around 'Product' when defining the foreign key:
product = models.ForeignKey('Product', null = True)
If you need to create a relationship on a model that has not yet been
defined, you can use the name of the model, rather than the model
object itself:
https://docs.djangoproject.com/en/1.8/ref/models/fields/#django.db.models.ForeignKey
You probably want to use a models.ManyToManyField not a Foreign Key. The way you have it written now is a Product can have many Shops.
At the very least you'd want the Shop to have many Products; in that case to have a ForeginKey in Product in that case.
You need to write verbose_name="salary", etc. to get rid of the problem.

Categories

Resources