No to gdzieś coś jest źle, bo metoda pop w tym miejscu odnosi się do słownika i validated_data powinno być słownikiem. Gdzieś coś musi być źle przypisane albo zadeklarowane.
Odczytanie zagnieżdżonych danych z żądania HTTP
- Rejestracja: dni
- Ostatnio: dni
- Lokalizacja: Wrocław
- Postów: 623
- Rejestracja: dni
- Ostatnio: dni
- Postów: 10230
szafran98 napisał(a):
No to gdzieś coś jest źle, bo metoda
popw tym miejscu odnosi się do słownika ivalidated_datapowinno być słownikiem. Gdzieś coś musi być źle przypisane albo zadeklarowane.
Gość nadpisał create() w widoku, a create() dostaje request, nie dict. To że próbuje go użyć jak słownika to inna sprawa.
- Rejestracja: dni
- Ostatnio: dni
- Lokalizacja: Wrocław
- Postów: 623
Tak jak @Riddle napisał, metoda create ma być nadpisana w serializerze. Sam dałeś link do dokumentacji, a źle z niej przepisałeś XD
class UserSerializer(serializers.ModelSerializer):
profile = ProfileSerializer()
class Meta:
model = User
fields = ['username', 'email', 'profile']
def create(self, validated_data):
profile_data = validated_data.pop('profile')
user = User.objects.create(**validated_data)
Profile.objects.create(user=user, **profile_data)
return user
- Rejestracja: dni
- Ostatnio: dni
- Postów: 119
Nadpisalem Create w serializerze i teraz wysyłam w POSTMANIE następujący json na widok:
{
"invoice_num": "faktura 12-2022",
"issuer": "IT Company, address, NIP 424234242",
"header": "COmpany name, address, NIP 332423324",
"notes": "Split payment",
"lines": [
{
"name": "uslugi programistyczne",
"net": 1000,
"tax": 22
},
{
"name": "hosting",
"net": 200,
"tax": 22
}
]
}
i otrzymuje błąd:
TypeError at /endpoint/
django.db.models.manager.BaseManager._get_queryset_methods.<locals>.create_method.<locals>.manager_method() argument after ** must be a mapping, not list
print(validated_data) zwraca teraz:
{'invoice_num': 'faktura 12-2022', 'issuer': 'IT Company, address, NIP 424234242', 'header': 'COmpany name, address, NIP 332423324', 'notes': 'Split payment', 'lines': [OrderedDict([('name', 'uslugi programistyczne'), ('net', 1000), ('tax', 22)]), OrderedDict([('name', 'hosting'), ('net', 200), ('tax', 22)])]}
- Rejestracja: dni
- Ostatnio: dni
- Lokalizacja: Wrocław
- Postów: 623
No to musisz debugować. Coś w metodzie create. Możliwe, że przekazujesz listę lines, a nie zmapowane instancje modelu. W docsach masz:
def create(self, validated_data):
tracks_data = validated_data.pop('tracks')
album = Album.objects.create(**validated_data)
for track_data in tracks_data:
Track.objects.create(album=album, **track_data)
return album
Zagnieżdżona relacja many-to-one jest tworzona w pętli. W metodzie create, którą wkleiłeś nie ma pętli.
- Rejestracja: dni
- Ostatnio: dni
- Postów: 119
Teraz działa jak zrobiłem na podstawie tego kodu co mi wysłałeś. Szafran i RIddle macie u mnie browara.
ale nadal nie wiem jak wyprintowac na dokumencie PDF zagnieżdżony słownik lines. Próbuje:
lines = [[x['name'] for x in y['lines']] for y in request.data]
for line in lines:
textob.textLine(line)
dostaje error:
string indices must be integers
print(request.data['lines']) zwraca:
[{'name': 'uslugi programistyczne', 'net': 3000, 'tax': 22}, {'name': 'hosting', 'net': 400, 'tax': 22}]
- Rejestracja: dni
- Ostatnio: dni
- Lokalizacja: Wrocław
- Postów: 623
No brawo, zaraz podeślę adres na pw. XD
Dodatkowo jeśli to nie jest zdanie na studia, tylko faktycznie się tego uczysz, to weź podszkol się z czystego Django i Pythona. Django narzuca architekturę i udostępnia programiście API, ale dużo rzeczy dzieje się tam pod spodem i trzeba mieć wyobrażenie co tam się po kolei robi, bo inaczej ciężko o modyfikacje.
- Rejestracja: dni
- Ostatnio: dni
- Lokalizacja: Wrocław
- Postów: 623
Naprawiłeś? XD
- Rejestracja: dni
- Ostatnio: dni
- Postów: 119
tego słownika nie moge wyprintować.
print(request.data['lines']) zwraca: [{'name': 'uslugi programistyczne', 'net': 3000, 'tax': 22}, {'name': 'hosting', 'net': 400, 'tax': 22}]
- Rejestracja: dni
- Ostatnio: dni
- Lokalizacja: Wrocław
- Postów: 623
No i tak miało być przecież. To zamień lines = [x['name'] for x in main_dict['lines']]
- Rejestracja: dni
- Ostatnio: dni
- Postów: 119
super. Tylko teraz mi printuje
lines:
uslugi programistyczne
hosting
a to ma być faktura czyli nie tylko nazwa uslugi ale tez koszt i podatek czyli:
Lines:
-
usługi programistyczne - kwota - podatek
-
hosting - kwota - podatek
teraz mam kod taki:
lines = [x['name'] for x in request.data['lines']] for line in lines: textob.textLine('-------------------------------------------------------------------------------------' '-------------') textob.textLine(line)efekt taki:
invoice num: faktura 12/2022
issuer: IT Company, address, NIP 424234242
header: COmpany name, address, NIP 332423324
notes: Split payment
--------------------------------------------------------------------------------------------------
uslugi programistyczne
--------------------------------------------------------------------------------------------------
hosting
- Rejestracja: dni
- Ostatnio: dni
- Lokalizacja: Wrocław
- Postów: 623
No to już są proste operacje na słowniku.
Tutaj jak posługiwać się tą strukturą danych: https://realpython.com/python-dicts/
A tutaj o f-stringach poczytaj: https://realpython.com/python-f-strings/
- Rejestracja: dni
- Ostatnio: dni
- Postów: 119
Nie ma rozwiązania w tym co mi wysłałeś. Muszę poszukać w internecie
- Rejestracja: dni
- Ostatnio: dni
- Lokalizacja: Wrocław
- Postów: 623
I nie będzie rozwiązania w internecie. Przecież nie znajdziesz przykładu, gdzie ktoś robi to samo z takimi samymi danymi. To Ty masz je wymyślić, a do tego musisz zrozumieć to co wysłałem w ostatnim poście. Żeby wypisywało to co chcesz, to jest jedna, maks dwie linijki kodu. Iteracje po lines już masz, więć musisz tylko wyciągnąć dane ze słownika.
- Rejestracja: dni
- Ostatnio: dni
- Postów: 119
Wiem, że nie znajdę takiego samego przykładu ale mogę analogicznie zrobić do jakiegoś przykładu.
Proszę pomóż mi z tym bo męczę się i nie mogę sobie poradzić.
- Rejestracja: dni
- Ostatnio: dni
- Lokalizacja: Wrocław
- Postów: 623
Wariacie musisz tylko zmienić list comprehension, które Ci podałem XD
lines = [x['name'] for x in request.data['lines']]
Wiesz co znaczy operacja po prawej stronie działania? Zwróć wartość dla klucza name od x dla każdego x z listy, która znajduje się w słowniku request.data pod kluczem lines.
Teraz popatrz na to:
name = 'programowanie'
net = 15000
tax = 19
invoice_service = f'{name} - {net} - {tax}'
print(invoice_service) -> programowanie - 15000 - 19
Prawda, że proste?
W tym: lines = [x['name'] for x in request.data['lines']], to co zwracasz dla każdego elementu, w tym przypadku x['name'] może być czymkolwiek. Stringiem, intem, boolem, funkcją, słownikiem, listą, krotką, klasą, obiektem i bóg wie czym jeszcze. W tym poście jest wszystko czego potrzebujesz. To jest ten przykład, który chciałeś szukać na necie.
- Rejestracja: dni
- Ostatnio: dni
- Postów: 119
name = 'programowanie'
net = 15000
tax = 19
invoice_service = f'{name} - {net} - {tax}'
print(invoice_service) -> programowanie - 15000 - 19
no to jest proste. to też rozumiem
lines = [x['name'] for x in request.data['lines']]
ale nadal nie rozumiem jak stworzyć tą pętle, która będzie printowała kolejno name, net, tax. No bo przecież nie tak:
lines = [x['name'], y['net'], c['tax'] for x, y ,c in request.data['lines']]
- Rejestracja: dni
- Ostatnio: dni
- Postów: 10230
hubertsuder napisał(a):
ale nadal nie rozumiem jak stworzyć tą pętle, która będzie printowała kolejno name, net, tax. No bo przecież nie tak:
lines = [x['name'], y['net'], c['tax'] for x, y ,c in request.data['lines']]
To Ci zwróci tuple z trzema wartościami. Możesz zrobić na całości print(lines) i zobaczyć co tam siedzi.
Jeśli chcesz najpierw wszystkie 'name', potem wszystkie 'net', etc. to możesz zrobić tak:
print([x['name'] for x in request.data['lines']])
print([x['net'] for x in request.data['lines']])
print([x['tax'] for x in request.data['lines']])
- Rejestracja: dni
- Ostatnio: dni
- Lokalizacja: Wrocław
- Postów: 623
Przecież możesz zwrócić stringa [f"{x['name']} - {x['net']} - {x['tax']}" for x in request.data['lines']]
- Rejestracja: dni
- Ostatnio: dni
- Postów: 119
lines = [f"x['name'] - x['net'] - x['tax']" for x in request.data['lines']]
for line in lines:
textob.textLine('-------------------------------------------------------------------------------------'
'-------------')
textob.textLine(line)
zwraca:
--------------------------------------------------------------------------------------------------
x['name'] - x['net'] - x['tax']
--------------------------------------------------------------------------------------------------
x['name'] - x['net'] - x['tax']
- Rejestracja: dni
- Ostatnio: dni
- Postów: 119
No teraz śmiga dobrze. Działa wszystko. Tylko nadal nie wyglada to dobrze na fakturze. Macie jakis pomysl zeby to wizualnie poprawic?
I jeszcze chcialem, żeby zliczało wszystkie x['net'] w sume kwoty do zapłacenia.
--------------------------------------------------------------------------------------------------
uslugi programistyczne - 1000 - 22
--------------------------------------------------------------------------------------------------
hosting - 200 - 22
- Rejestracja: dni
- Ostatnio: dni
- Postów: 10230
Czyli tobie od początku chodziło żeby zbudować taką tabelkę Ascii?
- Rejestracja: dni
- Ostatnio: dni
- Lokalizacja: Wrocław
- Postów: 623
Jak ma być ładniej? To zwykłe formatowanie stringów. Sumowanie net w pętli najprościej i będziesz miał spokój. Tak samo analogicznie. Masz przykłady w temacie albo na necie znajdziesz, zresztą pętle, to są chyba na 30 stronie książki z podstawami. Chyba wyniosłeś jakąś wiedzę przez te pięć stron tematu.
- Rejestracja: dni
- Ostatnio: dni
- Postów: 119
dobra, jest dobrze. Dziekuje CI Szafran. Chciałbym CI sie jakoś odwdzieczyc
- Rejestracja: dni
- Ostatnio: dni
- Lokalizacja: Wrocław
- Postów: 623
Nie trzeba. Po prostu to są takie podstawowe rzeczy, że z mojej perspektywy masz totalny brak talentu do tego albo w dupie naukę. Nie chcę Cię posądzać, że nie masz umiejętności, żeby to ogarnąć, więc bardziej zakładam, że nie chcesz tego zrozumieć. Triggeruje mnie takie podejście, bo zawsze na koniec semestru pojawiają się tutaj studenciaki, którzy udają, że mają problem z czymś, a koniec końców chcą gotowca albo po prostu wklejają treść zadania i proszą o rozwiazanie. Parę dni temu był tu taki, to jeszcze bezczelnie pytał, czemu go pouczam, a nie po prostu dam gotowca XD
Nie chcę generalizować, są też tacy, którzy faktycznie próbują, ale czegoś nie wiedzą i takim z chęcią pomogę.
Jak chcesz mieć szybko rozwiązanie i programowanie Cię w ogóle nie interesuje, to wtedy tworzysz temat w dziale "Ogłoszenia drobne" i zaoszczędzisz czas, swój i kogoś. Jeśli faktycznie próbujesz coś sam zrobić i nie możesz znaleźć rozwiązanie, to na pewno ktoś Ci pomoże.
- Rejestracja: dni
- Ostatnio: dni
- Postów: 119
Szafran podałeś mi dobre rozwiazanie:
lines = [f"{x['name']} - net pay: {x['net']} zl - tax: {x['tax']} %" for x in request.data['lines']]
for line in lines:
textob.textLine('-------------------------------------------------------------------------------------'
'-------------')
textob.textLine(line)
Tylko że w pętli line in lines nie moge się odwoływać do zmiennych wtedy. I nie moge zsumować kwoty brutto, czyli wymnożyć 2 zmienne, x['net'] x x['tax']. Udało mi się tylko z kwotą netto:
lines_net = [x['net'] for x in request.data['lines']]
net_pay = 0
for line in lines_net:
net_pay += line
- Rejestracja: dni
- Ostatnio: dni
- Lokalizacja: Wrocław
- Postów: 623
Jak dla każdej lini chcesz zwrócić kwotę netto i brutto, to zrób tak:
def remap_lines_dict(line):
line.update(
{'gross_ammount': line['net'] * float(f"1.{line['tax']}")})
return line
lines = [remap_lines_dict(line) for line in dict['lines']]
Nie jest 1:1 jak Ty napisałeś, bo nie mam czasu teraz rozkminiać. Masz listę i na stringi już sobie zmapujesz.
- Rejestracja: dni
- Ostatnio: dni
- Postów: 119
nic mi nie printuje jak robie tak jak mówisz. Po prostu puste na pdf
- Rejestracja: dni
- Ostatnio: dni
- Lokalizacja: Wrocław
- Postów: 623
A co jest w lines?
- Rejestracja: dni
- Ostatnio: dni
- Postów: 119
[None, None]