How to define Mode with generic ForeignKey in Django
我对姜戈不熟悉
我想用以下逻辑创建模型:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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 |
我知道它看起来很难看但一定有办法
是的,有一种方法:可以使用Djangos通用关系。
其要点如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | 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') |
在您看来,在创建
1 2 3 4 5 6 | 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) |
正如你所指出的和拉尔夫所描述的,Django中的实际通用外键仍然笨重难看。
但是,您要讨论的是一些特定类型,它们需要以特定的方式进行操作,我认为这是一个很好的继承候选,可以借助于库中的自定义管理器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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中,使用我的高级测试应用程序
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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'>) |