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:
slug
field with unique = True
, that means: each record must have different value, there can't be two records with same value in slug
slug
fieldslug
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:
unique=False
. Create a new migration and run it.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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With