【问题标题】:How to access related model in Django custom model manager?如何在 Django 自定义模型管理器中访问相关模型?
【发布时间】:2021-03-24 13:49:00
【问题描述】:

我有以下三个模型, 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',
    )

    # ...

还有一名模特经理, 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)

         # ... 
    # ... 

在模型管理器的create_activity 方法中,我想根据Activity.kind 创建ActivtyActivityAActivtyB。如果我在管理器中导入这些类,则会导致循环导入错误
如何在管理器中访问ActivityAActivtyB

我尝试通过使用信号来做到这一点,但无法做到。

@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=????)

【问题讨论】:

  • ActivityManager 示例中的确切问题是什么?那是您的答案中提到的循环导入吗?
  • @djvg;是的。我将其添加到问题中。
  • 您能否通过在models.py 中定义管理器来防止这些导入问题?还是您真的希望它在单独的 managers.py 模块中?
  • @djvg;该管理器的目的是将业务逻辑与视图和序列化程序分开,同时避免使模型变胖。所以,是的,它需要在一个单独的文件中。
  • 或者这似乎是最新的:stackoverflow.com/a/4881693

标签: python django django-models django-rest-framework


【解决方案1】:

所以,我去了老学校,这样做是为了让它发挥作用,

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)

它有效,但看起来不干净。还有其他更好的解决方案吗?


更新:

所以,使用django.apps.apps.get_model 就是答案。感谢@djvj 为我指明了正确的方向。
医生说:

apps.get_model(app_label, model_name, require_ready=True)
返回具有给定 app_labelmodel_name 的模型。作为一种快捷方式,此方法还接受app_label.model_name 形式的单个参数。 model_name 不区分大小写。

例子:

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')可以简单写成

apps.get_model('activity.ActivityA')

【讨论】:

    猜你喜欢
    • 2011-04-20
    • 1970-01-01
    • 1970-01-01
    • 2018-05-01
    • 2017-11-17
    • 2019-06-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多