I have three models as follows, models.py
:
class Activity(models.Model):
# ...
objects = models.Manager()
activity = ActivityManager()
kind = models.CharField(max_length=10, choices=KIND_CHOICES)
# ...
class ActivtyA(models.Model):
# ...
activity = models.OneToOneField(
Activity,
on_delete=models.CASCADE,
related_name='A',
)
# ...
class ActivtyB(models.Model):
# ...
activity = models.OneToOneField(
Activity,
on_delete=models.CASCADE,
related_name='B',
)
# ...
and a model manager, managers.py
:
class ActivityManager(models.Manager):
def create_activity(self, validated_data):
# ...
data = validated_data.pop(kind)
act = self.create(**validated_data)
if act.kind == 'A':
# Create ActivityA(act, **data)
elif act.kind == 'B':
# Create ActivityB(act, **data)
# ...
# ...
In model manager's create_activity
method I wand to create Activty
and either ActivityA
or ActivtyB
based on Activity.kind
. If I import these classes in manager then it results in circular import error .
How can I access ActivityA
and ActivtyB
in manager?
I tried to do this by using signals but couldn't make it.
@receiver(post_save, sender=Activity)
def create_activity_details(sender, instance, using, **kwargs):
if instance.kind == 'A':
ActivityA.objects.create(activity=instance, data=????) # Need data to create this object
elif instance.kind == 'A':
ActivityB.objects.create(activity=instance, data=????)
So, I went old school and did this to make it work,
data = validated_data.pop(kind)
act = self.create(**validated_data)
if act.kind == 'A':
from activity.models import ActivityA # Prevent the circular import
ActivityA.objects.create(activity=act, **data)
elif act.kind == 'B':
from activity.models import ActivityB
ActivityB.objects.create(activity=act, **data)
It works, but doesn't look clean. Any better solution other?
So, using django.apps.apps.get_model
is the answer. Thanks @djvj for pointing me in the right direction.
Doc says that:
apps.get_model(app_label, model_name, require_ready=True)
Returns the Model with the givenapp_label
andmodel_name
. As a shortcut, this method also accepts a single argument in the formapp_label.model_name
.model_name
is case-insensitive.
Example:
from django.apps import apps
class ActivityManager(models.Manager):
def create_activity(self, validated_data):
# ...
data = validated_data.pop(kind)
act = self.create(**validated_data)
if act.kind == 'A':
model = apps.get_model(app_label='activity', model_name='ActivityA')
model.objects.create(activity=act, **data)
elif act.kind == 'B':
model = apps.get_model(app_label='activity', model_name='ActivityB')
model.objects.create(activity=act, **data)
# ...
# ...
apps.get_model(app_label='activity', model_name='ActivityA')
can be simply written as
apps.get_model('activity.ActivityA')
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.