Django: использовать экземпляр модели в методе другой модели - PullRequest
1 голос
/ 10 октября 2011

Допустим, у меня есть модель кокоса:

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
  • В пользовательских сценариях авторизации, комбинируя предварительно определенные привилегии или объекты Permission.

Ответы [ 2 ]

1 голос
/ 10 октября 2011

Насколько я понимаю, на самом деле вы хотите настроить какой-либо объект по умолчанию. Для этого вы можете создать приложение конфигурации, чтобы вы могли выполнить настройку в интерфейсе администратора или сохранить его в приборе или чем-то еще.

Подойдет модель, которая отображает строку (параметр конфигурации) на объект любого типа. Приложение 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'

Тогда вы также зависите от данных, которые существуют в приложении конфигурации, но теперь это делается явным образом.

0 голосов
/ 10 октября 2011

Опция может состоять в том, чтобы использовать сигналы модели (выбор зависит от того, когда / где / как вам нужны значения по умолчанию или переопределения) и моделей прокси.

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 - это не всегда доступная опция, если не фикстуры, это ещё одна опция, которую вы можете рассмотреть.

надеюсь, это поможет;)

...