Django: dynamic model fields and migrations - python

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)

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.

"relation "social_auth_code" does not exist" when applying migrations on django

I recently switched from django-social-auth to python-social-auth, but it has clearly damage my migrations system. any time I try to migrate changes I got this one :
File "manage.py", line 10, in <module>
execute_from_command_line(sys.argv)
File "/app/.heroku/python/lib/python2.7/site-packages/django/core/management/__init__.py", line 385, in execute_from_command_line
utility.execute()
File "/app/.heroku/python/lib/python2.7/site-packages/django/core/management/__init__.py", line 377, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/app/.heroku/python/lib/python2.7/site-packages/django/core/management/base.py", line 288, in run_from_argv
self.execute(*args, **options.__dict__)
File "/app/.heroku/python/lib/python2.7/site-packages/django/core/management/base.py", line 338, in execute
output = self.handle(*args, **options)
File "/app/.heroku/python/lib/python2.7/site-packages/django/core/management/commands/migrate.py", line 161, in handle
executor.migrate(targets, plan, fake=options.get("fake", False))
File "/app/.heroku/python/lib/python2.7/site-packages/django/db/migrations/executor.py", line 68, in migrate
self.apply_migration(migration, fake=fake)
File "/app/.heroku/python/lib/python2.7/site-packages/django/db/migrations/executor.py", line 102, in apply_migration
migration.apply(project_state, schema_editor)
File "/app/.heroku/python/lib/python2.7/site-packages/django/db/migrations/migration.py", line 108, in apply
operation.database_forwards(self.app_label, schema_editor, project_state, new_state)
File "/app/.heroku/python/lib/python2.7/site-packages/django/db/migrations/operations/fields.py", line 139, in database_forwards
schema_editor.alter_field(from_model, from_field, to_field)
File "/app/.heroku/python/lib/python2.7/site-packages/django/db/backends/schema.py", line 457, in alter_field
self._alter_field(model, old_field, new_field, old_type, new_type, old_db_params, new_db_params, strict)
File "/app/.heroku/python/lib/python2.7/site-packages/django/db/backends/schema.py", line 603, in _alter_field
params,
File "/app/.heroku/python/lib/python2.7/site-packages/django/db/backends/schema.py", line 103, in execute
cursor.execute(sql, params)
File "/app/.heroku/python/lib/python2.7/site-packages/django/db/backends/utils.py", line 65, in execute
return self.cursor.execute(sql, params)
File "/app/.heroku/python/lib/python2.7/site-packages/django/db/utils.py", line 94, in __exit__
six.reraise(dj_exc_type, dj_exc_value, traceback)
File "/app/.heroku/python/lib/python2.7/site-packages/django/db/backends/utils.py", line 65, in execute
return self.cursor.execute(sql, params)
django.db.utils.ProgrammingError: relation "social_auth_code" does not exist
The problem being that it only happens in the production version of my app and that for some other reasons, I had to delete my migrations file in the past. Doesn't make it easy to investigate. Anyway, it perfectly work now with my development app but I can't figure out what can be the problem in production, I tried all the "faking migrations" tricks in the world and nothing seems to work.
the only place in the web were I can find such an error is there
but I never used South, so the first answer is not working for me.
Directly digging into the migrations table and sending raw SQL instructions could be the solution but since it is in my production version, I don't feel confortable with tinkering the db ( I got thousands of registered users, there data and all..). In short, I'm in deep sh*t :). Also, I don't know which command to use to directly access the migration table in the db...
Any solution that keeps my data safe is more than welcome :))
When migrating to python_social_auth I got the same error.
This is useful for Django 1.8.
Maybe my solution will help you:
Fake migrate initial of python_social_auth
python manage.py migrate default 0001 --fake
Create yourself migration for initial psa and put it to /your_project/your_app/migrations/0009_migrate_to_psa.py:
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import social.apps.django_app.default.fields
from django.conf import settings
import social.storage.django_orm
from social.utils import setting_name
user_model = getattr(settings, setting_name('USER_MODEL'), None) or \
getattr(settings, 'AUTH_USER_MODEL', None) or \
'auth.User'
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(user_model),
('your_app', '0008_last_migration_in_your_app'),
('default', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Code',
fields=[
('id', models.AutoField(
verbose_name='ID', serialize=False, auto_created=True,
primary_key=True)),
('email', models.EmailField(max_length=75)),
('code', models.CharField(max_length=32, db_index=True)),
('verified', models.BooleanField(default=False)),
],
options={
'db_table': 'social_auth_code',
},
bases=(models.Model, social.storage.django_orm.DjangoCodeMixin),
),
migrations.AlterUniqueTogether(
name='code',
unique_together=set([('email', 'code')]),
),
]
Notice the dependencies:
dependencies = [
migrations.swappable_dependency(user_model),
('your_app', '0008_last_migration_in_your_app'),
('default', '0001_initial'),
]
Migrate your project
python manage.py migrate your_app
And migrate all
python manage.py migrate
UPDATE:
Unfortunately, this method requires a model Code in the file models.py your application. Otherwise the table will be deleted from the database when the next operation makemigrations.
/your_project/your_app/models.py:
from social.storage.django_orm import DjangoCodeMixin
class Code(models.Model, DjangoCodeMixin):
email = models.EmailField(max_length=254)
code = models.CharField(max_length=32, db_index=True)
verified = models.BooleanField(default=False)
class Meta:
db_table = 'social_auth_code'
unique_together = ('email', 'code')
I tried to run the solution before and had a bit of difficulties with the dependency.
I ended up just prepending1 the following lines to the Migration.operations list in migration 0007_code_timestamp (exactly as the original first answer suggested)
migrations.CreateModel(
name='Code',
fields=[
('id', models.AutoField(
verbose_name='ID', serialize=False, auto_created=True,
primary_key=True)),
('email', models.EmailField(max_length=75)),
('code', models.CharField(max_length=32, db_index=True)),
('verified', models.BooleanField(default=False)),
],
options={
'db_table': 'social_auth_code',
},
bases=(models.Model, social_django.storage.DjangoCodeMixin),
),
migrations.AlterUniqueTogether(
name='code',
unique_together=set([('email', 'code')]),
),
And make sure to import social_django at the top.
That solved it for me, it was easier than creating a new migration and dealing with the dependency clarification.

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

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.

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.

python manage.py syncdb doesn't create a table

I created a model but after 'makemigrations' and 'syncdb' the table doesn't appear in the database.
This is the second model that I want to create and the first model was not a problem.
The command 'makemigrations' creates a .py file, but syncdb shows the message "No migrations to apply".
What am I doing wrong?
python manage.py makemigrations
Migrations for 'category':
0006_text.py:
- Create model text
root#BB:~/Documenten/BB$ python manage.py syncdb
Operations to perform:
Synchronize unmigrated apps: admin-tools, theming
Apply all migrations: admin, category, contenttypes, auth, sessions
Synchronizing apps without migrations:
Creating tables...
Installing custom SQL...
Installing indexes...
Running migrations:
No migrations to apply.
My models
from django.db import models
# Create your models here.
class textitem(models.Model):
bb_txt_lang = models.CharField(max_length=3)
bb_txt_cat = models.CharField(max_length=30)
bb_txt_title = models.CharField(max_length=50)
bb_txt_body = models.TextField()
bb_txt_footer = models.TextField()
# bb_txt_date_from = models.DateField()
# bb_txt_date_until= models.DateField()
bb_txt_status = models.BooleanField(default = False)
def __str__(self):
return self.bb_txt_title
class forum(models.Model):
bb_for_title = models.CharField(max_length=50)
bb_for_body = models.TextField()
bb_for_footer = models.TextField()
# bb_for_date_from = models.DateField()
# bb_for_date_until= models.DateField()
def __str__(self):
return self.bb_for_title
class category(models.Model):
bb_cat_lang = models.CharField(max_length=3)
bb_cat_desc = models.CharField(max_length=50)
# bb_cat_image = models.ImageField()
bb_cat_text = models.TextField()
bb_cat_prod = models.BooleanField(default = False)
bb_cat_sub = models.ForeignKey('category', null=True, blank=True )
def __str__(self):
return self.bb_cat_desc
The error code
biidbox#BiidBox:~/Documenten/BiidBox$ python manage.py migrate
Operations to perform:
Synchronize unmigrated apps: admin_tools, theming
Apply all migrations: admin, category, contenttypes, auth, sessions
Synchronizing apps without migrations:
Creating tables...
Installing custom SQL...
Installing indexes...
Running migrations:
Applying category.0002_auto_20141128_1502...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 84, in database_forwards
schema_editor.remove_field(from_model, from_model._meta.get_field_by_name(self.name)[0])
File "/usr/local/lib/python2.7/dist-packages/django/db/backends/schema.py", line 439, in remove_field
self.execute(sql)
File "/usr/local/lib/python2.7/dist-packages/django/db/backends/schema.py", line 99, 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)
django.db.utils.ProgrammingError: relation "category_forum" does not exist
if you're using Django 1.7, which I assume since you're using makemigrations then syncdb is deprecated... you should be using migrate
https://docs.djangoproject.com/en/1.7/topics/migrations/#the-commands
see also:
https://docs.djangoproject.com/en/1.7/releases/1.7/#schema-migrations
When you make a fresh app with a fresh database, you run the commands in following order:
1) python manage.py syncdb
This creates all the tables that will be used by django (eg :auth_group, auth_user) etc.
You won't see your app's tables, after this command, in the database.
Then you do:
2) python manage.py makemigrations
This will run the initial migration and will detect all your new models.It just detects the models.Doesn't create tables in the database
After that,run the following command
3) python manage.py migrate
This will create your tables.
After you have done this, you just need to use (2) and (3) for any changes to happen.The changes could be creating new models or editing the schema of existing models, etc.
So now, in your question, when you ran python manage.py makemigration ,it detected your new model "text"
Now just run python manage.py migrate for the changes to take effect(in this case, to create table).
Hope this helps

Categories

Resources