Django: Как правильно заполнить список необязательных атрибутов объекта, которые нужно заключить в try / кроме? Это хорошее место для eval ()? - PullRequest
0 голосов
/ 29 декабря 2010

Я неоднократно оказываюсь в положении, когда я пишу определенные поля экземпляра модели django в список по разным причинам (экспорт в CSV, ведение журнала), и я думаю, что то же самое верно для многих других людей.

Создание отчета может потребовать обхода внешних ключей, ЕСЛИ они существуют.Чем больше отчет, тем больше нечитаемый код становится, когда я обертываю попытки получения атрибута в try/except блоках.

Опциональные внешние ключи также являются проблемами: item.optional_fk.optional_date.method()

for item in django_model_instances:
    try:
          date_created = item.order.date_created.strftime('%Y/%m/%d')
    except AttributeError:
          date_created = ''

    try:
        date_complete = item.order.date_complete.strftime('%Y/%m/%d')
    except AttributeError:
        date_complete = ''

    # perhaps more try/except...

    writer.writerow([
        item.optional_fk.optional_field.strtime('%Y'),
        item.optional_fk.method(),
        item.bar,
        date_created,
        # other attributes...
        date_complete,
        # other attributes...
         ])

Когда выбольше столбцов для написания кода начинает выглядеть как монстр.

Мне нравится удобочитаемость использования eval(), заключенного в try/except, но я читаю, что следует избегать eval, как чумы.

Использование eval в Python - плохая практика?

  1. Почти всегда есть лучший способ сделать это - попытаться найти лучший способ без написания слишком большого количества кода:)
  2. Оченьопасно и небезопасно - строки жестко запрограммированы
  3. затрудняет отладку - верно
  4. медленно - код для создания отчетов, этоможет быть медленным.

.

def no_exceptions_getter(item, statement):
    try:
        return eval(statement)
    except AttributeError, e:
        log.debug(e)
        return ''

for item in django_model_instances:
    writer.writerow([no_exceptions_getter(item, x) for x in (
        'item.foo',
        'item.bar',
        'item.date_created.strftime("%Y/%m/%d")',
        'item.date_complete.strftime("%Y/%m/%d")',
        'item.optional_foreign_key.foo',
        # more items in a readable list format
        )])

Я не вижу проблем с безопасностью, скоростью или отладкой.Итак, мой вопрос к вам, эксперты, таков: это нормально для использования eval?

Ответы [ 3 ]

3 голосов
/ 29 декабря 2010

Почему вы просто не используете getattr?

for item in django_model_instances:
    date_created = getattr(item.order, 'date_created', '')
    if date_created:
          date_created = date_created.strftime('%Y/%m/%d')

или простая обертка, если этот конкретный шаблон часто используется:

def get_strftime(object, attr):
    value = getattr(object, attr, None)
    if value is None:
        return ''
    return value.strftime('%Y/%m/%d')

writer.writerow([
    item.foo,
    item.bar,
    get_strftime(item.order, 'date_created'),
    get_strftime(item.order, 'date_complete'),
])
0 голосов
/ 29 декабря 2010

Как насчет

def getattrchain(obj, attrStr, fnArgs=None, defaultResult=''):
    try:
        for attr in attrStr.split('.'):
            obj = getattr(obj,attr)
    except AttributeError:
        return defaultResult

    if callable(obj) and fnArgs is not None:
        return obj(*fnArgs)
    else:
        return obj

for item in django_model_instances:
    writer.writerow([getchainattr(item, x, args) for x,args in (
        ('foo', None),
        ('bar', None),
        ('date_created.strftime', [r'%Y/%m/%d']),
        ('date_complete.strftime', [r'%Y/%m/%d']),
        ('optional_foreign_key.foo', None),
    )
])
0 голосов
/ 29 декабря 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...