Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a Django 1.7+ replacement for South's add_introspection_rules()?

Tags:

Back in the days of South migrations, if you wanted to create a custom model field that extended a Django field's functionality, you could tell South to use the introspection rules of the parent class like so:

from south.modelsinspector import add_introspection_rules add_introspection_rules([], ["^myapp\.stuff\.fields\.SomeNewField"]) 

Now that migrations have been moved to Django, is there a non-South equivalent of the above? Is an equivalent even needed anymore, or is the new migration stuff smart enough to just figure it out on its own?

like image 963
Troy Avatar asked Apr 10 '15 00:04

Troy


1 Answers

As Phillip mentions in the comments, deconstruct() is the official way to handle custom fields in django migrations.

To go on to complete the request for clarification... It would appear that there are already a couple of examples of code out there written to handle both. For example, this excerpt (to handle the on parameter for ExclusiveBooleanField) is taken from django-exclusivebooleanfield:

from django.db import models, transaction from django.db.models import Q  from six import string_types from six.moves import reduce   try:     transaction_context = transaction.atomic except AttributeError:     transaction_context = transaction.commit_on_success   class ExclusiveBooleanField(models.BooleanField):     """     Usage:      class MyModel(models.Model):         the_one = ExclusiveBooleanField()       class MyModel(models.Model):         field_1 = ForeignKey()         field_2 = CharField()         the_one = ExclusiveBooleanField(on=('field_1', 'field_2'))         # `on` is a bit like a unique constraint, value of field         # is only exclusive for rows with same value of the on fields     """     def __init__(self, on=None, *args, **kwargs):         if isinstance(on, string_types):             on = (on, )         self._on_fields = on or ()         super(ExclusiveBooleanField, self).__init__(*args, **kwargs)      def contribute_to_class(self, cls, name):         super(ExclusiveBooleanField, self).contribute_to_class(cls, name)         models.signals.class_prepared.connect(self._replace_save, sender=cls)      def deconstruct(self):         """         to support Django 1.7 migrations, see also the add_introspection_rules         section at bottom of this file for South + earlier Django versions         """         name, path, args, kwargs = super(             ExclusiveBooleanField, self).deconstruct()         if self._on_fields:             kwargs['on'] = self._on_fields         return name, path, args, kwargs      def _replace_save(self, sender, **kwargs):         old_save = sender.save         field_name = self.name         on_fields = self._on_fields          def new_save(self, *args, **kwargs):             def reducer(left, right):                 return left & Q(**{right: getattr(self, right)})              with transaction_context():                 if getattr(self, field_name) is True:                     f_args = reduce(reducer, on_fields, Q())                     u_args = {field_name: False}                     sender._default_manager.filter(f_args).update(**u_args)                 old_save(self, *args, **kwargs)         new_save.alters_data = True          sender.save = new_save   try:     from south.modelsinspector import add_introspection_rules     add_introspection_rules(         rules=[             (                 (ExclusiveBooleanField,),                 [],                 {"on": ["_on_fields", {"default": tuple()}]},             )         ],         patterns=[             'exclusivebooleanfield\.fields\.ExclusiveBooleanField',         ]     ) except ImportError:     pass 
like image 94
Peter Brittain Avatar answered Sep 30 '22 22:09

Peter Brittain