Odczytanie zagnieżdżonych danych z żądania HTTP

Odczytanie zagnieżdżonych danych z żądania HTTP
1programmer
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Wrocław
  • Postów: 623
1

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.

Riddle
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 10230
2
szafran98 napisał(a):

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.

Gość nadpisał create() w widoku, a create() dostaje request, nie dict. To że próbuje go użyć jak słownika to inna sprawa.

1programmer
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Wrocław
  • Postów: 623
1

Tak jak @Riddle napisał, metoda create ma być nadpisana w serializerze. Sam dałeś link do dokumentacji, a źle z niej przepisałeś XD

Kopiuj
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
hubertsuder
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 119
0

Nadpisalem Create w serializerze i teraz wysyłam w POSTMANIE następujący json na widok:

Kopiuj
{
    "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:

Kopiuj
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:

Kopiuj
{'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)])]}

1programmer
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Wrocław
  • Postów: 623
1

No to musisz debugować. Coś w metodzie create. Możliwe, że przekazujesz listę lines, a nie zmapowane instancje modelu. W docsach masz:

Kopiuj
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.

hubertsuder
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 119
0

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:

Kopiuj
            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}]

1programmer
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Wrocław
  • Postów: 623
1

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.

1programmer
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Wrocław
  • Postów: 623
1

Naprawiłeś? XD

hubertsuder
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 119
0

tego słownika nie moge wyprintować.

print(request.data['lines']) zwraca: [{'name': 'uslugi programistyczne', 'net': 3000, 'tax': 22}, {'name': 'hosting', 'net': 400, 'tax': 22}]

1programmer
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Wrocław
  • Postów: 623
1

No i tak miało być przecież. To zamień lines = [x['name'] for x in main_dict['lines']]

hubertsuder
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 119
0

super. Tylko teraz mi printuje

Kopiuj
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:

    Kopiuj
    lines = [x['name'] for x in request.data['lines']]
    for line in lines:
      textob.textLine('-------------------------------------------------------------------------------------'
                                  '-------------')
      textob.textLine(line)
    

    efekt taki:

Kopiuj
invoice num: faktura 12/2022
issuer: IT Company, address, NIP 424234242
header: COmpany name, address, NIP 332423324
notes: Split payment
--------------------------------------------------------------------------------------------------
uslugi programistyczne
--------------------------------------------------------------------------------------------------
hosting
1programmer
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Wrocław
  • Postów: 623
1

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/

hubertsuder
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 119
0

Nie ma rozwiązania w tym co mi wysłałeś. Muszę poszukać w internecie

1programmer
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Wrocław
  • Postów: 623
2

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.

hubertsuder
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 119
0

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ć.

1programmer
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Wrocław
  • Postów: 623
1

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:

Kopiuj
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.

hubertsuder
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 119
0
Kopiuj
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

Kopiuj
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:

Kopiuj
lines = [x['name'], y['net'], c['tax'] for x, y ,c in request.data['lines']]

Riddle
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 10230
0
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:

Kopiuj
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:

Kopiuj
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']])
1programmer
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Wrocław
  • Postów: 623
1

Przecież możesz zwrócić stringa [f"{x['name']} - {x['net']} - {x['tax']}" for x in request.data['lines']]

hubertsuder
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 119
0
Kopiuj
  lines = [f"x['name'] - x['net'] - x['tax']" for x in request.data['lines']]
  for line in lines:
      textob.textLine('-------------------------------------------------------------------------------------'
                      '-------------')
      textob.textLine(line)

zwraca:

Kopiuj
--------------------------------------------------------------------------------------------------
x['name'] - x['net'] - x['tax']
--------------------------------------------------------------------------------------------------
x['name'] - x['net'] - x['tax']

hubertsuder
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 119
0

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.

Kopiuj
--------------------------------------------------------------------------------------------------
uslugi programistyczne - 1000 - 22
--------------------------------------------------------------------------------------------------
hosting - 200 - 22

Riddle
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 10230
0

Czyli tobie od początku chodziło żeby zbudować taką tabelkę Ascii?

1programmer
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Wrocław
  • Postów: 623
1

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.

hubertsuder
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 119
0

dobra, jest dobrze. Dziekuje CI Szafran. Chciałbym CI sie jakoś odwdzieczyc

1programmer
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Wrocław
  • Postów: 623
2

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.

hubertsuder
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 119
0

Szafran podałeś mi dobre rozwiazanie:

Kopiuj
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:

Kopiuj
lines_net = [x['net'] for x in request.data['lines']]
net_pay = 0
for line in lines_net:
    net_pay += line

1programmer
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Wrocław
  • Postów: 623
1

Jak dla każdej lini chcesz zwrócić kwotę netto i brutto, to zrób tak:

Kopiuj
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.

hubertsuder
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 119
0

nic mi nie printuje jak robie tak jak mówisz. Po prostu puste na pdf

1programmer
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Wrocław
  • Postów: 623
1

A co jest w lines?

hubertsuder
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 119
0

[None, None]

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.