2009-10-16 18 views
43

Zastanawiam się, jaki jest standardowy sposób aktualizowania wielu pól instancji modelu w django? ... Jeśli mam model z niektórych dziedzin,Jak zaktualizować wiele pól instancji modelu django?

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

... i oznacz ją z jednego pola podane, a następnie w oddzielnym etapie Chcę zapewnić resztę pól, w jaki sposób zrobić to po prostu przekazując słownik lub parametry wartości klucza? Możliwy?

Innymi słowy, mówię, że mam słownik zawierający pewne dane, które mają wszystko, co chcę napisać w instancji tego modelu. Instancja modelu została utworzona w oddzielnym kroku i powiedzmy, że nie została jeszcze utrwalona. Mogę powiedzieć foo_instance.field1 = my_data_dict['field1'] dla każdego pola, ale coś mówi mi, że powinien istnieć sposób wywoływania metody na instancji modelu, gdzie po prostu przekazuję wszystkie pary wartości pola jednocześnie i aktualizuje je. Coś jak foo_instance.update(my_data_dict). Nie widzę żadnych wbudowanych metod takich jak ta, czy tęsknię za nią, czy jak to się robi?

Mam przeczucie, że jest to oczywiste pytanie typu RTM, ale po prostu nie widziałem tego w dokumentach.

Odpowiedz

93

To kuszące, aby bałagan z __dict__, ale to nie będzie dotyczyć cech odziedziczonych z klasy nadrzędnej.

Można albo iteracyjne nad dict przypisać do obiektu:

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

Albo można bezpośrednio modyfikować go z queryset (upewniając zapytanie ustawić tylko zwraca obiekt jesteś zainteresowany):

+0

czy to działa z polami m2m? –

24

Można spróbować to:

obj.__dict__.update(my_data_dict) 
+6

ten nie stosuje się do odziedziczonych cech. –

+1

Jakie są konsekwencje faktu, że nie będzie on miał zastosowania do atrybutów odziedziczonych? –

+0

Ponadto, czy próbujesz zaktualizować klucz obcego klucza, używając __dict__, powiązane nazwy wartości to 'field_name_id', a nie' field_name', musisz zachować ostrożność. – levi

3

Wygląda na to, że chcesz zrobić coś takiego jak ty, ale nie znalazłem tego w dokumentach. Dokumenty mówią, że powinieneś zapisać podklasy save() na modelu. I to właśnie robię.

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

Myślenie o stworzeniu dekoratora dla modeli, które dodają nową metodę "dict_save" (więc dwie metody zapisu dla modelu - normalna i dyktuj) z ciałem nad następnym razem, kiedy tego potrzebuję. Sprawdziłem kod, którego używałem, i to jest to samo, poza tym, że robiłem to poza zasłoną.Miałem metodę update_model_obj_from_dict (model_object, update_dict) z praktycznie tą samą treścią co powyżej i oczekiwałem, że wybiorę, kiedy wywołać save() po. W pewnym sensie lubię mieć wybór. więc może metoda na modelu o nazwie "set_from_dict" ze wszystkim powyżej z wyjątkiem ostatniej linii i po prostu używając zapisz później. – Purrell

2

uzyskać nazwę klucza podstawowego, należy użyć go do filtrowania z Queryset.filter() i aktualizacji z 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) 

Umożliwia to aktualizację instancji bez względu na klucz podstawowy.

1

Aktualizacja za pomocą 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

Witamy w SO. Publikując odpowiedzi, dołącz objaśnienie kodu i pamiętaj, aby sformatować tekst. – Tony

Powiązane problemy