40

我有以下模型:

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)

当我操作这些东西时,在布尔值更新的视图中,第一种方法不起作用,但是第二种方法起作用。使用第一个和第二个有什么区别,什么时候应该使用?

谢谢!

4

2 回答 2

52

这更像是一个 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)

不知道为什么常规符号不起作用。它可能与您用于设置属性的方法无关。

于 2012-10-09T14:09:09.830 回答
10

如果您事先知道对象属性,您可能应该使用第一种方法。只需直接分配属性值。

当您需要为属性动态分配值时,第二个可能很有用。也许用户有能力改变许多不同属性的值,而你事先不知道哪一个会有值,你可以动态添加值

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])

“不工作”可能不取决于您设置值的方式,您确定您之后保存了更改吗?

于 2012-10-09T13:50:38.610 回答