web-dev-qa-db-fra.com

Différence entre setattr et manipulation d'objets en python / django

J'ai le modèle suivant:

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)

Il existe deux façons de manipuler le modèle:

Premier

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

Deuxième

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

Lorsque je manipulais les choses, dans les vues de la mise à jour de la valeur booléenne, la première méthode ne fonctionnait pas, mais la deuxième méthode fonctionnait. Quelle est la différence entre utiliser le premier et le deuxième, et quand doit-on les utiliser?

Merci!

26
whatf

Il s'agit plus d'une question Python.

Python est un langage très dynamique. Vous pouvez coder des choses (classes) à l'avance, ou Python vous permet de créer des classes complètement dynamiquement au moment de l'exécution. Prenons l'exemple suivant d'une classe vectorielle simple. Vous pouvez créer/coder le classe à l'avance comme:

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

ou vous pouvez créer la classe dynamiquement en faisant:

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

La principale différence entre les méthodes est que, pour celui que vous connaissez les attributs de classe à l'avance, tandis que pour la deuxième méthode, comme vous pouvez l'imaginer, vous pouvez créer par programme le dictionnaire fields, donc vous pouvez créer une classe complètement dynamique ( es).

Ainsi, lorsque vous connaissez les attributs de la classe à l'avance, vous pouvez définir des attributs de classe à l'aide de la notation d'objet:

instance.attribute = value

Gardez à l'esprit que cela équivaut à:

instance.__setattr__(attribute, value)

Cependant, il existe des scénarios où vous ne connaissez pas les attributs de classe que vous devrez manipuler à l'avance. C'est ici que vous pouvez utiliser __setattr__ fonction. Cependant, ce n'est pas une pratique recommandée. Donc, à la place, la recommandation est d'utiliser la méthode intégrée de Python setattr qui appelle en interne le __setattr__ méthode:

setattr(instance, attribute, value)

En utilisant cette approche, vous pouvez définir des attributs que vous ne connaissez pas à l'avance ou vous pouvez même boucler certains dict et définir des valeurs à partir de dict:

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

Je ne sais pas pourquoi la notation régulière n'a pas fonctionné. Cela n'a probablement rien à voir avec la méthode que vous avez utilisée pour définir les attributs.

35
miki725

Si vous connaissez les propriétés des objets à l'avance, vous devriez probablement utiliser la première méthode. Attribuez simplement des valeurs de propriété directement.

La seconde peut être utile lorsque vous devez affecter dynamiquement une valeur à une propriété. Peut-être qu'un utilisateur a la possibilité de modifier les valeurs d'un certain nombre d'attributs différents et que vous ne savez pas lequel aura une valeur à l'avance, vous pouvez ajouter dynamiquement des valeurs

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

Le "ne fonctionne pas" ne dépend probablement pas de la façon dont vous définissez les valeurs, êtes-vous sûr d'avoir enregistré vos modifications par la suite ??

9
dm03514