JSONDecodeError

Django, Flask, Bottle, WSGI, CGI…
Antworten
norgsmen
User
Beiträge: 55
Registriert: Samstag 26. Juni 2021, 22:09

Hallo zusammen,

ich bin gerade dabei ein Django Projekt mithilfe eines Tutorials umzusetzen und komme nun leider nicht mehr weiter. Der Fehler tritt erstmalig auf, wenn ich json.loads benutzte. Ich vermute das so ein Fehler unter anderem auftritt, wenn z.b aus einer HTML-Datei die falsche ID übergibt oder aber wenn das JSON Format ungültig ist.
Beides habe ich bei mir kontrolliert und keinen Fehler bzw. Syntaxfehler gefunden.

Im Browser wird mir zudem noch dieser Fehler anzeigt:
Uncaught TypeError: Cannot read properties of null (reading 'value')
at warenkorb.js

Hier ist der Code aus den verschiedenen Datein:

views.py:

Code: Alles auswählen

from django.shortcuts import render, redirect
from django.contrib import messages
from . models import *
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
import json
from django.contrib.auth import authenticate, login, logout
# from django.contrib.auth.forms import UserCreationForm da wird nun ein eignes usercreation from benutzen brauchen wir das Standardformular nicht mehr 
from . forms import EigeneUserCreationForm
import uuid # für eine eindeutige id



def shop(request):
    artikels = Artikel.objects.all()
    ctx = {'artikels':artikels}
    return render(request, 'shop/shop.html', ctx)

def warenkorb(request):
    if request.user.is_authenticated:
        kunde = request.user.kunde
        bestellung, created  = Bestellung.objects.get_or_create(kunde=kunde, erledigt=False)
        artikels = bestellung.bestellteartikel_set.all()
    else:
        artikels = []
        bestellung = []
    
    ctx = {'artikels':artikels, 'bestellung':bestellung}
    return render(request, 'shop/warenkorb.html', ctx)

def kasse(request):
    if request.user.is_authenticated:
        kunde = request.user.kunde
        bestellung, created  = Bestellung.objects.get_or_create(kunde=kunde, erledigt=False)
        artikels = bestellung.bestellteartikel_set.all()
    else:
        artikels = []
        bestellung = []
    
    ctx = {'artikels':artikels, 'bestellung':bestellung}
    return render(request, 'shop/kasse.html', ctx)

@csrf_exempt
def artikelBackend(request):
    daten = json.loads(request.body)
    artikelID = daten['artikelID']
    action = daten['action']
    kunde = request.user.kunde
    artikel = Artikel.objects.get(id=artikelID)
    bestellung, created  = Bestellung.objects.get_or_create(kunde=kunde, erledigt=False)
    bestellteArtikel, created = BestellteArtikel.objects.get_or_create(bestellung=bestellung, artikel=artikel)


    if action == 'bestellen':
        bestellteArtikel.menge = (bestellteArtikel.menge +1)
        messages.success(request, 'Artikel wurde zum Warenkorb hinzugefügt.')
    elif action == 'entfernen':
        bestellteArtikel.menge = (bestellteArtikel.menge -1)
        messages.warning(request, 'Artikel wurde aus dem Warenkorb entfernt.')
    bestellteArtikel.save()

    if bestellteArtikel.menge <=0:
        bestellteArtikel.delete()

    return JsonResponse("Artikel hinzugefügt", safe=False)


def loginSeite(request): # der request enthält die Daten die also benutzername und pw die im HTML template dann eingegeben werden
    seite = 'login'
    if request.method == 'POST':
        benutzername = request.POST['benutzername']
        passwort = request.POST['passwort']
    # jetzt muss geguckt werden ob die Daten auch wirklich valide sind
        benutzer = authenticate(request, username=benutzername, password=passwort) # username und password sind die Daten, die in einem user objekt gepeichert sind 
        
        if benutzer is not None: # Wenn in der Variable benutzer daten vorhanden sind
            login(request, benutzer)
            return redirect('shop') # mit redirect kann man automatische Seitenweiterleitungen einrichten
        else:
            messages.error(request, 'Benutzername oder Passwort nicht korrekt.')
    
    return render(request, 'shop/login.html', {'seite':seite})


def logoutBenutzer(request):
    logout(request)
    return redirect('shop')

def regBenutzer(request):
    seite = 'req'
    form = EigeneUserCreationForm

    if request.method == 'POST':
        form = EigeneUserCreationForm(request.POST) #request.poser enthält die übermittelten Daten also Benutzername und Passwort
        if form.is_valid():
            benutzer = form.save(commit=False)
            benutzer.save()

            kunde = Kunde(name=request.POST['username'], benutzer=benutzer)
            kunde.save()
            bestellung = Bestellung(kunde=kunde)
            bestellung.save()

            login(request, benutzer)
            return redirect('shop')
        else:
            messages.error(request, 'Fehlerhafte Eingabe')

    ctx = {'form':form, 'seite':seite}
    return render(request, 'shop/login.html', ctx)


def bestellen(request):
    auftrags_id = uuid.uuid4()
    daten = json.loads(request.body)
 
    if request.user.is_authenticated:
        kunde = request.user.kunde
        bestellung, created = Bestellung.objects.get_or_create(kunde=kunde, erledigt=False)
        gesamtpreis = float(daten['benutzerDaten']['gesamtpreis'])
        bestellung.auftrags_id = auftrags_id
        bestellung.erledigt = True
        bestellung.save()

        Adresse.objects.create(
            kunde=kunde,
            bestellung=bestellung,
            adresse=daten['lieferadresse']['adresse'],
            plz=daten['lieferadresse']['plz'],
            stadt=daten['lieferadresse']['stadt'],
            land=daten['lieferadresse']['land'],
        )
    else:
        print("nicht eingeloggt")        

    messages.success(request, 'Vielen Dank für ihre Bestellung!')
    return JsonResponse('Bestellung erfolgreich', safe=False)

Javascript Datei:

Code: Alles auswählen

// hiermit haben wir unser Queryset
let bestellenButtons = document.getElementsByClassName('warenkorb-bestellen') 

for (let i = 0; i < bestellenButtons.length; i++){
    bestellenButtons[i].addEventListener('click', function(){
        let artikelID = this.dataset.artikel;
        let action = this.dataset.action;
        updateKundenBestellung(artikelID, action)
    })
}

function updateKundenBestellung(artikelID, action){
// mit dem Klick auf dem Button rufen wir in der fetch api die url  "/artikel_backend/"; auf und schicken mit post die artikelid und die action an die artikelBackend view      
    let url = "/artikel_backend/";

    fetch(url, {
    method: 'post',
    headers: {
        'Content-Type': 'application/json',
        'X-CSRFToken': csrftoken,
    },
    body: JSON.stringify({'benutzerDaten': benutzerDaten, 'lieferadresse': lieferadresse})
    })
    .then(()=>location.reload())
}

//Kasse
let formular = document.getElementById('formular')
let gesamtpreis = document.getElementById('gesamtpreis').value



formular.addEventListener('submit', function(e){
    e.preventDefault()
    document.getElementById('formular-button').classList.add('d-none');
    document.getElementById('bezahlen-info').classList.remove('d-none');
 
})

document.getElementById('bezahlen-button').addEventListener('click', function(e){
    submitFormular()
})

function submitFormular(){ 
    let benutzerDaten = {
        'name': formular.inputName.value,
        'email': formular.inputEmail.value,
        'gesamtpreis': gesamtpreis
    }
    let lieferadresse = {
        'adresse': formular.inputAdresse.value,
        'plz': formular.inputPlz.value,
        'stadt': formular.inputStadt.value,
        'land': formular.inputLand.value,
    }
    console.log(benutzerDaten, lieferadresse)
// Jetzt werden die Daten an das Backende gesendet
    let url = "/bestellen/";

    fetch(url, {
        method: 'post',
        headers:{
            'Content-Type':'application/json', 
            'X-CSRFToken':csrftoken,
        },
        body:JSON.stringify({'benutzerDaten':benutzerDaten, 'lieferadresse':lieferadresse})
    })
    .then(()=>window.location.href="/")

}
HTML Datei:

Code: Alles auswählen

{% extends 'shop/index.html' %}

{% block content %}
    <div class="row mt-4">
        <div class="col-4">
            <div class="shadow p-4">
                <h3>Bestellübersicht</h3>
                <hr>
                {% for artikel in artikels %}
                <div class="d-flex">
                    <p class="p-2">{{artikel.menge}}</p>
                    <p class="me-auto p-2">{{artikel.artikel.name}}</p>
                    <p class="p-2">{{artikel.get_summe|floatformat:2}} €</p>
                </div>
                {% endfor %}
                <hr>
                <div class="d-flex">
                    <p class="me-auto fw-bold p-2">Menge: {{bestellung.get_gesamtmenge}}</p>
                    <p class="fw-bold p-2">Gesamtpreis: {{bestellung.get_gesamtpreis|floatformat:2}} €</p>
                    <input type="number" class="d-none" id="gesamtpreis" value={{bestellung.get_gesamtpreis|floatformat:2}}> <!--jetzt können wir mithilfe id=gesamtpreis auch in der warenkorb.js drauf zuzugreifen-->
                </div>
            </div>
        </div>
        <div class="col-8">
            <div class="shadow p-4">
                <form id="formular" class="row g-3"><!--mit id='formular' können wir das formular eindeutig ansprechen in js greifen wir dann auf diese id zu-->
                    <div class="col-md-6">
                      <label for="inputName" class="form-label">Name</label> 
                      <input type="text" class="form-control" id="inputName" value={{request.user|title}}> <!--mit value kann man ein Eingabefeld mit einem Inhalt vorbelegen-->
                    </div>
                    <div class="col-md-6">
                        <label for="inputEmail" class="form-label">Email</label>
                        <input type="email" class="form-control" id="inputEmail" value="{{request.user.email}}" required>
                    </div>
                    <div class="col-12">
                      <label for="inputAddress" class="form-label">Addresse</label>
                      <input type="text" class="form-control" id="inputAdresse" required> 
                    </div>
                    <div class="col-md-2">
                        <label for="inputPlz" class="form-label">PLZ</label>
                        <input type="text" class="form-control" id="inputPlz" required>
                      </div>
                    <div class="col-md-5">
                      <label for="inputStadt" class="form-label">Stadt</label>
                      <input type="text" class="form-control" id="inputStadt" required>
                    </div>
                    <div class="col-md-5">
                        <label for="inputLand" class="form-label">Land</label>
                        <input type="text" class="form-control" id="inputLand" required>
                      </div>
                    <div class="col-12 d-flex justify-content-end">
                      <button type="submit" id="formular-button" class="btn btn-secondary" >weiter</button>
                    </div>
                  </form>
                  <div class="d-flex d-none" id="bezahlen-info">
                    <p class="me-auto fw-bold">Zahlung: PayPal</p>
                    <button class="btn btn-danger" id="bezahlen-button">bezahlen</button>
                  </div>
            </div>
        </div>
    </div>
{% endblock content %}
Danke fürs Anworten!
Benutzeravatar
__blackjack__
User
Beiträge: 13185
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@norgsmen: Komplette Ausnahme mit Traceback wäre sinnvoll und die Ausgabe der `repr()`-Darstellung der Daten die da dekodiert werden sollen.

Beim Fehler im JavaScript sollte auch die Zeilennummer da stehen wo versucht wird auf `value` von einem ``null``-Wert zuzugreifen.
“There will always be things we wish to say in our programs that in all known languages can only be said poorly.” — Alan J. Perlis
norgsmen
User
Beiträge: 55
Registriert: Samstag 26. Juni 2021, 22:09

@blackjack Also im Terminal wir das hier ausgegeben:

Code: Alles auswählen

raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
[18/Aug/2023 14:16:16] "GET /bestellen/ HTTP/1.1" 500 75878
aber auch nur, wenn ich diese bestimme URL aufrufe. Der Fehler, der mir im Browser angezeigt, wird wird mir auch schon auf anderen Seiten angezeigt.

Code: Alles auswählen

Uncaught TypeError: Cannot read properties of null (reading 'value')
Benutzeravatar
__blackjack__
User
Beiträge: 13185
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@norgsmen: Bei der Ausnahme in Python müsstest Du halt schauen wie Du den kompletten Traceback bekommst. Und wie gesagt, lass Dir vor der Ausnahme mal den Wert ausgeben der dekodiert werden soll. Und zwar die `repr()`-Darstellung, damit man sieht was da tatsächlich drin ist.

Die Fehlermeldung im Browser sollte auch auf die Stelle im Quelltext verweisen *wo* dieser Fehler auftritt. Bei Firefox beispielsweise am Ende der Zeile in der Konsole. Da gibt es ja mehrere Kandidaten wo auf ein `value`-Attribut zugegriffen wird.

Wenn der auch auf anderen Seiten angezeigt wird, dann musst Du das dort halt auch weiter verfolgen und schauen woran es dort liegt.
“There will always be things we wish to say in our programs that in all known languages can only be said poorly.” — Alan J. Perlis
Benutzeravatar
sparrow
User
Beiträge: 4227
Registriert: Freitag 17. April 2009, 10:28

@norgsmen: Was steht denn _über_ den 3 Zeilen Fehler, die du hier gepostet hast?
norgsmen
User
Beiträge: 55
Registriert: Samstag 26. Juni 2021, 22:09

@__blackjack__ würdest du mir bitte helfen, wenn ich dir den Code einmal über codeshare rüberschicke?
norgsmen
User
Beiträge: 55
Registriert: Samstag 26. Juni 2021, 22:09

@sparrow im terminal wird nur das hier ausgeben:

Code: Alles auswählen

    raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
Antworten