skip to Main Content

I am using Stripe for handling payments in my Django app.
Whenever I try to fill dummy card credentials and submit, it gives the following error.

AttributeError, ‘Payment’ object has no attribute ‘save’

I cannot figure out how to save the payment object in ‘views.py’.

I have successfully applied migrations in my app and have migrated it, but still I am getting this error.

The following is my views.py

from django.conf import settings
from django.shortcuts import render, get_object_or_404
from django.views.generic import ListView, DetailView, View
from django.utils import timezone
from django.shortcuts import redirect
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.decorators import login_required
import stripe 

from django.contrib import messages
# token = stripe.api_key
stripe.api_key = "sk_test_4eC39HqLyjWDarjtT1zdp7dc"
# `source` is obtained with Stripe.js; see https://stripe.com/docs/payments/accept-a-payment-charges#web-create-token
# stripe.api_key = settings.STRIPE_SECRET_KEY
# Create your views here.

from .models import Item, OrderItem, Order, BillingInformation, Payment
from .forms import CheckoutForm
# def home(request):
#     context = {
#         'items': Item.objects.all()
#     }

#     return render(request,'home.html',context)

class HomeView(ListView):
    model = Item

    template_name = 'home.html'

class ItemDetails(DetailView):
    model = Item
    template_name = 'product.html'

@login_required
def add_to_cart(request, slug):
    item = get_object_or_404(Item, slug=slug)
    order_item, created = OrderItem.objects.get_or_create(
        order_item=item,
        user=request.user,
        is_ordered=False
        )
    order_qs = Order.objects.filter(user=request.user, is_ordered=False)
    if order_qs.exists():
        order = order_qs[0]
        print(order)
        if order.order_items.filter(order_item__slug=item.slug).exists():
            order_item.item_quantity += 1
            order_item.save()
        else:
                order.order_items.add(order_item)

    else:
            date_of_order = timezone.now()
            order = Order.objects.create(user=request.user,date_of_order= date_of_order)
            order.order_items.add(order_item)
    return redirect("core:order-summary")

@login_required
def remove_from_cart(request, slug):
    item = get_object_or_404(Item,slug=slug)
    order_qs = Order.objects.filter(user=request.user, is_ordered=False)
    if order_qs.exists():
        order = order_qs[0]
        if order.order_items.filter(order_item__slug=item.slug).exists():
            order_item = OrderItem.objects.filter(
                                order_item=item,
                                user=request.user,
                                is_ordered=False
                                )[0]
            order.order_items.filter(order_item__slug=item.slug).delete()
        else:
            return redirect("core:product",slug=slug)
    else:
        return redirect("core:product",slug=slug)

    return redirect("core:product",slug=slug)


@login_required
def remove_single_item_from_cart(request, slug):
    item = get_object_or_404(Item,slug=slug)
    order_qs = Order.objects.filter(user=request.user, is_ordered=False)
    if order_qs.exists():
        order = order_qs[0]
        if order.order_items.filter(order_item__slug=item.slug).exists():
            order_item = OrderItem.objects.filter(
                                order_item=item,
                                user=request.user,
                                is_ordered=False
                                )[0]
            if order_item.item_quantity > 1:
                order_item.item_quantity -= 1
                order_item.save()
            else:
                order.order_items.filter(order_item__slug=item.slug).delete()

        else:
            return redirect("core:order-summary")
    else:
        return redirect("core:order-summary")

    return redirect("core:order-summary")



class OrderSummary(LoginRequiredMixin,View):
    def get(self, *args, **kwargs):
        order = Order.objects.get(user=self.request.user, is_ordered=False)
        context = {'object':order}
        return render(self.request,'order-summary.html',context)



class CheckoutView(LoginRequiredMixin,View):


    def get(self,*args,**kwargs):

        form = CheckoutForm
        context = {'form':form}
        return render(self.request,'checkout.html',context)

    def post(self, *args, **kwargs):
        form = CheckoutForm(self.request.POST or None)
        order = Order.objects.get(user=self.request.user, is_ordered=False)
        if form.is_valid():
            street = form.cleaned_data.get('street')
            city = form.cleaned_data.get('city')
            state = form.cleaned_data.get('state')
            landmark = form.cleaned_data.get('landmark')
            shipping_same_as_billing = form.cleaned_data.get('shipping_same_as_billing')
            save_info = form.cleaned_data.get('save_info')
            payment_info = form.cleaned_data.get('payment_info')

            billing_address = BillingInformation(
                user = self.request.user,
                street = street,
                city = city,
                state = state,
                landmark = landmark,
                shipping_same_as_billing = shipping_same_as_billing,
                save_info = save_info,
                payment_info = payment_info
            )

            billing_address.save()
            order.billing_address = billing_address
            order.save()


        return redirect('core:order-summary')

class Payment(LoginRequiredMixin, View):

    def get(self,*args,**kwargs):
        order = Order.objects.get(user=self.request.user, is_ordered=False)
        context = {
            'order':order
        }
        return render(self.request,'payment.html',context)

    def post(self,*args,**kwargs):
        order = Order.objects.get(user=self.request.user,is_ordered=False)
            # token = self.request.POST.get('stripeToken')
        order_amount =  int(order.get_cart_total())
        try:
            charge = stripe.Charge.create(
                    amount=order_amount,
                    currency="inr",
                    source = self.request.POST.get('stripeToken')
                    )

            payment = Payment()
            payment.stripe_charge_id = charge['id']
            payment.amount = order_amount
            payment.user = self.request.user
            payment.save()

            order.is_ordered = True
            order.payment = payment

            order.save()
            messages.success(self.request,"YaYY!! Your order has been successfully placed")
            return render(self.request,'order_placed.html')
        except stripe.error.CardError as e:
            # Problem with the card
            messages.error(self.request,"Card error")
            return redirect("/")
            # pass
        except stripe.error.RateLimitError as e:
            # Too many requests made to the API too quickly

            messages.error(self.request,"Rate limit error")
            # pass
            return redirect("/")
        except stripe.error.InvalidRequestError as e:
            print(e)
            # Invalid parameters were supplied to Stripe API
            # pass

            messages.error(self.request,"Invalid request  error")
            return redirect("/")
        except stripe.error.AuthenticationError as e:
            # Authentication Error: Authentication with Stripe API failed (maybe you changed API keys recently)
            # pass

            messages.error(self.request,"Authentication error")
            return redirect("/")
        except stripe.error.APIConnectionError as e:
            # Network communication with Stripe failed
            # pass

            messages.error(self.request,"API connection error")
            return redirect("/")
        except stripe.error.StripeError as e:
            # Stripe Error
            # pass

            messages.error(self.request,"Stripe error")
            return redirect("/")

The following is my models.py

from django.db import models
from django.conf import settings
from django.shortcuts import reverse
# Create your models here.

CATEGORY_CHOICES = (
        ('S','Shirt'),
        ('SW','Sports Wear'),
        ('OW','Out Wear'),
)

LABEL_CHOICES = (
        ('P','primary'),
        ('S','success'),
        ('D','danger'),
)

PAYMENT_METHOD = (
    ('S','Stripe'),
    ('P',"PayPal"),
)


class Item(models.Model):
    item_name = models.CharField(max_length=200)
    item_price = models.FloatField()
    item_discounted_price = models.FloatField(null=True,blank=True)
    item_description = models.TextField()
    item_category = models.CharField(choices=CATEGORY_CHOICES, default='S', max_length=2)
    item_label = models.CharField(choices=LABEL_CHOICES, default='P', max_length=1)
    item_discount = models.PositiveIntegerField(null=True,blank=True)
    item_image = models.CharField(max_length=500,default='http://leeford.in/wp-content/uploads/2017/09/image-not-found.jpg')
    slug = models.SlugField(default='test-product')


    class Meta:
        db_table = 'Item'

    def __str__(self):
        return self.item_name

    def get_absolute_url(self):
        return reverse('core:product', kwargs={
                    'slug':self.slug
        })

    def get_add_to_cart_url(self):
           return reverse('core:add-to-cart', kwargs={
                    'slug':self.slug
        })

    def get_remove_from_cart_url(self):
        return reverse('core:remove-from-cart', kwargs={
                    'slug':self.slug
        })

    def get_item_price(self):
        if self.item_discounted_price:
            return self.item_discounted_price
        else:
            return self.item_price


class OrderItem(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete = models.CASCADE, blank=True, null=True)
    order_item = models.ForeignKey(Item, on_delete = models.CASCADE)
    item_quantity = models.PositiveIntegerField(default=1)
    is_ordered = models.BooleanField(default=False)

    class Meta:
        db_table = 'Order Item'

    def __str__(self):
        return str(self.item_quantity) + " " + self.order_item.item_name

    def get_total_item_price(self):
        return  self.item_quantity * self.order_item.get_item_price()

    def get_total_savings(self):
        if self.order_item.item_discounted_price:
            return (self.order_item.item_price - self.order_item.item_discounted_price)*self.item_quantity
        else:
            return 0

class BillingInformation(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete = models.CASCADE)
    street = models.CharField(max_length=300)
    city = models.CharField(max_length=50)
    pin_code = models.CharField(max_length=6)
    state = models.CharField(max_length=100)
    landmark = models.CharField(max_length=500)
    shipping_same_as_billing = models.BooleanField(default=False)
    save_info = models.BooleanField(default=False)
    payment_info = models.CharField(choices=PAYMENT_METHOD,max_length=1)

    def __str__(self):
        return self.street+ " " + self.city+ " " + self.state


class Payment(models.Model):
    stripe_charge_id = models.CharField(max_length=50)
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL,blank=True, null=True)
    amount = models.FloatField(default=0)
    time_stamp = models.DateTimeField(auto_now_add=True)

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



class Order(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete = models.CASCADE)
    order_items = models.ManyToManyField(OrderItem)
    date_of_order = models.DateTimeField()
    is_ordered = models.BooleanField(default=False)
    billing_address = models.ForeignKey(BillingInformation,on_delete=models.PROTECT,blank=True,null=True)
    payment = models.ForeignKey(Payment,on_delete=models.SET_NULL,null=True)

    class Meta:
        db_table = 'Order'

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

    def get_cart_total(self):
        price = 0
        for i in self.order_items.all():
            price += i.get_total_item_price()
        return price

The following is the error

 AttributeError at /payment/stripe/ 'Payment' object has no attribute 'save' 
 Request Method:    POST Request
 URL:   http://localhost:8000/payment/stripe/ 
 Django Version:    2.2.4
 Exception Type:    AttributeError Exception Value:  'Payment' object has no attribute 'save' 
 Exception Location:    C:UsershrshkDesktopecommcoreviews.py in post, line 178

2

Answers


  1. You are using Payment class name in views.py and this Payment class is also same in models.py. Django is confused while getting Payment object. Please change class name anything else for proper working.

    Login or Signup to reply.
  2. Your view and model are having same name, that’s the reason of name confliction.

    Change your view to PaymentView (or any different name):

    class PaymentView(LoginRequiredMixin, View):
        # rest of the code
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search