Jak można przekonwertować obiekt Django Model na dyktowanie za pomocą wszystkimi jego polami? Wszystko idealnie zawiera klucze obce i pola z editable=False
.
Pozwól mi rozwinąć. Powiedzmy, że mam model Django, taki jak poniżej:
from django.db import models
class OtherModel(models.Model): pass
class SomeModel(models.Model):
normal_value = models.IntegerField()
readonly_value = models.IntegerField(editable=False)
auto_now_add = models.DateTimeField(auto_now_add=True)
foreign_key = models.ForeignKey(OtherModel, related_name="ref1")
many_to_many = models.ManyToManyField(OtherModel, related_name="ref2")
W terminalu wykonałem następujące czynności:
other_model = OtherModel()
other_model.save()
instance = SomeModel()
instance.normal_value = 1
instance.readonly_value = 2
instance.foreign_key = other_model
instance.save()
instance.many_to_many.add(other_model)
instance.save()
Chcę przekonwertować to na następujący słownik:
{'auto_now_add': datetime.datetime(2015, 3, 16, 21, 34, 14, 926738, tzinfo=<UTC>),
'foreign_key': 1,
'id': 1,
'many_to_many': [1],
'normal_value': 1,
'readonly_value': 2}
Pytania z niezadowalającymi odpowiedziami:
Django: Konwertowanie całego zestawu obiektów Modelu na pojedynczy słownik
Jak mogę przekształcić obiekty Django Model w słownik i nadal mieć ich klucze obce?
to_dict
i obsłużyć ją tak, jak chcesz._meta
definicje modelu, aby znaleźć pola powiązane z modelem i pobrać ich wartości w instancji.Odpowiedzi:
Istnieje wiele sposobów konwersji instancji na słownik o różnym stopniu obsługi przypadków w narożnikach i bliskości pożądanego wyniku.
1.
instance.__dict__
który zwraca
Jest to zdecydowanie najprostsze, ale brakuje go
many_to_many
,foreign_key
jest źle nazwane i zawiera dwie niepożądane rzeczy dodatkowe.2)
model_to_dict
który zwraca
Jest to jedyny z
many_to_many
, ale brakuje pól nieedytowalnych.3)
model_to_dict(..., fields=...)
który zwraca
Jest to zdecydowanie gorsze niż standardowe
model_to_dict
wywołanie.4
query_set.values()
który zwraca
Jest to ten sam wynik,
instance.__dict__
ale bez dodatkowych pól.foreign_key_id
jest nadal błędny imany_to_many
nadal go brakuje.5. Funkcja niestandardowa
Kod dla django
model_to_dict
miał większość odpowiedzi. Wyraźnie usunął pola nieedytowalne, więc usunięcie tej kontroli i pobranie identyfikatorów kluczy obcych dla wielu do wielu pól skutkuje następującym kodem, który zachowuje się zgodnie z potrzebami:Chociaż jest to najbardziej skomplikowana opcja, wywoływanie
to_dict(instance)
daje nam dokładnie pożądany rezultat:6. Użyj serializatorów
ModelSerialzer w Django Rest Framework umożliwia automatyczne tworzenie serializatora z modelu.
zwroty
Jest to prawie tak dobre, jak funkcja niestandardowa, ale auto_now_add jest ciągiem zamiast obiektu datetime.
Runda bonusowa: lepsze drukowanie modelu
Jeśli chcesz mieć model Django z lepszym wyświetlaniem wiersza polecenia Pythona, poproś swoje modele o klasę potomną:
Na przykład, jeśli zdefiniujemy nasze modele jako takie:
Wywołanie
SomeModel.objects.first()
teraz daje wynik w następujący sposób:źródło
isinstance
test w rozwiązaniu nr 5 (i premię) naif f.many_to_many
.model_to_dict
, który wykorzystujeisinstance
. Nie jestem pewien, dlaczego dokonali tego wyboru, ale może istnieć dobry powód (na przykład wprowadzeniemany_to_many
nieruchomości w późniejszej wersji)@property
pola?Znalazłem dobre rozwiązanie, aby uzyskać wynik:
Załóżmy, że masz obiekt modelu
o
:Zadzwoń:
źródło
Rozwiązanie @Zags było wspaniałe!
Dodałbym jednak warunek dla pól daty, aby JSON był przyjazny.
Runda bonusowa
Jeśli chcesz mieć model django z lepszym wyświetlaniem wiersza polecenia Pythona, poproś klasę potomną modeli, aby:
Na przykład, jeśli zdefiniujemy nasze modele jako takie:
Wywołanie
SomeModel.objects.first()
teraz daje wynik w następujący sposób:źródło
Najprostszy sposób
Jeśli twoje zapytanie to Model.Objects.get ():
get () zwróci pojedynczą instancję, abyś mógł bezpośrednio
__dict__
z niej korzystaćmodel_dict =
Model.Objects.get().__dict__
dla filter () / all ():
all () / filter () zwróci listę instancji, dzięki czemu można użyć
values()
do uzyskania listy obiektów.model_values = Model.Objects.all (). values ()
źródło
po prostu
vars(obj)
poda całe wartości obiektuMożesz to również dodać
źródło
Aktualizacja
Nowsza zbiorcza odpowiedź opublikowana przez @zags jest bardziej kompletna i elegancka niż moja własna. Zamiast tego zapoznaj się z tą odpowiedzią.
Oryginalny
Jeśli chcesz zdefiniować własną metodę to_dict, jak sugerował @karthiker, to sprowadza się do problemu z zestawem.
Musimy usunąć źle oznakowane klucze obce z otherDict .
Aby to zrobić, możemy użyć pętli, która tworzy nowy słownik, który zawiera każdy element z wyjątkiem tych z podkreśleniami. Lub, aby zaoszczędzić czas, możemy po prostu dodać tych, do oryginalnego dict od słowniki są tylko zestawy pod maską.
Pozostaje nam zatem następujący dyktand :
I właśnie to zwrócisz.
Z drugiej strony nie można używać podkreślników w edytowalnych = fałszywych nazwach pól. Z drugiej strony będzie to działać dla każdego zestawu pól, w których pola utworzone przez użytkownika nie zawierają podkreślników.
To nie jest najlepszy sposób na zrobienie tego, ale może działać jako rozwiązanie tymczasowe, dopóki nie zostanie znaleziona bardziej bezpośrednia metoda.
W poniższym przykładzie dict utworzono by na podstawie modelu_to_dict, a otherDict utworzono by metodą wartości filtru. Zrobiłbym to z samymi modelami, ale nie mogę zmusić mojej maszyny do zaakceptowania innego Modelu.
Mam nadzieję, że powinno to postawić cię w trudnym polu odpowiedzi na twoje pytanie.
źródło
re
. Jeśli ma odfiltrować klucze z podkreśleniami, nie jest to ani poprawny kod, ani prawidłowe zachowanie.re.match("_", "reference1_id")
ZwrotyNone
i uzasadnione kolumny w bazie danych mogą zawierać podkreślenia w swoich nazwach.editable=false
dziedzinach. Chciałem tylko dostarczyć coś, z czym możesz pracować, dopóki nie uda się dostarczyć więcej rozwiązania kanonicznego."_" in string
raczej niżre
w takim przypadku.in
zamiastre
.Wiele ciekawych rozwiązań tutaj. Moim rozwiązaniem było dodanie metody as_dict do mojego modelu ze zrozumieniem dict.
Jako bonus, to rozwiązanie w połączeniu ze zrozumieniem listy nad zapytaniem stanowi dobre rozwiązanie, jeśli chcesz wyeksportować swoje modele do innej biblioteki. Na przykład zrzuć swoje modele do ramki danych pandy:
źródło
(nie chciałem komentować)
Ok, to tak naprawdę nie zależy od typów. Być może źle zrozumiałem pierwotne pytanie, więc wybacz mi, jeśli tak jest. Jeśli tworzysz serliazers.py, tam tworzysz klasy, które mają meta-klasy.
Następnie, gdy uzyskasz dane w klasie widoku, możesz:
To jest prawie to, co mam w różnych miejscach i zwraca ładny JSON przez JSONRenderer.
Jak powiedziałem, jest to dzięki uprzejmości DjangoRestFramework, więc warto się temu przyjrzeć.
źródło
Najłatwiej jest po prostu użyć
pprint
, który znajduje się w podstawowym języku PythonTo daje wynik, który wygląda podobnie,
json.dumps(..., indent = 4)
ale poprawnie obsługuje dziwne typy danych, które mogą być osadzone w instancji modelu, takie jakModelState
iUUID
itp.Testowane na Pythonie 3.7
źródło
Może to ci pomoże. Niech to nie ukrywa relacji wielu do wielu, ale jest to bardzo przydatne, gdy chcesz wysłać swój model w formacie json.
źródło
Najlepsze rozwiązanie, jakie kiedykolwiek widziałeś.
Konwertuj instancję django.db.models.Model i wszystkie powiązane pola funkcji ForeignKey, ManyToManyField i @Property na dict.
https://gist.github.com/shuge/f543dc2094a3183f69488df2bfb51a52
źródło
Odpowiedź z @zags jest wyczerpująca i powinna wystarczyć,
ale metoda nr 5 (najlepsza IMO) generuje błąd, więc poprawiłem funkcję pomocnika.Ponieważ OP poprosił o konwersję
many_to_many
pól na listę kluczy podstawowych zamiast na listę obiektów, ulepszyłem tę funkcję, aby zwracana wartość była teraz możliwa do serializacji JSON - poprzez konwersjędatetime
obiektów nastr
imany_to_many
obiekty na listę identyfikatorów.źródło
concrete_fields
im2m_fields
wyglądają identycznie, więc zakładając, żem2m_fields
pętla ma tutaj niepoprawną implementację.AttributeError: 'list' object has no attribute 'values_list'
którego nie mogłem znaleźć. Używam Django 2.1.1field.value_from_object
iw rezultaciemodel_to_dict
. Zaktualizowałem sekcję 5 mojej odpowiedzi, aby to odzwierciedlić.