Изменить класс ребенка на моделях 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. Не уверен, почему вы хотели бы сделать это, хотя. Можете ли вы опубликовать больше своего кода?