Python: назначение переменной объекта из функции (OpenERP)

Я работаю в среде OpenERP, но, возможно, на мою проблему можно ответить с точки зрения чистого Python. То, что я пытаюсь сделать, это определить класс, чья переменная «_columns» может быть установлена ​​​​из функции, которая возвращает соответствующий словарь. Итак, в основном:

class repos_report(osv.osv):
    _name = "repos.report"
    _description = "Reposition"
    _auto = False

    def _get_dyna_cols(self):
        ret = {}
        cr = self.cr
        cr.execute('Select ... From ...')
        pass           #<- Fill dictionary
        return ret

    _columns = _get_dyna_cols()

    def init(self, cr):
        pass    #Other stuff here too, but I need to set my _columns before as per openerp 

repos_report()

Я пробовал много способов, но этот код отражает мою основную потребность. Когда я запускаю свой модуль для установки, я получаю следующую ошибку.

TypeError: _get_dyna_cols() takes exactly 1 argument (0 given)

При определении функции _get_dyna_cols я должен иметь self в качестве первого параметра (даже перед выполнением). Кроме того, мне нужна ссылка на курсор openerp 'cr', чтобы запрашивать данные для заполнения моего словаря _columns. Итак, как я могу вызвать эту функцию, чтобы ее можно было назначить _columns? Какой параметр я могу передать этой функции?

С точки зрения OpenERP, думаю, я достаточно ясно изложил свою потребность. Поэтому любой другой предложенный подход также приветствуется.


person nicobustillos    schedule 09.10.2012    source источник
comment
Почему бы вам не поместить строку _columns = внутри строки __init__?   -  person Mark Ransom    schedule 10.10.2012
comment
Нет. Скорее всего, он хочет это как собственность - длинный ответ ниже.   -  person jsbueno    schedule 10.10.2012


Ответы (2)


С точки зрения OpenERP правильное решение зависит от того, что вы на самом деле пытаетесь сделать, а это не совсем ясно из вашего описания. Обычно _columns определение модели должно быть статическим, поскольку оно будет подвергаться самоанализу с помощью ORM и (среди прочего) приведет к созданию соответствующих столбцов базы данных. Вы можете установить _columns в методе __init__ (а не init1) вашей модели, но это не будет иметь особого смысла, поскольку результат не должен меняться со временем (и он будет вызываться только один раз, когда реестр модели инициализируется в любом случае).

Теперь есть несколько исключений из правил «статических столбцов»:

Поля функций

Если вы просто хотите динамически обрабатывать операции чтения/записи в виртуальном столбце, вы можете просто использовать столбец из fields.function. Он должен эмулировать один из других типов полей, но может делать с данными все, что захочет, динамически. Типичные примеры будут хранить данные в других (реальных) столбцах после некоторой предварительной обработки. В официальных модулях OpenERP есть сотни примеров.

Набор динамических столбцов

Когда вы разрабатываете модель мастера (подкласс TransientModel, ранее osv_memory), вы обычно не заботитесь о хранилище базы данных, а просто хотите получить некоторый ввод от пользователя и выполнить соответствующие действия. В этом случае нередко требуется полностью динамический набор столбцов, где количество и типы столбцов могут меняться каждый раз при использовании модели. Этого можно добиться, переопределив несколько ключевых методов API для имитации динамических столбцов:

  • fields_view_get — метод API который вызывается клиентами для получения определения представления (форма/дерево/...) для модели.
  • fields_get включен в результат fields_view_get, но может быть вызван отдельно и возвращает dict с определением столбцов модели.
  • search, read, write и create вызываются клиентом для доступа и обновления данных записи , и должны изящно принимать или возвращать значения для столбцов, которые были определены в результате fields_get

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

В официальных надстройках есть несколько примеров таких наборов динамических столбцов, например, в модуле survey, которому необходимо имитировать формы опроса на основе определения опросной кампании.

1 Метод init() вызывается только тогда, когда модуль модели установлен или обновлен, чтобы настроить/обновить серверную часть базы данных для этой модели. Для этого он использует _columns.

person odony    schedule 10.10.2012
comment
Спасибо, Оливер. Я понял. На самом деле было приемлемо установить _columns из функции __init__(), потому что я просто хотел добавить одно поле столбца для каждого внутреннего местоположения в базе данных (что довольно статично, и я думаю, нам просто нужно будет обновить модуль, если появится новый). Место создано). Мой первый подход состоял в том, чтобы создать эти поля из функции init() с помощью кода (вызывая объекты «ir.model.fields» и «ir.model.data»), но почему-то они не распознавались в представлении (после добавления те же поля через fields_view_get(), конечно). Поэтому я пошел с этим подходом, и теперь все в порядке. - person nicobustillos; 10.10.2012

Когда вы пишете _columns = _get_dyna_cols() в теле класса, этот вызов функции выполняется прямо там, в теле класса, поскольку Python все еще анализирует сам класс. В этот момент ваш метод _get_dyn_cols является просто объектом функции в локальном (тело класса) пространстве имен - и он вызывается.

Сообщение об ошибке, которое вы получаете, связано с отсутствующим параметром self, который вставляется только тогда, когда вы обращаетесь к своей функции как к методу, но это сообщение об ошибке не в том, что здесь неправильно: неправильно то, что вы делаете немедленный вызов функции и ожидая особого поведения, например позднего исполнения.

Способ в Python для достижения того, чего вы хотите, т.е. для автоматического вызова метода при доступе к атрибуту colluns, заключается в использовании встроенного «свойства». В этом случае сделайте следующее: _columns = property(_get_dyna_cols) — это создаст атрибут класса с именем «столбцы», который с помощью механизма, называемого «протокол дескриптора», будет вызывать нужный метод всякий раз, когда к атрибуту обращаются из экземпляра.

Чтобы узнать больше о встроенном свойстве, проверьте документы: http://docs.python.org/library/functions.html#property

person jsbueno    schedule 10.10.2012
comment
Не уверен, что ваше решение сработает для него, учитывая структуру OpenERP, но ваш анализ проблемы точен. - person Ethan Furman; 12.03.2013
comment
Привет, nicobustillos, не могли бы вы уточнить успешный ответ, потому что я слишком застрял при создании динамических полей. Я использовал команду Alter в своей функции для создания поля в db. - person Arsalan Sherwani; 14.04.2014