Django:在另一个模型的方法中使用模型实例

时间:2011-10-10 19:11:59

标签: django django-orm

假设我有一个模型椰子:

class Coconut(models.Model):
    carrier = models.ForeignKey('birds.Swallow')
    husk_color = models.IntegerField(Choices=COLORS)

现在在某些情况下,我想在视图或管理命令或任何地方设置运营商。

然而,在其他情况下,我希望默认为特定的燕子。

我很想:

    BERT_THE_AFRICAN_SWALLOW = Swallow.objects.get(id=7)
    def set_carrier(swallow=BERT_THE_AFRICAN_SWALLOW):
        self.carrier = swallow

显然这不对,因为它与数据库中的现有数据相关联。

此外,如果尚未实例化“birds”应用程序,它会导致测试运行器出现问题。

那么正确的方法是什么?

我遇到这个问题时的一些例子:

  • 为“创建者”用户分配自动流程,该用户实际上是各种机器人
  • 在VOIP应用中,将特定进程分配给特定的预定义PhoneNumber对象
  • 在自定义授权方案中,组合预定义权限或权限对象。

2 个答案:

答案 0 :(得分:1)

我理解它的方式,你真正想要做的是配置某种类型的默认对象。您可以为此创建一个配置应用程序,以便您可以在管理界面中进行配置,或将其存储在夹具或其他内容中。

将字符串(配置选项)映射到任何类型的对象的模型都可以。 contenttype应用程序完全适合您需要的外键类型。

# models.py

from django.db import models
from django.db.contenttypes.models import ContentType
from django.db.contenttypes import generic

class ConfigurationOption(models.Model):

    name = models.SlugField(max_length = 255, unique=True)

    value_id = models.PositiveIntegerField()
    value_type = models.ForeignKey(ContentType)
    value = generic.GenericForeignKey('value_type', 'value_id')

    class Meta:
        unique_together = 'value_id', 'value_type'

然后,您还依赖于配置应用程序中存在的数据,但现在这已经明确了。

答案 1 :(得分:0)

一个选项可以是使用模型信号(选择取决于何时/何地/如何需要默认值或被覆盖的值)和代理模型。

https://docs.djangoproject.com/en/dev/ref/signals/#module-django.db.models.signals

使用Django模型继承,您可以创建具有不同post / pre方法的代理模型,并共享同一个表。

https://docs.djangoproject.com/en/dev/topics/db/models/#proxy-models

class Coconut(models.Model):
    carrier = models.ForeignKey('birds.Swallow')
    husk_color = models.IntegerField(Choices=COLORS)

class CoconutCarriedByShallow(Coconut):
    pass

    class Meta():
       proxy = True

cached_carriers_dict = {}

def assign_shallow_carrier(sender, instance, **kwargs):
    import birds.models
    attrs = {'name': 'Jhon', 'kind': 'super-fast'}
    carrier = cached_carriers_dict.get(tuple(attrs.items()))
    if carrier is None:
        defaults = {'color': 'blue'}
        carrier, c = birds.models.Swallow.objects.get_or_create(**attrs, defaults= defaults)
        cached_carriers_dict.update({tuple(attrs.items()): carrier})
    instance.carrier = carrier

models.signals.post_init.connect(assign_shallow_carrier, sender=CoconutCarriedByShallow)

当然get_or_create并不总是一个可用选项,如果没有灯具是您可能想要考虑的其他选项。

希望它有所帮助;)