Estoy tratando de hacer un django-south migration a una aplicación existente para agregar django-audit-log (para rastrear los cambios iniciados por el usuario de un módulo), pero me estoy encontrando con errores significativos. Específicamente con el campo action_user_id que es un LastUserField (que almacena al usuario que especificó el cambio que se está rastreando).django-south con django-audit-log
Si yo estaba empezando a partir de un modelo en blanco, tan sólo pudiera añadir una audit_log a través de:
from audit_log.models.managers import AuditLog
...
class SomeModel(models.Model)
...
audit_log = AuditLog()
La aplicación de este simple cambio y haciendo un schemamigration en django-sur comprensivamente me da un error:
! Cannot freeze field 'myapp.mymodelauditlogentry.action_user'
! (this field has class audit_log.models.fields.LastUserField)
! South cannot introspect some fields; this is probably because they are custom
! fields. If they worked in 0.6 or below, this is because we have removed the
! models parser (it often broke things).
! To fix this, read http://south.aeracode.org/wiki/MyFieldsDontWork
leí el wiki MyFieldsDontWork (y las piezas de campos personalizados/Introspección), pero no es 100% claro lo que tengo que hacer para conseguir los campos para trabajar.
Trato de añadir:
from south.modelsinspector import add_introspection_rules
add_introspection_rules([], ["^audit_log\.models\.fields\.LastUserField"])
a mi models.py que permitió la schemamigration ./manage.py para crear un script de migración con el error anterior desaparece. Sin embargo cuando intento migrar (para aplicar la migración), consigo los siguientes errores:
Running migrations for myapp:
- Migrating forwards to 0004_auto__add_mymodelauditlogentry.
> my_app:0004_auto__add_mymodelauditlogentry
Traceback (most recent call last):
File "./manage.py", line 11, in <module>
execute_manager(settings)
File "/usr/local/lib/python2.6/dist-packages/Django-1.2.3-py2.6.egg/django/core/management/__init__.py", line 438, in execute_manager
utility.execute()
File "/usr/local/lib/python2.6/dist-packages/Django-1.2.3-py2.6.egg/django/core/management/__init__.py", line 379, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/usr/local/lib/python2.6/dist-packages/Django-1.2.3-py2.6.egg/django/core/management/base.py", line 191, in run_from_argv
self.execute(*args, **options.__dict__)
File "/usr/local/lib/python2.6/dist-packages/Django-1.2.3-py2.6.egg/django/core/management/base.py", line 220, in execute
output = self.handle(*args, **options)
File "/usr/local/lib/python2.6/dist-packages/South-0.7.3-py2.6.egg/south/management/commands/migrate.py", line 105, in handle
ignore_ghosts = ignore_ghosts,
File "/usr/local/lib/python2.6/dist-packages/South-0.7.3-py2.6.egg/south/migration/__init__.py", line 191, in migrate_app
success = migrator.migrate_many(target, workplan, database)
File "/usr/local/lib/python2.6/dist-packages/South-0.7.3-py2.6.egg/south/migration/migrators.py", line 221, in migrate_many
result = migrator.__class__.migrate_many(migrator, target, migrations, database)
File "/usr/local/lib/python2.6/dist-packages/South-0.7.3-py2.6.egg/south/migration/migrators.py", line 292, in migrate_many
result = self.migrate(migration, database)
File "/usr/local/lib/python2.6/dist-packages/South-0.7.3-py2.6.egg/south/migration/migrators.py", line 125, in migrate
result = self.run(migration)
File "/usr/local/lib/python2.6/dist-packages/South-0.7.3-py2.6.egg/south/migration/migrators.py", line 93, in run
south.db.db.current_orm = self.orm(migration)
File "/usr/local/lib/python2.6/dist-packages/South-0.7.3-py2.6.egg/south/migration/migrators.py", line 246, in orm
return migration.orm()
File "/usr/local/lib/python2.6/dist-packages/South-0.7.3-py2.6.egg/south/utils.py", line 62, in method
value = function(self)
File "/usr/local/lib/python2.6/dist-packages/South-0.7.3-py2.6.egg/south/migration/base.py", line 422, in orm
return FakeORM(self.migration_class(), self.app_label())
File "/usr/local/lib/python2.6/dist-packages/South-0.7.3-py2.6.egg/south/orm.py", line 46, in FakeORM
_orm_cache[args] = _FakeORM(*args)
File "/usr/local/lib/python2.6/dist-packages/South-0.7.3-py2.6.egg/south/orm.py", line 125, in __init__
self.models[name] = self.make_model(app_label, model_name, data)
File "/usr/local/lib/python2.6/dist-packages/South-0.7.3-py2.6.egg/south/orm.py", line 318, in make_model
field = self.eval_in_context(code, app, extra_imports)
File "/usr/local/lib/python2.6/dist-packages/South-0.7.3-py2.6.egg/south/orm.py", line 236, in eval_in_context
return eval(code, globals(), fake_locals)
File "<string>", line 1, in <module>
File "/usr/local/lib/python2.6/dist-packages/django_audit_log-0.2.1-py2.6.egg/audit_log/models/fields.py", line 12, in __init__
super(LastUserField, self).__init__(User, null = True, **kwargs)
TypeError: __init__() got multiple values for keyword argument 'null'
EDITAR (12/20 mediodía): Puedo aplicar el schemamigration si añado las líneas de models.py
from south.modelsinspector import add_introspection_rules, add_ignored_fields
add_ignored_fields(["^audit_log\.models\.fields\.LastUserField"])
excepto entonces el middleware audit_log no funciona ya que no hay campo entero action_user_id en myapp_mymodelauditlogentry que las referencias "aUTH_USER" por "id". Luego aplico manualmente el (sintaxis sqlite, obtenida mediante el uso de Sqliteman en la base de datos recién creada.) SQL
ALTER TABLE "myapp_mymodelauditlogentry" ADD "action_user_id" integer REFERENCES "auth_user" ("id");
y funciona. Todavía voy a dar la recompensa si alguien explica cómo se supone que debo hacer esto en el contexto de django-Sur con las migraciones/introspección, sin necesidad de ir a la base de datos de SQL depende cruda y estar agradecidos.
Además, he creado un índice para action_user_id. Me he dado cuenta que la creación de los modelos normales con cables a un índice llamado
CREATE INDEX "myapp_mymodelauditlogentry_26679921" ON "myapp_mymodelauditlogentry" ("action_user_id")
Cacé abajo que el hash 26679921 se crea basándose en el nombre del campo con '%x' % (abs(hash(('action_user_id',))) % 4294967296L,)
y no se basa en ninguna otra cosa (por lo que debe ser siempre _26679921 a menos que la base de datos requiera el nombre largo para ser truncado). No estoy seguro si los nombres del índice alguna vez importan; pero quería estar seguro.
El problema es que South no sabe cómo migrar sus campos. Para los campos personalizados, debe agregar sus propias reglas de introspección, donde le indica al sur qué parámetros son importantes y cuáles pueden ignorarse. Si tengo tiempo esta noche, escribiré un ejemplo sobre cómo hacer que la introspección funcione correctamente. – Wolph
@WoLpH: Sí, lograr que la introspección funcione es el problema, pero afortunadamente hubo documentación para la introspección. No estaba claro para mí, un novato en schema-migrations/django-south (así como django-audit-log). Las primeras cosas que probé no funcionaban con LastUserField. Estaría agradecido si se puede trabajar en introspección (para no tener que insertar SQL manualmente), pero para ser honesto, dejé de intentarlo y pasé a otros temas. –
He estado bastante ocupado, así que no he tenido tiempo de darle una respuesta adecuada todavía. Por favor, tengan paciencia conmigo un poco más :) (o alguien más puede explicarlo).Para resumir, no funciona porque no le dijiste al sur acerca de los parámetros, por lo que lo ignora lo que hace que pase dos veces. – Wolph