Related
I have a model called "Employment" in my app, which references two models called "User" and "Company". In the Employments table in the database, there is a composite index on the two foreign keys preventing the same user from having two employments with the same company. I am trying to represent this composite index in Django using the UniqueConstraint class, but it is throwing an error which I cannot find any documentation for.
This model usually works perfectly fine. However, when I add the UniqueConstraint to the model's indexes, the server throws an error. I've looked at the documentation for UniqueConstraint, as well as the rest of Django's documentation, but could not find any mentions of the error I receive. I've also tried replacing 'User_ID' and 'Company_ID' with 'user' and 'company' in the fields argument for UniqueConstraint, but I obtained the exact same error.
Not sure if this is relevant to the issue, but I'm running the Django server with Docker in a python:3.6 container with Django version 2.2.
Here is the Employment model:
from django.db import models
from app.models import User, Company
class Employment(models.Model):
Employment_ID = models.AutoField(primary_key=True)
user = models.ForeignKey(User, db_column='User_ID', on_delete=models.CASCADE)
company = models.ForeignKey(Company, db_column='Company_ID', on_delete=models.CASCADE)
class Meta:
db_table = "Employments"
indexes = [
models.UniqueConstraint(fields=['User_ID', 'Company_ID'],
name='Employment_User_Company_UNIQUE') # server works fine without this
]
When I start my Django server, I get the following output:
Watching for file changes with StatReloader
Performing system checks...
Exception in thread Thread-1:
Traceback (most recent call last):
File "/usr/local/lib/python3.6/threading.py", line 916, in _bootstrap_inner
self.run()
File "/usr/local/lib/python3.6/threading.py", line 864, in run
self._target(*self._args, **self._kwargs)
File "/usr/local/lib/python3.6/site-packages/django/utils/autoreload.py", line 54, in wrapper
fn(*args, **kwargs)
File "/usr/local/lib/python3.6/site-packages/django/core/management/commands/runserver.py", line 117, in inner_run
self.check(display_num_errors=True)
File "/usr/local/lib/python3.6/site-packages/django/core/management/base.py", line 390, in check
include_deployment_checks=include_deployment_checks,
File "/usr/local/lib/python3.6/site-packages/django/core/management/base.py", line 377, in _run_checks
return checks.run_checks(**kwargs)
File "/usr/local/lib/python3.6/site-packages/django/core/checks/registry.py", line 72, in run_checks
new_errors = check(app_configs=app_configs)
File "/usr/local/lib/python3.6/site-packages/django/core/checks/model_checks.py", line 31, in check_all_models
errors.extend(model.check(**kwargs))
File "/usr/local/lib/python3.6/site-packages/django/db/models/base.py", line 1254, in check
*cls._check_indexes(),
File "/usr/local/lib/python3.6/site-packages/django/db/models/base.py", line 1565, in _check_indexes
fields = [field for index in cls._meta.indexes for field, _ in index.fields_orders]
File "/usr/local/lib/python3.6/site-packages/django/db/models/base.py", line 1565, in <listcomp>
fields = [field for index in cls._meta.indexes for field, _ in index.fields_orders]
AttributeError: 'UniqueConstraint' object has no attribute 'fields_orders'
If anyone has experienced this error or knows of a workaround, I would be very grateful for your insight.
You defined this in the indexes parameter, but this should be in the constraints [Django-doc] attribute. indexes contains, as the name suggests, the list of indexes defined on the table. constraints on the other hand contains the constraints that should be enforced.
class Employment(models.Model):
Employment_ID = models.AutoField(primary_key=True)
user = models.ForeignKey(User, db_column='User_ID', on_delete=models.CASCADE)
company = models.ForeignKey(Company, db_column='Company_ID', on_delete=models.CASCADE)
class Meta:
db_table = "Employments"
constraints = [
models.UniqueConstraint(
fields=['User_ID', 'Company_ID'],
name='Employment_User_Company_UNIQUE'
)
]
So I have been trying to implement a way to upload multiple images to a post. The way I did it is to have tables. One for the actual post, and one of the multiple images uploaded. I was planning to link them with a foreign key but it is not working. My terminal started throwing the error "TypeError: id() takes exactly one argument (0 given)" . It throws me this error whenever I migrate it.
I am not sure how to fix this.
MY code:
models.py
from django.db import models
from django.utils import timezone
from django.forms import ModelForm
from django.utils.text import slugify
from django.utils.crypto import get_random_string
from django.conf import settings
from PIL import Image
import os
DEFAULT_IMAGE_ID = 1
# Create your models here.
class Projects(models.Model):
title = models.CharField(max_length=30)
description = models.TextField(max_length=150)
publish_date = models.DateTimeField(auto_now=False, auto_now_add=True)
update_date = models.DateTimeField(auto_now=True, auto_now_add=False)
slug = models.SlugField(unique=True)
files = models.FileField(upload_to='files/', blank=True)
images = models.ImageField(upload_to='images/', height_field = 'img_height', width_field = 'img_width',blank=True)
img_height = models.PositiveIntegerField(default=600)
img_width = models.PositiveIntegerField(default=300)
#feature_images = models.ForeignKey(P_Images, on_delete=models.CASCADE, default=DEFAULT_IMAGE_ID)
feature_images = models.AutoField(primary_key=True)
def __str__(self):
return self.title
def save(self, *args, **kwargs):
# Generates a random string
unique_string = get_random_string(length=32)
# Combines title and unique string to slugify
slugtext = self.title + "-" + "unique_id=-" + unique_string
self.slug = slugify(slugtext)
return super(Projects, self).save(*args, **kwargs)
class P_Images(models.Model):
p_file = models.ImageField(upload_to='images/', blank=None)
p_uploaded_at = models.DateTimeField(auto_now_add=True, auto_now=False)
#fk_post = models
fk_post = models.ForeignKey(Projects, on_delete=models.CASCADE)
The errorlog
Operations to perform:
Apply all migrations: admin, auth, contenttypes, projects, sessions
Running migrations:
Applying projects.0005_auto_20180823_0553...Traceback (most recent call last):
File "manage.py", line 15, in <module>
execute_from_command_line(sys.argv)
File "/home/erichardson/env01/lib/python3.6/site-packages/django/core/management/__init__.py", line 371, in execute_from_command_line
utility.execute()
File "/home/erichardson/env01/lib/python3.6/site-packages/django/core/management/__init__.py", line 365, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/home/erichardson/env01/lib/python3.6/site-packages/django/core/management/base.py", line 288, in run_from_argv
self.execute(*args, **cmd_options)
File "/home/erichardson/env01/lib/python3.6/site-packages/django/core/management/base.py", line 335, in execute
output = self.handle(*args, **options)
File "/home/erichardson/env01/lib/python3.6/site-packages/django/core/management/commands/migrate.py", line 200, in handle
fake_initial=fake_initial,
File "/home/erichardson/env01/lib/python3.6/site-packages/django/db/migrations/executor.py", line 117, in migrate
state = self._migrate_all_forwards(state, plan, full_plan, fake=fake, fake_initial=fake_initial)
File "/home/erichardson/env01/lib/python3.6/site-packages/django/db/migrations/executor.py", line 147, in _migrate_all_forwards
state = self.apply_migration(state, migration, fake=fake, fake_initial=fake_initial)
File "/home/erichardson/env01/lib/python3.6/site-packages/django/db/migrations/executor.py", line 244, in apply_migration
state = migration.apply(state, schema_editor)
File "/home/erichardson/env01/lib/python3.6/site-packages/django/db/migrations/migration.py", line 122, in apply
operation.database_forwards(self.app_label, schema_editor, old_state, project_state)
File "/home/erichardson/env01/lib/python3.6/site-packages/django/db/migrations/operations/fields.py", line 216, in database_forwards
schema_editor.alter_field(from_model, from_field, to_field)
File "/home/erichardson/env01/lib/python3.6/site-packages/django/db/backends/base/schema.py", line 525, in alter_field
old_db_params, new_db_params, strict)
File "/home/erichardson/env01/lib/python3.6/site-packages/django/db/backends/base/schema.py", line 630, in _alter_field
new_default = self.effective_default(new_field)
File "/home/erichardson/env01/lib/python3.6/site-packages/django/db/backends/base/schema.py", line 218, in effective_default
default = field.get_default()
File "/home/erichardson/env01/lib/python3.6/site-packages/django/db/models/fields/__init__.py", line 775, in get_default
return self._get_default()
TypeError: id() takes exactly one argument (0 given)
I use a MySQL database for this. This error started popping up after I updated my tables to be able to link with each other. I plan the fk_post of the P_Images to contain the feature_image value of Projects for the foreign key.
005_migration.py
import builtins
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('projects', '0004_auto_20180823_0547'),
]
operations = [
migrations.AlterField(
model_name='p_images',
name='fk_post',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='projects.Projects'),
),
migrations.AlterField(
model_name='projects',
name='feature_images',
field=models.IntegerField(default=builtins.id),
),
]
please let me know if the migration.py tells you something or nothing.
You have something very bizarre in your migration:
models.IntegerField(default=builtins.id)
This is referring to the builtin id function, which requires an argument because it returns the internal ID of an object in Python. It has nothing to do with database IDs, and doesn't belong here at all. I can only guess that you were asked for a default when creating the migration and you just typed in id.
You should delete that default from the migration, but that may make it unable to execute. You could also try a default of 0, which makes sense there; but your actual models code shows that field as the primary key, so you presumably have another subsequent migration that changes the field again; and 0 wouldn't work as a pk.
If you're still in development and don't have any data you need to keep, I would suggest deleting your database and migrations completely and starting again with makemigrations.
I think this error occurred because you haven't set a default value to your foreign key. For your previous P_Images instances (before your current migration), they don't have a Projects id related to them.
The error text shown also confirms it:
return self._get_default()
TypeError: id() takes exactly one argument (0 given)
So try adding a default value :
DEFAULT_PROJECT = 1 # or the id of any project that does exist
fk_post = models.ForeignKey(Projects, on_delete=models.CASCADE, default = DEFAULT_PROJECT)
UPDATE:
This is probably a better representation of my question:
Using loadtestdata, how do you populate the auth.User database? I just want to populate the database with bogus users, and simulations that are linked to those bogus users.
I have looked at all relevant resources but I'm unable to make any headway.
Situation:
I am building a simulation model using Django and am looking to store simulation data as well as sets of parameter data. Many sets of simulation data should be linked to each user, and many sets of parameter data can be linked to each simulation. Thus, I have tried to model this under 'models.py' of my Django app.
from django.db import models
from django.conf import settings
# Create your models here.
class Simulation(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, )
date = models.DateTimeField()
# Each simulation has only one graph
# Graphing parameters
hill_num = models.CharField(max_length=3)
div_type = models.CharField(max_length=10)
s3_url = models.CharField(max_length=256)
def __str__(self):
return str(self.sim_id)
class Parameter(models.Model):
# Each simulation can have many sets of simulation parameters
simulation = models.ForeignKey('Simulation', on_delete=models.CASCADE)
lsp = models.PositiveIntegerField()
plots = models.PositiveIntegerField()
pioneer = models.BooleanField()
neutral = models.BooleanField()
# for pioneers
p_max = models.PositiveIntegerField()
p_num = models.PositiveIntegerField()
p_start = models.PositiveIntegerField()
# for non-pioneers
np_max = models.PositiveIntegerField()
np_num = models.PositiveIntegerField()
np_start = models.PositiveIntegerField()
def __str__(self):
return str(self.param_id)
./manage.py makemigrations works but when I try to populate the database with python manage.py loadtestdata auth.User:10 divexplorer.Simulation:40 divexplorer.Parameter:300, it throws this error:
auth.User(pk=72): JshtkqSzw3
auth.User(pk=73): QwPfxJc_KS1k5sgH5BN98J
auth.User(pk=74): fuEhnZ
auth.User(pk=75): a
auth.User(pk=76): XjVXXLYGz3MJSfmZ54wGxXo
auth.User(pk=77): fhOWIp
auth.User(pk=78): 5tkEhKOjX2UUbFe
auth.User(pk=79): JgG4Y4PqkcapNJJOlFW1LOQ
auth.User(pk=80): fhRmfQHNim4zM8hGPzpYdkwaHI7
auth.User(pk=81): cEPQtyByKdUs8Gw58DrfNtpsCRB_
Traceback (most recent call last):
File "manage.py", line 22, in <module>
execute_from_command_line(sys.argv)
File "/Users/evanma/anaconda/lib/python2.7/site-packages/django/core/management/__init__.py", line 363, in execute_from_command_line
utility.execute()
File "/Users/evanma/anaconda/lib/python2.7/site-packages/django/core/management/__init__.py", line 355, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/Users/evanma/anaconda/lib/python2.7/site-packages/django/core/management/base.py", line 283, in run_from_argv
self.execute(*args, **cmd_options)
File "/Users/evanma/anaconda/lib/python2.7/site-packages/django/core/management/base.py", line 330, in execute
output = self.handle(*args, **options)
File "/Users/evanma/anaconda/lib/python2.7/site-packages/django/utils/decorators.py", line 185, in inner
return func(*args, **kwargs)
File "/Users/evanma/anaconda/lib/python2.7/site-packages/autofixture/management/commands/loadtestdata.py", line 225, in handle
autofixture.create(model, count, **kwargs)
File "/Users/evanma/anaconda/lib/python2.7/site-packages/autofixture/__init__.py", line 136, in create
return autofixture.create(count, **create_kwargs)
File "/Users/evanma/anaconda/lib/python2.7/site-packages/autofixture/base.py", line 554, in create
instance = self.create_one(commit=commit, **kwargs)
File "/Users/evanma/anaconda/lib/python2.7/site-packages/autofixture/base.py", line 519, in create_one
instance.save()
File "/Users/evanma/anaconda/lib/python2.7/site-packages/django/db/models/base.py", line 807, in save
force_update=force_update, update_fields=update_fields)
File "/Users/evanma/anaconda/lib/python2.7/site-packages/django/db/models/base.py", line 837, in save_base
updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
File "/Users/evanma/anaconda/lib/python2.7/site-packages/django/db/models/base.py", line 923, in _save_table
result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
File "/Users/evanma/anaconda/lib/python2.7/site-packages/django/db/models/base.py", line 962, in _do_insert
using=using, raw=raw)
File "/Users/evanma/anaconda/lib/python2.7/site-packages/django/db/models/manager.py", line 85, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/Users/evanma/anaconda/lib/python2.7/site-packages/django/db/models/query.py", line 1076, in _insert
return query.get_compiler(using=using).execute_sql(return_id)
File "/Users/evanma/anaconda/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 1099, in execute_sql
cursor.execute(sql, params)
File "/Users/evanma/anaconda/lib/python2.7/site-packages/django/db/backends/utils.py", line 80, in execute
return super(CursorDebugWrapper, self).execute(sql, params)
File "/Users/evanma/anaconda/lib/python2.7/site-packages/django/db/backends/utils.py", line 65, in execute
return self.cursor.execute(sql, params)
File "/Users/evanma/anaconda/lib/python2.7/site-packages/django/db/utils.py", line 94, in __exit__
six.reraise(dj_exc_type, dj_exc_value, traceback)
File "/Users/evanma/anaconda/lib/python2.7/site-packages/django/db/backends/utils.py", line 65, in execute
return self.cursor.execute(sql, params)
django.db.utils.ProgrammingError: column "user_id" of relation "divexplorer_simulation" does not exist
LINE 1: INSERT INTO "divexplorer_simulation" ("user_id", "date", "hi...
I have spent hours trying to work through this error but to no avail. Any ideas?
I have tried renaming the argument db_column in the ForeignKey function, applying default values, but none of them work. Would appreciate some input thank you very much!
I believe you need to specify if related models should also be created with random values.
Please check the docs: http://django-autofixture.readthedocs.io/en/latest/loadtestdata.html
Where it is stated:
There are a few command line options available. Mainly to control the behavior of related fields. If foreingkey or many to many fields should be populated with existing data or if the related models are also generated on the fly. Please have a look at the help page of the command for more information:
django-admin.py help loadtestdata
Unfortunately I can't check a running instance of Django know in order to point you to the exact option and it's value but checking the docs I would say that you have to use this option from loadtestdata:
...
make_option('--generate-fk', action='store', dest='generate_fk', default=None,
help=u'Do not use already existing instances for ForeignKey relations. ' +
'Create new instances instead. You can specify a comma sperated list of ' +
'field names or ALL to indicate that all foreignkeys should be generated ' +
'automatically.'),
...
I'm new to the forum and I've got a problem.
in Django im trying to create a UserProfile class by referencing it via a OnetoOneField to an User Object. When i try to migrate, I get:
"You are trying to add a non-nullable field 'id' to author without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows)
2) Quit, and let me add a default in models.py"
I understand, that there are some fields in the User model (for example "id") that are not allowed to be null.
When I try to set a default it will makemigrations, but migrate fails with a syntax error.
My Question is how do I allow Null, or set a default that works, without writing a custom User class, and is that even possible ?
I'd really appreciate any help with this.
Here is my Code:
from django.db import models
from django.contrib.auth.models import User as User_django
class User(User_django):
pass
class Author(models.Model):
user = models.OneToOneField(User, null=True)
class BaseElement(models.Model):
author=models.ForeignKey(Author, null=True)
upvotes = models.PositiveIntegerField(default=0)
downvotes = models.PositiveIntegerField(default=0)
created = models.DateTimeField(auto_now_add=True, null=True)
def vote_up(self):
self.upvotes.value = self.upvotes.value + 1
def vote_down(self):
self.downvotes.value = self.downvotes.value + 1
class Meta:
abstract = True
class Post(BaseElement):
content = models.TextField(max_length=240)
tags = models.CharField(max_length=40, blank=True)
said_by = models.CharField(max_length=40)
said_at = models.CharField(max_length=40, blank=True)
def get_comments(self):
return self.comment_set.all()
def get_comments_anzahl(self):
return self.comment_set.all().count()
class Comment(BaseElement):
content = models.TextField(max_length=140)
commented_post = models.ForeignKey(Post, related_query_name="comment", null=True)
EDIT:
This happens if I try to set a default and try to migrate:
You are trying to add a non-nullable field 'id' to author without a
default; we can't do that (the database needs something to populate
existing rows).
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows)
2) Quit, and let me add a default in models.py
Select an option: 1
Please enter the default value now, as valid Python
The datetime and django.utils.timezone modules are available, so you can
do e.g. timezone.now()
>>> 1
Migrations for 'post':
0003_auto_20160505_1237.py:
- Change Meta options on author
- Change managers on author
- Remove field user_ptr from author
- Add field id to author
- Add field user to author
Operations to perform:
Apply all migrations: contenttypes, admin, sessions, post, auth
Running migrations:
Rendering model states... DONE
Applying post.0003_auto_20160505_1237...Traceback (most recent call last):
File "/home/jaidmin/.conda/envs/cyf/lib/python3.5/site-packages/django/db/backends/utils.py", line 64, in execute
return self.cursor.execute(sql, params)
File "/home/jaidmin/.conda/envs/cyf/lib/python3.5/site-packages/django/db/backends/sqlite3/base.py", line 323, in execute
return Database.Cursor.execute(self, query, params)
sqlite3.OperationalError: near ")": syntax error
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "manage.py", line 10, in <module>
execute_from_command_line(sys.argv)
File "/home/jaidmin/.conda/envs/cyf/lib/python3.5/site-packages/django /core/management/__init__.py", line 353, in execute_from_command_line
utility.execute()
File "/home/jaidmin/.conda/envs/cyf/lib/python3.5/site-packages/django/core/management/__init__.py", line 345, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/home/jaidmin/.conda/envs/cyf/lib/python3.5/site-packages/django/core/management/base.py", line 348, in run_from_argv
self.execute(*args, **cmd_options)
File "/home/jaidmin/.conda/envs/cyf/lib/python3.5/site-packages/django/core/management/base.py", line 399, in execute
output = self.handle(*args, **options)
File "/home/jaidmin/.conda/envs/cyf/lib/python3.5/site-packages/django/core/management/commands/migrate.py", line 200, in handle
executor.migrate(targets, plan, fake=fake, fake_initial=fake_initial)
File "/home/jaidmin/.conda/envs/cyf/lib/python3.5/site-packages/django/db/migrations/executor.py", line 92, in migrate
self._migrate_all_forwards(plan, full_plan, fake=fake, fake_initial=fake_initial)
File "/home/jaidmin/.conda/envs/cyf/lib/python3.5/site-packages/django/db/migrations/executor.py", line 121, in _migrate_all_forwards
state = self.apply_migration(state, migration, fake=fake, fake_initial=fake_initial)
File "/home/jaidmin/.conda/envs/cyf/lib/python3.5/site-packages/django/db/migrations/executor.py", line 198, in apply_migration
state = migration.apply(state, schema_editor)
File "/home/jaidmin/.conda/envs/cyf/lib/python3.5/site-packages/django/db/migrations/migration.py", line 123, in apply
operation.database_forwards(self.app_label, schema_editor, old_state, project_state)
File "/home/jaidmin/.conda/envs/cyf/lib/python3.5/site-packages/django/db/migrations/operations/fields.py", line 121, in database_forwards
schema_editor.remove_field(from_model, from_model._meta.get_field(self.name))
File "/home/jaidmin/.conda/envs/cyf/lib/python3.5/site-packages/django/db/backends/sqlite3/schema.py", line 247, in remove_field
self._remake_table(model, delete_fields=[field])
File "/home/jaidmin/.conda/envs/cyf/lib/python3.5/site-packages/django/db/backends/sqlite3/schema.py", line 197, in _remake_table
self.quote_name(model._meta.db_table),
File "/home/jaidmin/.conda/envs/cyf/lib/python3.5/site-packages/django/db/backends/base/schema.py", line 110, in execute
cursor.execute(sql, params)
File "/home/jaidmin/.conda/envs/cyf/lib/python3.5/site-packages/django/db/backends/utils.py", line 79, in execute
return super(CursorDebugWrapper, self).execute(sql, params)
File "/home/jaidmin/.conda/envs/cyf/lib/python3.5/site-packages/django/db/backends/utils.py", line 64, in execute
return self.cursor.execute(sql, params)
File "/home/jaidmin/.conda/envs/cyf/lib/python3.5/site-packages/django/db/utils.py", line 95, in __exit__
six.reraise(dj_exc_type, dj_exc_value, traceback)
File "/home/jaidmin/.conda/envs/cyf/lib/python3.5/site-packages/django/utils/six.py", line 685, in reraise
raise value.with_traceback(tb)
File "/home/jaidmin/.conda/envs/cyf/lib/python3.5/site-packages/django/db/backends/utils.py", line 64, in execute
return self.cursor.execute(sql, params)
File "/home/jaidmin/.conda/envs/cyf/lib/python3.5/site-packages/django/db/backends/sqlite3/base.py", line 323, in execute
return Database.Cursor.execute(self, query, params)
django.db.utils.OperationalError: near ")": syntax error
EDIT:
It seems like I solved it by creating a new project and step by step copying the models and migrating. Still wondering what was going on there, because I flushed the database and deleted the migration files multiple times and it was still throwing errors.
Thanks for the help !
Take a look at this:
https://docs.djangoproject.com/es/1.9/topics/db/examples/one_to_one/
Your code is a ONE-to-ONE with user. When you set it, it implies CASCADE delete, and therefore can never be null.
if you change to One-to-Many, and just ensure that you only insert one object for the foreign key, it'll work. Otherwise, change your cascade rule.
I will say, however, that's not a good idea, because if you make it null, what separates it from other records. Consider a second PK field.
Best of luck.
Just import django's built-in User model like this:
from django.contrib.auth.models import User
and delete this line:
class User(User_django):
pass
from your code as it is completely unnecessary.
UPDATE: Also it looks like your problem has nothing to do with the User model. I think somehow you added an id field to your Author model and deleted it (maybe after an unsuccessful migration). If this is the case, then you could edit your 0003_auto_20160505_1237.py. To do that open it and remove the lines which look something like this:
migrations.AddField(
model_name='author',
name='id',
field=models.someFieldType(options)),
),
and try again.
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.