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

0
{
    "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?

5

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

0
KamilAdam napisał(a):

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

MultiValueDictKeyError at /endpoint/

'invoice_num.lines[0].name'

Łącze api djangorestframework z pythonem

0

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

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

albo

lines = [x['name'] for x in request.data['lines']]
0
szafran98 napisał(a):
lines = list(map(lambda x: x.name), request.data['invoice_num'].lines)
TypeError at /endpoint/

map() must have at least two arguments.
0
lines = [x['name'] for x in request.data['lines']]
MultiValueDictKeyError at /endpoint/

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

'lines'
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

0

Wziąłem go z API djangorestframework.

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

1

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

0
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)
0
hubertsuder napisał(a):
p.drawString(30, 600, 'lines:' + lines)

Jakiego wyniku oczekujesz od string+list?

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:

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

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]
TypeError at /endpoint/

string indices must be integers

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

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

print(request.data)
print(type(request.data))
0

zwraca None

1

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

0

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

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

widocznie tak nie mozna

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

0
<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

# lines = LineSerializer(many=True) 

bo testuje teraz bez tej funkcji bo mi blad zwraca

50
hubertsuder napisał(a):
<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

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

1
hubertsuder napisał(a):

Łącze api djangorestframework z pythonem

:D

2
hubertsuder napisał(a):
<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

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

0

Jak

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:

<QueryDict: {'csrfmiddlewaretoken': ['VcJzVZzMhBUS2TkK4BzEaQdRJjObEm81YVsuotaSlkTwtjPFjN33ydOaYc0h9m2K'], 'invoice_num': ['faktura 12-2022'], 'issuer': ['IT Company, address, NIP 424234242'], 'header': ['COmpany name, address, NIP 332423324'], 'notes': ['Split payment']}>
1

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

0

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

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

2

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

0

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

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:

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:

AttributeError at /endpoint/

'Request' object has no attribute 'pop'
1

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

0

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

1 użytkowników online, w tym zalogowanych: 0, gości: 1