0
votes

Here I am trying to save the Seller into the Order model after a Customer places a successful order. As the logged in User is a Customer so it shows RelatedObjectDoesNotExist: User has no seller. But I want to save the Seller after a Customer places an order, so that the Seller can be notified that the Seller has a new order. But in the Order Model where seller = models.ForeignKey(Seller, blank=True, null=True, on_delete=models.CASCADE), here it doesn't save the seller.

'cart views.py`

def checkout(request):
    cart_obj, cart_created = Cart.objects.new_or_get(request)
    order_obj = None
    if cart_created or cart_obj.products.count() == 0:
        return redirect('cart:cart')
    login_form = CustomerLoginForm()
    signin_form = CreateCustomerForm()
    address_form = AddressForm()
    billing_address_id = request.session.get("billing_address_id", None)
    shipping_address_id = request.session.get("shipping_address_id", None)
    billing_profile, billing_profile_created = BillingProfile.objects.new_or_get(request)
    address_qs = None
    customer = request.user.customer
    seller = request.user.seller
    if billing_profile is not None:
        if request.user.is_authenticated:
            address_qs = Address.objects.filter(billing_profile=billing_profile)
        order_obj, order_obj_created = Order.objects.new_or_get(billing_profile, cart_obj, customer, seller)
        if shipping_address_id:
            order_obj.shipping_address = Address.objects.get(id=shipping_address_id)
            del request.session["shipping_address_id"]
        if billing_address_id:
            order_obj.billing_address = Address.objects.get(id=billing_address_id)
            del request.session["billing_address_id"]

        if billing_address_id or shipping_address_id:
            order_obj.save()
    if request.method == "POST":
        is_done = order_obj.check_done()
        if is_done:
            order_obj.mark_paid()
            request.session['cart_items'] = ""
            del request.session['cart_id']
            return redirect("cart:success")

    context = {
        'object':order_obj,
        'billing_profile':billing_profile,
        'login_form':login_form,
        'signin_form': signin_form,
        'address_form':address_form,
        'address_qs': address_qs,
    }
    return render(request, 'cart/checkout.html', context)

accounts models.py


class UserManager(BaseUserManager):
    """Define a model manager for User model with no username field."""

    use_in_migrations = True

    def _create_user(self, email, password, **extra_fields):
        """Create and save a User with the given email and password."""
        if not email:
            raise ValueError('The given email must be set')
        email = self.normalize_email(email)
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_user(self, email, password=None, **extra_fields):
        """Create and save a regular User with the given email and password."""
        extra_fields.setdefault('is_staff', False)
        extra_fields.setdefault('is_superuser', False)
        return self._create_user(email, password, **extra_fields)

    def create_superuser(self, email, password, **extra_fields):
        """Create and save a SuperUser with the given email and password."""
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)

        if extra_fields.get('is_staff') is not True:
            raise ValueError('Superuser must have is_staff=True.')
        if extra_fields.get('is_superuser') is not True:
            raise ValueError('Superuser must have is_superuser=True.')

        return self._create_user(email, password, **extra_fields)


class User(AbstractUser):
    """User model."""

    username = None
    email = models.EmailField(_('email address'), unique=True)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []

    objects = UserManager() ## This is the new line in the User model. ##


class Customer(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE,  primary_key=True)
    email = models.EmailField(_('email address'), unique=True)
    full_name = models.CharField(max_length=120, null=True, blank=True)
    phone = models.IntegerField(null=True, blank=True)
    profile_pic = models.ImageField(upload_to='profile-image/', default='profile1.png', null=True, blank=True)

    def __str__(self):
        return self.user.email

class Seller(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
    email = models.EmailField(_('email address'), unique=True)
    full_name = models.CharField(max_length=120, null=True, blank=True)
    phone = models.IntegerField(null=True, blank=True)
    profile_pic = models.ImageField(upload_to='profile-image/', default='profile1.png', null=True, blank=True)

    def __str__(self):
        return self.user.email

cart models.py

class CartManager(models.Manager):
    # creating a new cart or getting the current one
    def new_or_get(self, request):
        cart_id = request.session.get("cart_id", None)
        qs = self.get_queryset().filter(id=cart_id)
        if qs.count() == 1:
            new_obj = False # the cart exists
            cart_obj = qs.first()
            if request.user.is_authenticated and cart_obj.user is None:
                cart_obj.user = request.user
                cart_obj.save()
        else:
            cart_obj = Cart.objects.new(user=request.user)
            new_obj = True # Ceated new
            request.session['cart_id'] = cart_obj.id
        return cart_obj, new_obj

    # Associating the user to the cart

    def new(self, user=None):
        user_obj = None
        if user is not None:
            if user.is_authenticated:
                user_obj = user
        return self.model.objects.create(user=user_obj)

class Cart(models.Model):
    user        = models.ForeignKey(User, null=True, blank=True, on_delete=models.CASCADE)
    products    = models.ManyToManyField(Product, blank=True)

    quantity    = models.IntegerField(default=1)

    subtotal    = models.DecimalField(default=0.00, max_digits=100, decimal_places=2)
    total       = models.DecimalField(default=0.00, max_digits=100, decimal_places=2)

    updated     = models.DateTimeField(auto_now=True)
    timestamp   = models.DateTimeField(auto_now_add=True)

    objects = CartManager()

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

product models.py

class Product(models.Model):
    title               = models.CharField(max_length=120)
    description         = models.TextField(max_length=400)
    categories          = models.CharField(max_length=120, choices=CATEGORIES)
    volume              = models.DecimalField(decimal_places=2,max_digits=10, default=0.00)
    volume_type         = models.CharField(max_length=120, choices=PRODUCT_VOL_TYPE)
    product_stock       = models.IntegerField(default=0.00)
    price               = models.DecimalField(decimal_places=2,max_digits=10, default=0.00)
    image               = models.ImageField(upload_to='products/', null=True, blank=True)
    active              = models.BooleanField(default=True)
    timestamp           = models.DateTimeField(auto_now_add=True)
    slug                = models.SlugField(blank=True, unique=True)

    seller = models.ForeignKey(Seller, on_delete=models.CASCADE)

    objects = ProductManager()

    def __str__(self):
        return self.title

order models.py


class OrderManager(models.Manager):
    def new_or_get(self, billing_profile, cart_obj, customer, seller):
        created = False
        qs = self.get_queryset().filter(cart=cart_obj, billing_profile=billing_profile, customer=customer, seller=seller, active=True, status='created')
        if qs.count() == 1:
            obj = qs.first()
        else:
            obj = self.model.objects.create(billing_profile=billing_profile, customer=customer, seller=seller, cart=cart_obj)
            created = True
        return obj, created


class Order(models.Model):
    order_id = models.CharField(max_length=120, blank=True)

    billing_profile = models.ForeignKey(BillingProfile, blank=True, null=True, on_delete=models.CASCADE)
    shipping_address = models.ForeignKey(Address, related_name="shipping_address", null=True, blank=True, on_delete=models.CASCADE)
    billing_address = models.ForeignKey(Address, related_name="billing_address", null=True, blank=True, on_delete=models.CASCADE)

    shipping_total = models.DecimalField(default=5.99, max_digits=100, decimal_places=2) 
    total = models.DecimalField(default=0.00, max_digits=100, decimal_places=2)

    status = models.CharField(max_length=120, default='created', choices=ORDER_STATUS_CHOICES)
    active = models.BooleanField(default=True)

    cart = models.ForeignKey(Cart, on_delete=models.CASCADE)

    customer = models.ForeignKey(Customer,blank=True, null=True,  on_delete=models.CASCADE)
    seller = models.ForeignKey(Seller, blank=True, null=True, on_delete=models.CASCADE)

    objects = OrderManager()

    def __str__(self):
        return self.order_id

Traceback

Internal Server Error: /cart/checkout/

Traceback (most recent call last):

File "D:\mondayBS\lib\site-packages\django\core\handlers\exception.py", line 34, in inner response = get_response(request)

File "D:\mondayBS\lib\site-packages\django\core\handlers\base.py", line 115, in _get_response response = self.process_exception_by_middleware(e, request)

File "D:\mondayBS\lib\site-packages\django\core\handlers\base.py", line 113, in _get_response response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "D:\mondayBS\src\cart\views.py", line 68, in checkout seller = request.user.seller

File "D:\mondayBS\lib\site-packages\django\utils\functional.py", line 225, in inner return func(self._wrapped, *args)

File "D:\mondayBS\lib\site-packages\django\db\models\fields\related_descriptors.py", line 420, in get
raise self.RelatedObjectDoesNotExist( accounts.models.User.seller.RelatedObjectDoesNotExist: User has no seller.

Probably this are the lines that are not working properly. May be!

cart views.py

order_obj, order_obj_created = Order.objects.new_or_get(billing_profile, cart_obj, customer, seller)

order models.py

def new_or_get(self, billing_profile, cart_obj, customer, seller):
        created = False
        qs = self.get_queryset().filter(cart=cart_obj, billing_profile=billing_profile, customer=customer, seller=seller, active=True, status='created')
        if qs.count() == 1:
            obj = qs.first()
        else:
            obj = self.model.objects.create(billing_profile=billing_profile, customer=customer, seller=seller, cart=cart_obj)
            created = True
        return obj, created
1
Is seller available on the Cart model? What if an order has multiple products with different sellers? - Iain Shelvington
@IainShelvington No, the Cart model don't have seller associated with it. A Cart has a ManyToMany realtion with the Product, so if there are multiple products with different Sellers the Customer can still see from which Seller they have bought. - Debopriyo Das
@IainShelvington I got your point. Since the Order can have multiple Product from different Seller and I am just trying to save a single Seller to that particular Order it's bad way to do it. How should I proceed with this? I added the Cart model . - Debopriyo Das
@IainShelvington I tried man. But I just couldn't figure it out. If you save time can we connect through screen share or anything. Anything. I won't take too much off your time - Debopriyo Das

1 Answers

0
votes

I would suggest removing the Order.seller foreign key. An Order can have many products and many sellers so you need to notify all of them when the order is placed. You can get the sellers for an order like this or similar depending on related_names for relationships

Seller.objects.filter(product__cart__order=order).distinct()

You can then loop over the sellers to notify each one