web-dev-qa-db-fra.com

Comment mettre à jour plusieurs champs d'une instance de modèle Django?

Je me demande, quelle est une façon standard de mettre à jour plusieurs champs d'une instance d'un modèle dans django? ... Si j'ai un modèle avec quelques champs,

Class foomodel(models.Model):
    field1 = models.CharField(max_length=10)
    field2 = models.CharField(max_length=10)
    field3 = models.CharField(max_length=10)
    ...

... et je l'instancie avec un champ donné, puis dans une étape distincte, je veux fournir le reste des champs, comment faire en passant simplement un dictionnaire ou des paramètres de valeur clé? Possible?

En d'autres termes, disons que j'ai un dictionnaire contenant des données contenant tout ce que je veux écrire dans une instance de ce modèle. L'instance de modèle a été instanciée dans une étape distincte et disons qu'elle n'a pas encore été persistée. Je peux dire foo_instance.field1 = my_data_dict['field1'] Pour chaque champ, mais quelque chose me dit qu'il devrait y avoir un moyen d'appeler une méthode sur l'instance de modèle où je passe juste toutes les paires champ-valeur à la fois et il les met à jour. Quelque chose comme foo_instance.update(my_data_dict). Je ne vois aucune méthode intégrée comme celle-ci, est-ce que je la manque ou comment cela se fait-il efficacement?

J'ai le sentiment que c'est une évidence, RTM genre de question, mais je ne l'ai tout simplement pas vu dans les documents.

58
Purrell

Il est tentant de jouer avec __dict__, mais cela ne s'applique pas aux attributs hérités d'une classe parente.

Vous pouvez soit parcourir le dict à affecter à l'objet:

for (key, value) in my_data_dict.items():
    setattr(obj, key, value)

Ou vous pouvez le modifier directement à partir d'un ensemble de requêtes (en vous assurant que votre ensemble de requêtes ne renvoie que l'objet qui vous intéresse):

FooModel.objects.filter(whatever="anything").update(**my_data_dict)
120
Wilfred Hughes

Vous pouvez essayer ceci:

obj.__dict__.update(my_data_dict)
27
Daniel Roseman

Cela semble être une chose si naturelle que vous voudriez le faire, mais comme vous, je ne l'ai pas trouvé non plus dans les documents. Les documents disent que vous devez sous-classe save () sur le modèle. Et c'est ce que je fais.

def save(self, **kwargs):
    mfields = iter(self._meta.fields)
    mods = [(f.attname, kwargs[f.attname]) for f in mfields if f.attname in kwargs]
    for fname, fval in mods: setattr(self, fname, fval)
    super(MyModel, self).save()
4
longhaulblue

J'obtiens le nom de la clé primaire, l'utilise pour filtrer avec Queryset.filter() et mettre à jour avec Queryset.update().

fooinstance = ...    
# Find primary key and make a dict for filter
pk_name foomodel._meta.pk.name
filtr = {pk_name: getattr(fooinstance, pk_name)}
# Create a dict attribute to update
updat = {'name': 'foo', 'lastname': 'bar'}
# Apply
foomodel.objects.filter(**filtr).update(**updat)

Cela me permet de mettre à jour une instance quelle que soit la clé primaire.

2
Zulu

Mettre à jour à l'aide de update()

Discussion.objects.filter(slug=d.slug)
    .update(title=form_data['title'],
            category=get_object_or_404(Category, pk=form_data['category']),
            description=form_data['description'], closed=True)
1
Kusaasira Noah