2009-10-16 24 views
43

Mi chiedo, qual è un modo standard di aggiornare più campi di un'istanza di un modello in django? ... Se ho un modello con alcuni campi,Come aggiornare più campi di un'istanza del modello django?

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

... e io un'istanza con un campo determinato, e poi in una fase separata voglio fornire il resto dei campi, come faccio fallo semplicemente passando un dizionario o parametri di valore chiave? Possibile?

In altre parole, dire che ho un dizionario con alcuni dati in esso che ha tutto ciò che voglio scrivere in un'istanza di quel modello. L'istanza del modello è stata istanziata in un passaggio separato e diciamo che non è stata ancora mantenuta. Posso dire foo_instance.field1 = my_data_dict['field1'] per ogni campo, ma qualcosa mi dice che dovrebbe esserci un modo per chiamare un metodo sull'istanza del modello in cui ho appena passato tutte le coppie campo-valore in una volta e le aggiorna. Qualcosa come foo_instance.update(my_data_dict). Non vedo alcun metodo incorporato come questo, mi manca o come viene fatto in modo efficiente?

Ho la sensazione che questo sia un ovvio tipo di domanda RTM ma non l'ho visto nei documenti.

risposta

93

E 'forte la tentazione di pasticciare con __dict__, ma che non si applica agli attributi ereditati da una classe genitore.

è possibile iterare il dict per assegnare all'oggetto:

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

Oppure è possibile modificare direttamente da un set di query (assicurandosi che la query impostata solo restituisce l'oggetto che ti interessa):

+0

funziona con i campi m2m? –

24

Si potrebbe provare questo:

obj.__dict__.update(my_data_dict) 
+6

Questo non si applica agli attributi ereditati. –

+1

Quali sono le implicazioni del fatto che non si applica agli attributi ereditati? –

+0

Inoltre, stai cercando di aggiornare un ForeignKey, usando __dict__, i relativi valori name sono 'field_name_id' not' field_name', devi stare attento a questo. – levi

3

Sembra una cosa naturale che vorresti fare ma come te non l'ho trovata nemmeno nei documenti. I documenti dicono che dovresti sottoclasse save() sul modello. E questo è quello che faccio.

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() 
+1

Pensando di fare un decoratore per i modelli che aggiungono un nuovo metodo "dict_save" (quindi 2 metodi di salvataggio per il modello - normale e dict) con il corpo sopra la volta successiva che mi serve. Ho cercato il codice che ho usato per fare questo ed è lo stesso, tranne che lo stavo facendo al di fuori di save.Aveva un metodo update_model_obj_from_dict (model_object, update_dict) con praticamente lo stesso corpo di cui sopra e mi aspettavo che avrei scelto quando chiamare save() dopo. Mi piace avere la scelta. quindi forse un metodo sul modello chiamato "set_from_dict" con tutto sopra tranne l'ultima riga e usando solo il salvataggio più tardi. – Purrell

2

ottengo il nome di chiave primaria, lo usano per filtrare con Queryset.filter() e l'aggiornamento con 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) 

Questo mi consente di aggiornare un'istanza qualunque sia la chiave primaria.

1

aggiornamenti tramite 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) 
+0

Benvenuti in SO. Quando pubblichi le risposte, includi una spiegazione del tuo codice e ricorda di formattare il testo. – Tony

Problemi correlati