2014-01-03 4 views
3

Возможно ли создать поле пользовательской модели Django, которое ссылается на функцию или класс, а не на модель?Поле модели Django, сохраняющее функцию или класс

В случае, если вам интересно, почему я хочу этого, вот краткое объяснение того, что я пытаюсь достичь.

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

Сначала я подумал о том, чтобы решить это, используя какой-то полиморфизм, но тогда мне нужно было бы создать конкретную модель для каждого отдельного алгоритма, и они также были бы в разных таблицах в БД, что было бы проблемой для меня. Я также думал об использовании Django Polymorphic, но я слышал, что он действительно не очень хорошо масштабируется, так что это тоже не очень хорошая идея.

Я думал, что если бы я мог просто ссылаться на эти разные алгоритмы на поле модели, у меня будет элитное и эффективное решение.

+0

Будет ли расчет всегда производить один и тот же тип вывода (целое число, строка и т.д. ?) – yuvi

+0

Да, он всегда будет производить десятичную – Thiago

ответ

5

Моя мысль в том, что если бы я мог просто ссылаться на эти различные алгоритмы на полевой модели

Это хорошая идея, например:

CALCULATION_TYPES = [(1, 'Normal'), (2, 'Express')] 

class FreightTable(models.Model): 
    # Normal fields 
    calculation_type = models.IntegerField(choices=CALCULATION_TYPES) 

    def calc_normal(self): 
     pass 

    def calc_express(self): 
     pass 

    def calc_default(self): 
     pass 

Теперь, для каждого груза тип, вы задали свой метод расчета:

ft = FreightType(calculation_type=2) 
ft.save() 

A т в точку, где вы хотите, чтобы отобразить результат вычисления, выборки методы из экземпляра, а затем вызвать соответствующий метод:

call_map = {1: 'calc_normal', 2: 'calc_express'} 
ft = FreightTable.objects.get(pk=1) 
calculated_value = getattr(ft, call_map(ft.calculation_type))() 
+0

Спасибо, вот что я искал! – Thiago

+0

Должен ли FreightType быть FreightTable во второй связке кода? – Gonzalo

2

Невозможно мариновать классы, функции и методы Python, поэтому вы не можете хранить сам код в базе данных.

Что вы можете сделать, это

1) Хранить полный пунктирный путь к функции в CharField. Затем разрешите ссылку на функцию с помощью пакета zope.dottedname и вызовите его.

или

2) Храните код расчета в качестве исходного кода Python в базе данных в виде простого текста. Затем выполните его через eval() или импортируйте динамический модуль, используя модуль imp.

Я не уверен, что у Django был встроенный пунктирный указатель имен, вы можете использовать его вместо zope.dottedname.

+0

. Вторая альтернатива выглядит как много неприятностей, но первая довольно интересная, не знала об этом пакете. – Thiago

+0

Хотя имя Зопа ненавидеет среди многих Python, они - люди, которые впервые ввели модульные компоненты Python, и есть много драгоценных камней с десятилетним испытанием боевых навыков среди пакетов :) –

Смежные вопросы