Django - store.models.Customer.MultipleObjectsReturned: get() 返回了多个客户 -- 它返回了 2"

Django - store.models.Customer.MultipleObjectsReturned: get() returned more than one Customer -- it returned 2"

我正在尝试制作一个电子商务网站,“匿名用户”或来宾用户可以通过提供他们的姓名、电子邮件和地址来订购和结帐产品。但是在点击“付款”按钮后,我的终端出现错误,显示“store.models.Customer.MultipleObjectsReturned:get() 返回了不止一个客户——它返回了 2 个!”

当我尝试登录并为经过身份验证的用户执行该过程时,没有出现错误。它恰好发生在匿名用户身上。

这是我的 checkout.html:

{% extends 'store/main.html' %}
{% load static %}
{% block content %}
     <div class="row">
        <div class="col-lg-6">
            <div class="box-element" id="form-wrapper">
                <form id="form">
                    <div id="user-info">
                        <div class="form-field">
                            <input required class="form-control" type="text" name="name" placeholder="Name..">
                        </div>
                        <div class="form-field">
                            <input required class="form-control" type="email" name="email" placeholder="Email..">
                        </div>
                    </div>
                    
                    <div id="shipping-info">
                        <hr>
                        <p>Shipping Information:</p>
                        <hr>
                        <div class="form-field">
                            <input class="form-control" type="text" name="address" placeholder="Address..">
                        </div>
                        <div class="form-field">
                            <input class="form-control" type="text" name="city" placeholder="City..">
                        </div>
                        <div class="form-field">
                            <input class="form-control" type="text" name="state" placeholder="State..">
                        </div>
                        <div class="form-field">
                            <input class="form-control" type="text" name="zip" placeholder="zip code..">
                        </div>
                    </div>

                    <hr>
                    <input id="form-button" class="btn btn-success btn-block" type="submit" value="Continue">
                </form>
            </div>

            <br>
            <div class="box-element hidden" id="payment-info">
                <small>Paypal Options</small>
                <button id="make-payment">Make Payment</button>
            </div>
            
        </div>

        <div class="col-lg-6">
            <div class="box-element">
                <a  class="btn btn-outline-dark" href="{% url 'cart' %}">&#x2190; Back to Cart</a>
                <hr>
                <h3>Order Summary</h3>
                <hr>
                {% for item in items %}
                    <div class="cart-row">
                        <div style="flex:2"><img class="row-image" src="{{item.product.imageURL}}"></div>
                        <div style="flex:2"><p>{{item.product.name}}</p></div>
                        <div style="flex:1"><p>₱{{item.product.price|floatformat:2}}</p></div>
                        <div style="flex:1"><p>x{{item.quantity}}</p></div>
                    </div>
                {% endfor %}
                <h5>Items:   {{order.get_cart_items}}</h5>
                <h5>Total:   ₱{{order.get_cart_total|floatformat:2}}</h5>
            </div>
        </div>
    </div>

<script type="text/javascript">
    var shipping = '{{order.shipping}}'
    var user = '{{request.user.is_authenticated}}'
    var total = '{{order.get_cart_total|floatformat:2}}'
    

    if(shipping == 'False'){
        document.getElementById('shipping-info').innerHTML = ''
    }

    if (user == "True"){
        document.getElementById('user-info').innerHTML = ''
    }

    if (shipping == 'False' && user == "True"){
        //Hide entire form if user is logged in and shipping is false
        document.getElementById('form-wrapper').classList.add('hidden');
        //Show payment if logged in user wants to buy an item that does not require shipping
        document.getElementById('payment-info').classList.remove('hidden');
    }

    var form = document.getElementById('form')
    
    form.addEventListener('submit', function(e){
        e.preventDefault()
        console.log('Form Submitted...')
        document.getElementById('form-button').classList.add("hidden");
        document.getElementById('payment-info').classList.remove("hidden");
    })

    document.getElementById('make-payment').addEventListener('click', function(e){
        submitFormData()
    })

    function submitFormData(){
        console.log('Payment button clicked')

        var userFormData = {
            'name':null,
            'email':null,
            'total':total,
        }

        var shippingInfo = {
            'address':null,
            'city':null,
            'state':null,
            'zip':null,
        }

        if (shipping != 'False'){
            shippingInfo.address = form.address.value
            shippingInfo.city = form.city.value
            shippingInfo.state = form.state.value
            shippingInfo.zip = form.zip.value
        }

        if (user == 'False'){
            userFormData.name = form.name.value
            userFormData.email = form.email.value
        }

        var url = '/process_order/'
        fetch(url,{
            method:'POST',
            headers:{
                'Content-Type':'application/json',
                'X-CSRFToken':csrftoken,
            },
            body:JSON.stringify({'form':userFormData, 'shipping':shippingInfo})
        })

        .then((response) => response.json())
        .then((data) => {
            console.log('Success:', data);
            alert('Transaction Completed');

            cart ={}
            document.cookie = 'cart=' + JSON.stringify(cart) + ";domain=;path=/"

            window.location.href = "{% url 'store' %}"
        })
         
    }

</script>

{% endblock content %}

这是我的 models.py:

from django.db import models
from django.contrib.auth.models import User

# Create your models here.

class Customer(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True)
    name = models.CharField(max_length=200, null=True)
    email = models.CharField(max_length=200)

    def __str__(self):
        return self.name

class Product(models.Model):
    name = models.CharField(max_length=200)
    price = models.DecimalField(max_digits=9, decimal_places=2)
    digital = models.BooleanField(default=False, null=True, blank=True)
    image = models.ImageField(null=True, blank=True)

    def __str__(self):
        return self.name

    @property
    def imageURL(self):
        try:
            url = self.image.url 
        except:
            url = ''
        return url

class Order(models.Model):
    customer = models.ForeignKey(Customer, on_delete=models.CASCADE, null=True, blank=True)
    date_ordered = models.DateTimeField(auto_now_add=True)
    complete = models.BooleanField(default=False)
    transaction_id = models.CharField(max_length=20, null=True)

    def __str__(self):
        return str(self.id)

    @property
    def shipping(self):
        shipping = False
        orderitems = self.orderitem_set.all()
        for i in orderitems:
            if i.product.digital == False:
                shipping = True
        return shipping

    @property
    def get_cart_total(self):
        orderitems = self.orderitem_set.all()
        total = sum([item.get_total for item in orderitems])
        return total

    @property
    def get_cart_items(self):
        orderitems = self.orderitem_set.all()
        total = sum([item.quantity for item in orderitems])
        return total

class OrderItem(models.Model):
    product = models.ForeignKey(Product, on_delete=models.SET_NULL, null=True)
    order = models.ForeignKey(Order, on_delete=models.SET_NULL, null=True)
    quantity = models.IntegerField(default=0, null=True, blank=True)
    date_added = models.DateTimeField(auto_now_add=True)

    @property
    def get_total(self):
        total = self.product.price * self.quantity
        return total

class ShippingAddress(models.Model):
    customer = models.ForeignKey(Customer, on_delete=models.SET_NULL, null=True)
    order = models.ForeignKey(Order, on_delete=models.SET_NULL, null=True)
    address = models.CharField(max_length=200, null=False)
    city = models.CharField(max_length=200, null=False)
    state = models.CharField(max_length=200, null=False)
    zip = models.CharField(max_length=200, null=False)
    date_added = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.address

这是我的 views.py:

from django.http import JsonResponse
from django.shortcuts import render
from .models import *
import json
import datetime
from .utils import cookieCart, cartData, guestOrder

def store(request): 

    data = cartData(request)
    cartItems = data['cartItems']

    products = Product.objects.all()
    context = {'products':products, 'cartItems': cartItems}
    return render(request, 'store/store.html', context)

def cart(request):

    data = cartData(request)
    cartItems = data['cartItems']
    order = data['order']
    items = data['items']

    context = {'items':items, 'order':order, 'cartItems': cartItems}
    return render(request, 'store/cart.html', context)

def checkout(request):
    data = cartData(request)
    cartItems = data['cartItems']
    order = data['order']
    items = data['items']

    context = {'items':items, 'order':order, 'cartItems': cartItems}
    return render(request, 'store/checkout.html', context)

def updateItem(request):
    data = json.loads(request.body)
    productId = data['productId']
    action = data['action']
    print('Action:', action)
    print('Product:', productId)

    customer = request.user.customer
    product = Product.objects.get(id=productId)
    order, created = Order.objects.get_or_create(customer=customer, complete=False)

    orderItem, created = OrderItem.objects.get_or_create(order=order, product=product)

    if action == 'add':
        orderItem.quantity = (orderItem.quantity + 1)
    elif action == 'remove':
        orderItem.quantity = (orderItem.quantity - 1)

    orderItem.save()

    if orderItem.quantity <= 0:
        orderItem.delete()

    return JsonResponse('Item was added', safe=False)

def processOrder(request):
    transaction_id = datetime.datetime.now().timestamp()
    data = json.loads(request.body)

    if request.user.is_authenticated:
        customer = request.user.customer
        order, created = Order.objects.get_or_create(customer=customer, complete=False)

    else:
        customer, order = guestOrder(request, data)

    total = float(data['form']['total'])
    order.transaction_id = transaction_id

    if total == order.get_cart_total:
        order.complete = True
    order.save()

    if order.shipping == True:
        ShippingAddress.objects.create(
            customer=customer,
            order=order,
            address=data['shipping']['address'],
            city=data['shipping']['city'],
            state=data['shipping']['state'],
            zip=data['shipping']['zip'],
        )

    return JsonResponse('Payment complete!', safe=False)

这是我的 utils.py:

import json
from .models import *

def cookieCart(request):
    try:
        cart = json.loads(request.COOKIES['cart'])
    except:
        cart = {}
    
    print('Cart:', cart)
    items = []
    order = {'get_cart_total':0, 'get_cart_items':0, 'shipping': False}
    cartItems = order['get_cart_items']

    for i in cart:
        try:
            cartItems += cart[i]["quantity"]

            product = Product.objects.get(id=i)
            total = (product.price * cart[i]['quantity'])

            order['get_cart_total'] += total
            order['get_cart_items'] += cart[i]['quantity']

            item = {
                'product':{
                    'id':product.id,
                    'name':product.name,
                    'price':product.price,
                    'imageURL':product.imageURL,
                    },
                'quantity': cart[i]['quantity'],
                'get_total': total,
                }
            items.append(item)

            if product.digital == False:
                order['shipping'] = True

        except:
            pass
    return {'cartItems': cartItems, 'order': order, 'items': items}

def cartData(request):
    if request.user.is_authenticated:
        customer = request.user.customer
        order, created = Order.objects.get_or_create(customer=customer, complete=False)
        items = order.orderitem_set.all()
        cartItems = order.get_cart_items

    else:
        cookieData = cookieCart(request)
        cartItems = cookieData['cartItems']
        order = cookieData['order']
        items = cookieData['items']

    return {'cartItems': cartItems, 'order': order, 'items': items}

def guestOrder(request, data):
    print('User is not logged in...')

    print('COOKIES:', request.COOKIES)
    name = data['form']['name']
    email = data['form']['email']

    cookieData = cookieCart(request)
    items = cookieData['items'] 

    customer, created = Customer.objects.get_or_create(
        email=email,
        )
    customer.name = name
    customer.save()

    order = Order.objects.create(
        customer=customer,
        complete=False,
        )

    for item in items:
        product=Product.objects.get(id=item['product']['id'])

        orderItem = OrderItem.objects.create(
            product=product,
            order=order,
            quantity=item['quantity']
            )

    return customer, order

我怎样才能摆脱这个错误,让来宾用户在不需要创建帐户或登录的情况下结帐?

已编辑:

当我检查我在管理站点结帐时输入的所有信息时,我遇到了一个错误,提示“str 返回了非字符串(类型 NoneType)”。 =17=]

这是问题所在:

TypeError at /admin/store/customer/3/change/
__str__ returned non-string (type NoneType)
Request Method: GET
Request URL:    http://127.0.0.1:8000/admin/store/customer/3/change/
Django Version: 4.0.2
Exception Type: TypeError
Exception Value:    
__str__ returned non-string (type NoneType)
Exception Location: C:\Users\RolfShin025\Desktop\E-COMMERCE\env\lib\site-packages\django\contrib\admin\options.py, line 1645, in _changeform_view
Python Executable:  C:\Users\RolfShin025\Desktop\E-COMMERCE\env\Scripts\python.exe
Python Version: 3.10.2
Python Path:    
['C:\Users\RolfShin025\Desktop\E-COMMERCE\WannaCome',
 'C:\Program Files\Python310\python310.zip',
 'C:\Program Files\Python310\DLLs',
 'C:\Program Files\Python310\lib',
 'C:\Program Files\Python310',
 'C:\Users\RolfShin025\Desktop\E-COMMERCE\env',
 'C:\Users\RolfShin025\Desktop\E-COMMERCE\env\lib\site-packages']
Server time:    Sat, 26 Feb 2022 19:59:54 +0000

这是我终端中的回溯:

Traceback (most recent call last):
  File "C:\Users\RolfShin025\Desktop\E-COMMERCE\env\lib\site-packages\django\core\handlers\exception.py", line 47, in inner
    response = get_response(request)
  File "C:\Users\RolfShin025\Desktop\E-COMMERCE\env\lib\site-packages\django\core\handlers\base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "C:\Users\RolfShin025\Desktop\E-COMMERCE\env\lib\site-packages\django\contrib\admin\options.py", line 622, in wrapper
    return self.admin_site.admin_view(view)(*args, **kwargs)
  File "C:\Users\RolfShin025\Desktop\E-COMMERCE\env\lib\site-packages\django\utils\decorators.py", line 130, in _wrapped_view
    response = view_func(request, *args, **kwargs)
  File "C:\Users\RolfShin025\Desktop\E-COMMERCE\env\lib\site-packages\django\views\decorators\cache.py", line 57, in _wrapped_view_func
    response = view_func(request, *args, **kwargs)
  File "C:\Users\RolfShin025\Desktop\E-COMMERCE\env\lib\site-packages\django\contrib\admin\sites.py", line 236, in inner
    return view(request, *args, **kwargs)
  File "C:\Users\RolfShin025\Desktop\E-COMMERCE\env\lib\site-packages\django\contrib\admin\options.py", line 1673, in change_view
    return self.changeform_view(request, object_id, form_url, extra_context)
  File "C:\Users\RolfShin025\Desktop\E-COMMERCE\env\lib\site-packages\django\utils\decorators.py", line 43, in _wrapper
    return bound_method(*args, **kwargs)
  File "C:\Users\RolfShin025\Desktop\E-COMMERCE\env\lib\site-packages\django\utils\decorators.py", line 130, in _wrapped_view
    response = view_func(request, *args, **kwargs)
  File "C:\Users\RolfShin025\Desktop\E-COMMERCE\env\lib\site-packages\django\contrib\admin\options.py", line 1549, in changeform_view
    return self._changeform_view(request, object_id, form_url, extra_context)
  File "C:\Users\RolfShin025\Desktop\E-COMMERCE\env\lib\site-packages\django\contrib\admin\options.py", line 1645, in _changeform_view
    'subtitle': str(obj) if obj else None,
TypeError: __str__ returned non-string (type NoneType)

在这里您正在为 AnonymousUser 创建 Customer 对象(只是没有记录 User)。

customer, created = Customer.objects.get_or_create(
        email=email,
        )

如果您多次使用同一电子邮件,我认为它可能会找到更多。