python/django中setattr和对象操作之间的区别

wha*_*atf 25 python django django-models setattribute setattr

我有以下型号:

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)
Run Code Online (Sandbox Code Playgroud)

有几种操作模型的方法:

第一

ticket = Ticket.objects.get(pk=1)
ticket.title = "This is edit title"
ticket.merged_to_id = 2
ticket.looser_ticket = True
Run Code Online (Sandbox Code Playgroud)

第二

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

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

谢谢!

mik*_*725 36

这更像是一个Python问题.

Python是非常动态的语言.您可以提前编写事物(类),或者Python允许您在运行时完全动态地创建类.考虑以下简单向量类的示例.您可以提前创建/编写类,如:

class MyVector(object):
    x = 0
    y = 0
Run Code Online (Sandbox Code Playgroud)

或者您可以通过执行以下操作动态创建类:

fields = {'x':0, 'y':0}
MyVector = type('MyVector', (object,), fields)
Run Code Online (Sandbox Code Playgroud)

这些方法之间的主要区别在于,您可以提前知道类属性,而对于您可以想象的第二种方法,您可以以编程方式创建fields字典,因此您可以创建完全动态的类.

因此,当您提前知道类的属性时,可以使用对象表示法设置类属性:

instance.attribute = value
Run Code Online (Sandbox Code Playgroud)

请记住,这相当于:

instance.__setattr__("attribute", value)
Run Code Online (Sandbox Code Playgroud)

但是,有些情况下您不知道需要提前操作的类属性.这是您可以使用__setattr__功能的地方.但是不推荐练习.所以建议使用Python setattr内置调用__setattr__方法的内置方法:

setattr(instance, attribute, value)
Run Code Online (Sandbox Code Playgroud)

使用这种方法,您可以提前设置您不知道的属性,或者甚至可以循环一些dict并从dict设置值:

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

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


dm0*_*514 9

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

当您需要为属性动态分配值时,第二个非常有用.也许用户能够更改许多不同属性的值,并且您不知道哪一个具有预先获得的值,您可以动态添加值

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])
Run Code Online (Sandbox Code Playgroud)

"不工作"可能不依赖于您设置值的方式,您确定之后保存了更改吗?