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

倾然丶 夕夏残阳落幕 提交于 2019-12-09 08:08:33

问题


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?


回答1:


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


来源:https://stackoverflow.com/questions/29551367/is-there-a-django-1-7-replacement-for-souths-add-introspection-rules

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!