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

Odczytanie zagnieżdżonych danych z żądania HTTP
hubertsuder
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 119
0
Kopiuj
{
    "id": 1,
    "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
        }
    ]
},

do invoice_num odwołujemy się poprzez request.data['invoice_num'].

a jak odwołać się do lines.name?

KamilAdam
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Silesia/Marki
  • Postów: 5550
5

Może request.data['invoice_num.lines[0].name'] ?
Co to za biblioteka to sprawdzę za ciebie w dokumentacji

hubertsuder
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 119
0
KamilAdam napisał(a):

Może request.data['invoice_num.lines[0].name'] ?
Co to za biblioteka to sprawdzę za ciebie w dokumentacji

Kopiuj
MultiValueDictKeyError at /endpoint/

'invoice_num.lines[0].name'

Łącze api djangorestframework z pythonem

KamilAdam
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Silesia/Marki
  • Postów: 5550
0

Miało być request.data['lines[0].name']
CO to za biblioteka do parsowania? CO tam masz za importy?
Jakis standard z django?

1programmer
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Wrocław
  • Postów: 623
3
Kopiuj
lines = list(map(lambda x: x['name'], request.data['lines']))

albo

Kopiuj
lines = [x['name'] for x in request.data['lines']]
hubertsuder
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 119
0
szafran98 napisał(a):
Kopiuj
lines = list(map(lambda x: x.name), request.data['invoice_num'].lines)
Kopiuj
TypeError at /endpoint/

map() must have at least two arguments.
hubertsuder
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 119
0
Kopiuj
lines = [x['name'] for x in request.data['lines']]
Kopiuj
MultiValueDictKeyError at /endpoint/

'lines'
Kopiuj
lines = list(map(lambda x: x['name'], request.data['lines']))
Kopiuj
MultiValueDictKeyError at /endpoint/

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

No to musisz się odwołać do prawidłowego słownika. Ja nie siedzę w twoim środowisku i tego nie wiem. Jeśli to Django, to sprawdź dokumentację, skąd wyciągnąć ten słownik, przecież skądś go do pierwszego posta wziąłeś. Weź może wyciągnij to metodą get. request.data.get('lines')

screenshot-20221216124556.png

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

Wziąłem go z API djangorestframework.

Zrzut ekranu z 2022-12-16 12-49-31.png

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

Pokaż kod, gdzie to robisz, co ci dałem.

hubertsuder
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 119
0
Kopiuj
buffer = io.BytesIO()

# Create the PDF object, using the buffer as its "file."
p = canvas.Canvas(buffer)

# Draw things on the PDF. Here's where the PDF generation happens.
# See the ReportLab documentation for the full list of functionality.
p.drawString(30, 800, 'invoice num: ' + request.data['invoice_num'])
p.drawString(30, 750, 'issuer: ' + request.data['issuer'])
p.drawString(30, 700, 'header: ' + request.data['header'])
p.drawString(30, 650, 'notes: ' + request.data['notes'])

lines = list(map(lambda x: x['name'], request.data['lines']))
p.drawString(30, 600, 'lines:' + lines)
_13th_Dragon
  • Rejestracja: dni
  • Ostatnio: dni
0
hubertsuder napisał(a):
Kopiuj
p.drawString(30, 600, 'lines:' + lines)

Jakiego wyniku oczekujesz od string+list?

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

Wychodzi, że w request.data masz dict, a nie listę. MultiValueDict posiada metodę get() do pobierania wartości klucza, więc tym sprawdź co wyżej podawałem.
https://github.com/django/django/blob/205c36b58fed5a1a0ff462593fc61b58189027d8/django/utils/datastructures.py#L49

Jeśli request.data to lista słowników, to:

Kopiuj
lines = list(map(lambda x: [x['name'] for x in x['lines']], request.data))

lub

Kopiuj
lines = [[x['name'] for x in y['lines']] for y in request.data]
hubertsuder
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 119
0
szafran98 napisał(a):

Wychodzi, że w request.data masz dict, a nie listę. MultiValueDict posiada metodę get do pobierania wartości klucza, więc tym sprawdź co wyżej podawałem.
https://github.com/django/django/blob/205c36b58fed5a1a0ff462593fc61b58189027d8/django/utils/datastructures.py#L49

Jeśli request.data to lista słowników, to:

Kopiuj
lines = list(map(lambda x: [x['name'] for x in x['lines']], request.data))

lub

lines = [[x['name'] for x in y['lines']] for y in request.data]
Kopiuj
TypeError at /endpoint/

string indices must be integers

zarówno na 1 i na 2 ten sam bląd.

Kopiuj
buf = io.BytesIO()
c = canvas.Canvas(buf, pagesize=letter, bottomup=0)
textob = c.beginText()
textob.setTextOrigin(inch, inch)
textob.setFont('Helvetica', 14)
lines = [
    'invoice num: ' + request.data['invoice_num'],
    'issuer: ' + request.data['issuer'],
    'header: ' + request.data['header'],
    'notes: ' + request.data['notes'],
    'lines: '
]
for line in lines:
    textob.textLine(line)

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

c.drawText(textob)
c.showPage()
c.save()
buf.seek(0)
1programmer
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Wrocław
  • Postów: 623
2

@hubertsuder: No, ale wkleiłeś po prostu to co napisałem, czy faktycznie sprawdziłeś co się znajduje w request.data? Wklej co podaje:

Kopiuj
print(request.data)
print(type(request.data))
hubertsuder
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 119
0

zwraca None

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

To czegoś nie rozumiem. Jakim cudem wcześniej wyciągasz request.data['issuer'], a dalej okazuje się, że request.data ma typ None?

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

coś pomieszałem. Bo print() wzialem wpisalem do responsu:

Kopiuj
return HttpResponse(print(type(request.data)))

widocznie tak nie mozna

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

No nie. To nie ma być w żadnym response. To się wyświetli w terminalu/konsoli, w której jest uruchomiona aplikacja i bardziej mnie interesuje, co zwraca print(request.data).

hubertsuder
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 119
0
Kopiuj
<QueryDict: {'csrfmiddlewaretoken': ['spO8Lag44qMCGkA45VlnWXOdSRGpTImov8x3eERa89Lg7K5Zk7PMkkpw7KSvoIg7'], 'invoice_num': ['faktura 12-2022'], 'issuer': ['IT Company, address, NIP 424234242'], 'header': ['COmpany name, address, NIP 332423324'], 'notes': ['Split payment']}>

mam zakomentowane w serializers.py

Kopiuj
# lines = LineSerializer(many=True) 

bo testuje teraz bez tej funkcji bo mi blad zwraca

ledi12
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Wrocław
50
hubertsuder napisał(a):
Kopiuj
<QueryDict: {'csrfmiddlewaretoken': ['spO8Lag44qMCGkA45VlnWXOdSRGpTImov8x3eERa89Lg7K5Zk7PMkkpw7KSvoIg7'], 'invoice_num': ['faktura 12-2022'], 'issuer': ['IT Company, address, NIP 424234242'], 'header': ['COmpany name, address, NIP 332423324'], 'notes': ['Split payment']}>


mam zakomentowane w serializers.py

Kopiuj
# lines = LineSerializer(many=True) 

bo testuje teraz bez tej funkcji bo mi blad zwraca

No mając zakomentowany serializer (który podałem Ci w poprzednim temacie) żadne z powyższych rozwiązań Ci nie zadziała. Wytłumacz co dokładnie chcesz zrobić, bo nadal nie rozumiem po przeczytaniu tego wątku. @szafran98 podał Ci sensowne rozwiązanie na podstawie opisu (dostęp do konkretnego klucza w liście obiektów) a Ty nadal cudujesz. Coś tutaj nie gra.

Riddle
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 10227
1
hubertsuder napisał(a):

Łącze api djangorestframework z pythonem

:D

1programmer
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Wrocław
  • Postów: 623
2
hubertsuder napisał(a):
Kopiuj
<QueryDict: {'csrfmiddlewaretoken': ['spO8Lag44qMCGkA45VlnWXOdSRGpTImov8x3eERa89Lg7K5Zk7PMkkpw7KSvoIg7'], 'invoice_num': ['faktura 12-2022'], 'issuer': ['IT Company, address, NIP 424234242'], 'header': ['COmpany name, address, NIP 332423324'], 'notes': ['Split payment']}>

mam zakomentowane w serializers.py

Kopiuj
# lines = LineSerializer(many=True) 

bo testuje teraz bez tej funkcji bo mi blad zwraca

No to ziomek, proszę Cię, sam nie pomagasz rozwiązać problemu. Przecież to jest banalny case. Masz dict przypisany do zmiennej i chcesz coś z niego wyciągnąć. Przecież my nie wiemy, co tam jest, nie wklejaj kodu, który dostajesz, na ślepo, tylko ze zrozumieniem. Zastanawiałeś się, jak działa ten kod, który Ci podałem? Wiesz jak działa map, co to lambda, list comprehension? Jeśli nie to nie wchodź w Django, bo problemów będzie tylko więcej. Jeszcze raz powtórzę, pokaż co jest w request.data.

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

Jak

Kopiuj
lines = LineSerializer(many=True)

nie jest zakomentowany to nie moge wysłać json na widok bo mi zwraca błąd, że te pola są wymagane. Dlatego nie moge sprawdzić co jest w request.data.

A jak zakomentuje to moge wyslac slownik wtedy bez zagniezdzenia LINES i wtedy request.data zwraca:

Kopiuj
<QueryDict: {'csrfmiddlewaretoken': ['VcJzVZzMhBUS2TkK4BzEaQdRJjObEm81YVsuotaSlkTwtjPFjN33ydOaYc0h9m2K'], 'invoice_num': ['faktura 12-2022'], 'issuer': ['IT Company, address, NIP 424234242'], 'header': ['COmpany name, address, NIP 332423324'], 'notes': ['Split payment']}>
1programmer
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Wrocław
  • Postów: 623
1

To wysyłaj requesta przez postmana albo curla. Ja pamietam, że panel DRF średnio ogarnia relacje itd. Zresztą jest szybciej, łatwiej i przyjemniej.

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

Jak mam odkomentowany lines = LineSerializer(many=True) i wysyłam POST na widok to wyskakuje mi błąd:

Kopiuj
AssertionError at /endpoint/
The `.create()` method does not support writable nested fields by default.
Write an explicit `.create()` method for serializer `api.serializers.EndpointSerializer`, or set `read_only=True` on nested serializer fields.

Nie obsługuje zagnieżdżonych słowników... trzeba nadpisać funkcje create w views. Próbuje nadpisać widok zgodnie z

https://www.django-rest-framework.org/community/3.0-announcement/#writable-nested-serialization

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

No i o to chodzi. Django musi wiedzieć jak serializować zagnieżdżony model.

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

Robie analogiczne do tutoriala z django rest framework i po nadpisaniu widoku:

Kopiuj
def create(self, validated_data):
    lines_data = validated_data.pop('lines')
    endpoint = Endpoint.objects.create(**validated_data)
    Line.objects.create(endpoint=endpoint, **lines_data)
    return Endpoint

Modele:

Kopiuj
class Endpoint(models.Model):
    invoice_num = models.CharField(max_length=100)
    issuer = models.CharField(max_length=100)
    header = models.CharField(max_length=100)
    notes = models.CharField(max_length=100)

    def __str__(self):
        return self.invoice_num

class Line(models.Model):
    endpoint = models.ForeignKey(Endpoint, on_delete=models.CASCADE, blank=True, null=True, related_name='lines')
    name = models.CharField(max_length=100)
    net = models.IntegerField()
    tax = models.IntegerField()

    def __str__(self):
        return str(self.lines) +' - '+self.name

class PdfModel(models.Model):
    def pdf_upload_path(instance, filename):
        # return f'{instance.created_date.strftime("%Y-%m-%d")}{filename}'
        return f'{filename}'

zwraca mi błąd:

Kopiuj
AttributeError at /endpoint/

'Request' object has no attribute 'pop'
1programmer
  • Rejestracja: dni
  • Ostatnio: dni
  • Lokalizacja: Wrocław
  • Postów: 623
1

No to sprawdź, co jest w validated_data w metodzie create.

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

<rest_framework.request.Request: POST '/endpoint/'> to mi zwraca po print(validated_data)

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.