Изменить класс ребенка на моделях Django

Допустим, у меня есть занятия в форме:

class A(models.Model):
   attrA = models.CharField()
class B(A):
   attrB = models.CharField()
class C(A):
   attrC = models.CharField()

И тогда я создаю экземпляр B:

b = B()

Теперь, основываясь на некоторых решениях, я хотел преобразовать этот объект b в экземпляр класса C, но с доступным атрибутом attrC. Это возможно?

2 ответа

В Python вы можете изменить класс объекта следующим образом:

b.__class__=C

Тогда все атрибуты B доступны, даже если они не определены для класса C. Хотя b теперь является экземпляром класса C, он не имеет атрибутов C. Перед сохранением объекта в базе данных (или вызовом других методов класса Model) необходимо добавить все оставшиеся атрибуты класса C. Чтобы доказать, что это работает, я создал простое приложение. Вот мои модели:

class A(models.Model):
    attrA = models.CharField(max_length=128)
    class Meta:
        abstract=True
class B(A):
    attrB = models.CharField(max_length=128)
class C(A):
    attrC = models.CharField(max_length=128)

И вот мои тесты:

class ABCTestCase(TestCase):
    def test_changing_classes(self):
        """Changing classes"""
        a = A()
        self.assertIsInstance(a, A)
        a.attrA='bacon'
        self.assertEqual(a.attrA, 'bacon')
        a.__class__=B
        self.assertIsInstance(a, B)
        self.assertEqual(a.attrA, 'bacon')
        a.attrB='spam'
        self.assertEqual(a.attrA, 'bacon')
        self.assertEqual(a.attrB, 'spam')
        a.__class__=C
        self.assertIsInstance(a, C)
        self.assertIsInstance(a, A)
        self.assertNotIsInstance(a, B)
        a.attrC='egg'
        self.assertEqual(a.attrA, 'bacon')
        self.assertEqual(a.attrB, 'spam')
        self.assertEqual(a.attrC, 'egg')
        a.id=None
        a.save()
        self.assertIsNotNone(a.id)

Результат теста в порядке.

Более безопасный подход - определить метод для каждого класса, который конвертируется из B в C или из C в B.

b = C() сделает локальную переменную b экземпляром класса C. Не уверен, почему вы хотели бы сделать это, хотя. Можете ли вы опубликовать больше своего кода?

Другие вопросы по тегам