【问题标题】:Setting relationship with chosen model class in Django Admin interface在 Django Admin 界面中设置与所选模型类的关系
【发布时间】:2021-05-13 20:34:09
【问题描述】:

问题: 如何通过 Django Admin 接口动态地将所选模型实例的关系添加到任何其他 Django 模型?

说明:

我想通过 Django 管理界面创建Categories。每个Category 都有多个Choices 分配给它。来自给定CategoryChoice(s) 只能分配给另一个特定Django 类(模型)的对象。让我们展示一个伪代码示例:

class Category(models.Model):
    category_name = models.CharField()


class Choice(models.Model):
    category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name="choices")
    choice_name = models.CharField()


class ModelWithChoosableFields(models.Model):
    possible_categories = ...   # objects of class Category
    selected_choices = ...   # objects of class Choice

    class Meta:
        abstract = True


class Book(ModelWithChoosableFields):
    ...

class Animal(ModelWithChoosableFields):
    ...
  • Categorycategory_name = 'Genre' 有三种可能 Choices: choice_name = 'biography', choice_name = 'thriller'choice_name = 'poetry'

    Categorycategory_name = 'Animal type' 有两种可能 Choices: choice_name = 'mammal'choice_name = 'reptile'.

  • Book 类可能具有来自CategoryChoices 之一 category_name = 'Genre' 已分配。但是,Choicescategory_name = 'Animal type' 不能分配给类 Book

    类比Animal只能有Choices相关 category_name = 'Animal type' 分配给它。

换句话说,在管理面板中,例如Book 类的实例,我希望有一种方法可以从Categories 中选择适合Book 类的Choice 对象。

我想这样做的原因是,使用 Django 管理界面的用户可以将可能的类别动态添加到所选模型(例如,添加 Category category_name = "Conservation status" 可用于类 Animal),如果需要,可以向类别添加更多选项(例如,将另一个 choice_name = 'fish' 添加到 category_name = 'Animal type'。这样对于最终管理员用户来说非常灵活,无需更改代码中的任何内容。

我尝试使用泛型关系来实现它 - 但是,它并不成功,因为 AFAIK 泛型关系将给定对象(例如 Category)与任何其他类的 对象实例 联系在一起,而不是一般到任何其他类(因此,在使用通用关系时,对于Category,我必须指定与给定Book 对象实例的关系,而不是一般Book 类)。

我想知道这样的行动是否可行 - 我搜索了很多,但找不到任何东西。也许有更简单的方法?提前谢谢!

【问题讨论】:

  • ChoiceCategory 是什么,它们是否扩展了 models.Model
  • @Alex 是的,他们有。编辑了问题。谢谢
  • “选择”一词需要改进。在您使用它的上下文中,它实际上并没有任何意义,而且由于 Django 的ChoiceField,它会让人感到困惑。为这些实体寻找更好的名称是一种哲学练习,但一个快速的想法是使用CategoryType 来表示您一直称为“类别”的内容,使用Category 来表示您一直称为“选择”的内容。
  • "这种方式对最终管理员用户来说非常灵活,无需更改任何代码。"然而,对我来说,它看起来像是过早的优化和 YAGNI。我也怀疑如果用户无法定义新实体(ModelWithChoosableFields 子类;顺便说一句,ModelWithChoosableFields 也需要一个更好的名称)会有多大用处。虽然ChoiceField 可能会对您有所帮助,但我相信您正在寻找的东西并不是开箱即用的。
  • category 和您的每个模型之间的多对多关系如何?管理员可以从管理面板中选择分配给每个BookAnimal 的类别,并且由于选择与类别相关,Animals 和Books 将通过这个多连接到他们的选择很多关系。

标签: python django django-models django-admin


【解决方案1】:

使用ContentTypes,您可以将模型实例与整个模型类相关联,无需覆盖即可实现您的目标。

这里是怎么做的:

  1. 在您的类别模型中,为 ContentType 定义一个 many-to-many relationship。这样,在您的类别模型表单中,您将能够选择此类别适用于哪些模型,并且您将能够根据其类别是否包含特定模型来过滤选项。使用 ManyToManyField 的 limit_choices_to 参数将 ContentType 选项限制为具有正确 app_label 的选项,当然排除 Choice 和 Category 模型。

  2. 来自书籍/动物/等。 models 将 many-to-many relationships 添加到 Choice 模型中,并使用 limit_choices_to 参数将 Choices 限制为仅具有与相应模型相关的类别的选项。

你的模型应该看起来像这样:

from django.db import models


def get_ContentTypes():
    appQ = models.Q(app_label='YourAppName') #change value of app_label to match your app's name
    modelIsCatQ = models.Q(model='category')
    modelIsChoice = models.Q(model='choice')
    return appQ & ~modelIsCatQ & ~modelIsChoice

class Category(models.Model):
    category_name = models.CharField(max_length=128)
    asigned_models = models.ManyToManyField(ContentType,limit_choices_to=get_ContentTypes)

class Choice(models.Model):
    choice_name = models.CharField(max_length=128)
    category = models.ForeignKey(Category,on_delete=models.Model)

class Animal(models.Model):
    choices = models.ManyToManyField(Choice,limit_choices_to=models.Q(category_assigned_models__model__startswith='animal'))

class Book(models.Model):
    choices = models.ManyToManyField(Choice,limit_choices_to=models.Q(category_assigned_models__model__startswith='book'))

啊,瞧。你有它:

  1. 创建/编辑类别时,您可以选择它应该应用于哪些模型
  2. 创建/编辑书籍/动物/等时。您只能看到相关的选择。

【讨论】:

    猜你喜欢
    • 2010-12-27
    • 2014-10-29
    • 2016-11-13
    • 1970-01-01
    • 1970-01-01
    • 2011-01-06
    • 2019-03-26
    • 2022-01-27
    • 2015-03-02
    相关资源
    最近更新 更多