【问题标题】:How to define Mode with generic ForeignKey in Django如何在 Django 中使用通用 ForeignKey 定义模式
【发布时间】:2018-11-25 16:14:10
【问题描述】:

我是 Django 新手,我想创建具有以下逻辑的模型:

class ExerciseCardio(models.Model):
    pass


class ExerciseWeights(models.Model):
    pass


class Exercise(models.Model):
    name = models.CharField(max_length=100, default='')

    EXERCISE_TYPE_CHOICES = (
        (1, 'cardio'),
        (2, 'Weights'),
    )

    exercise_type = models.PositiveSmallIntegerField(
        choices=EXERCISE_TYPE_CHOICES, default=2)

    if exercise_type == 1:
        exercise_model_type = models.ForeignKey(ExerciseCardio, on_delete=models.CASCADE, default=0)
    elif exercise_type == 2:
        exercise_model_type = models.ForeignKey(ExerciseWeights, on_delete=models.CASCADE, default=0)

    def __str__(self):
        return self.name

我知道它看起来很丑,但必须有办法做到这一点。

【问题讨论】:

    标签: django django-models foreign-keys multiple-choice


    【解决方案1】:

    是的,有一个办法:可以使用djangosgeneric relations

    大意如下:

    from django.contrib.contenttypes.fields import GenericForeignKey
    from django.contrib.contenttypes.models import ContentType
    
    class Exercise(models.Model):
        EXERCISE_TYPE_CHOICES = (
            (1, 'cardio'),
            (2, 'Weights'),
        )
    
        name = models.CharField(
            max_length=100, default='')
        exercise_type = models.PositiveSmallIntegerField(
            choices=EXERCISE_TYPE_CHOICES, default=2)
        content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
        object_id = models.PositiveIntegerField()
        content_object = GenericForeignKey('content_type', 'object_id')
    

    在您看来,在创建Exercise 实例时,您必须选择正确模型的ContentType,可能是这样的:

    obj = Exercise()
    obj.exercise_type = ...
    if obj.exercise_type == 1:
        obj.content_type = ContentType.objects.get_for_model(ExerciseCardio)
    else:
        obj.content_type = ContentType.objects.get_for_model(ExerciseWeights)
    

    【讨论】:

      【解决方案2】:

      正如您指出和 Ralf 所说明的那样,Django 中的实际通用外键仍然笨拙且丑陋。

      但是,您说的是一些需要以特定方式运行的特定类型,我认为这是在库中的自定义管理器的帮助下继承的一个很好的候选者:django-model-utils.managers.InheritanceManager

      models.py:

      from django.db import models
      from model_utils.managers import InheritanceManager
      
      
      class Exercise(models.Model):
          name = models.CharField(max_length=32)
      
          objects = InheritanceManager()
      
          def __str__(self):
              return "{n} ({t})".format(n=self.name, t=type(self))
      
      
      class ExerciseCardio(Exercise):
          pass
      
      
      class ExerciseWeights(Exercise):
          pass
      

      示例(在 Django shell 中,使用我的精美测试应用,eh):

      from eh.models import ExerciseCardio, Exercise, ExerciseWeights
      
      
      c = ExerciseCardio.objects.create(name="Cardio!")
      w = ExerciseWeights.objects.create(name="Weights!")
      
      print(Exercise.objects.filter(name="Cardio!").select_subclasses().get())
      # Cardio! (<class 'eh.models.ExerciseCardio'>)
      
      for e in Exercise.objects.all().select_subclasses():
          print(e)
      # Cardio! (<class 'eh.models.ExerciseCardio'>)
      # Weights! (<class 'eh.models.ExerciseWeights'>)
      

      【讨论】:

        猜你喜欢
        • 2016-03-31
        • 1970-01-01
        • 2018-12-15
        • 2016-04-12
        • 2013-02-28
        • 2014-09-01
        • 1970-01-01
        • 2019-02-18
        • 1970-01-01
        相关资源
        最近更新 更多