Hi,
I don't know if crossposting with stackoverflow is allowed here but
essentially my problem is explained
in
https://stackoverflow.com/questions/46162104/django-dynamic-model-fields-and-migrations.
What I want to create is a custom ModelField of type DecimalField, that
dynamically adds another ModelField (CharField) to the source model. As far
as I can tell, this is nicely explained
in
https://blog.elsdoerfer.name/2008/01/08/fuzzydates-or-one-django-model-field-multiple-database-columns/.
Let's assume I start with a fresh project and app and add this code to
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)
If I then call *./manage.py makemigrations* the following migration file
for the app is created:
# 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)),
],
),
]
All good, as far as I can tell. The problem comes up if I then call
*./manage.py
migrate* which errors with the following exception:
./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
As said, I have a fresh project with no exisiting DB and tables so far. Why
is it complaining that there allready exista a column named
"price_extension"?. The migration file only contains one field called
"price_extension"?
A sample project can be cloned
from https://github.com/hetsch/django_testing.
Thank you a lot for your help!
--
You received this message because you are subscribed to the Google Groups
"Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-users/9ca1469c-abcb-4b30-a383-f4654f1705b2%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.