Подтвердить что ты не робот

Разница между setattr и манипуляцией с объектом в python/django

У меня есть следующая модель:

class Ticket(models.Model):
    title = models.CharField()
    merged_to = models.ForeignKey("self", related_name='merger_ticket', null=True, blank=True)
    looser_ticket = models.BooleanField(default=False)

Существует несколько способов манипулирования моделью:

Первая

ticket = Ticket.objects.get(pk=1)
ticket.title = "This is edit title"
ticket.merged_to_id = 2
ticket.looser_ticket = True

Второй

ticket = Ticket.objects.get(pk=1)
setattr(ticket, "title", "Edit Title")
setattr(ticket, "merged_to_id", 2)
setattr(ticket, "looser_ticket", True)

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

Спасибо!

4b9b3361

Ответ 1

Это больше вопрос Python.

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

class MyVector(object):
    x = 0
    y = 0

или вы можете создать класс динамически, выполнив:

fields = {'x':0, 'y':0}
MyVector = type('MyVector', (object,), fields)

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

Поэтому, когда вы заранее знаете атрибуты класса, вы можете установить атрибуты класса, используя обозначение объекта:

instance.attribute = value

Имейте в виду, что это эквивалентно:

instance.__setattr__("attribute", value)

Однако существуют сценарии, в которых вы не знаете атрибутов класса, которыми вам нужно будет управлять заранее. Здесь вы можете использовать функцию __setattr__. Однако это не рекомендуемая практика. Поэтому вместо этого рекомендуется использовать встроенный метод Python setattr, который внутренне вызывает метод __setattr__:

setattr(instance, attribute, value)

Используя этот подход, вы можете устанавливать атрибуты, которые вы не знаете заранее, или вы можете даже зацикливать некоторые dict и устанавливать значения из dict:

values = {
    'title': 'This is edit title',
    ...
}
for k, v in values.items():
    setattr(ticket, k, v)

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

Ответ 2

Если вы знаете свойства объектов перед рукой, вероятно, вы должны использовать первый метод. Просто присвойте значения свойств напрямую.

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

possible_fields = ['title', 'looser_ticket']
ticket = Ticket.objects.get(pk=1)
for field in possible_fields:
  if request.GET.get(field):
     setattr(ticket, field, request.GET[field])

"Не работает", вероятно, не зависит от того, как вы устанавливаете значения, уверены ли вы, что впоследствии сохранили свои изменения?