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
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.
Your view and model are having same name, that’s the reason of name confliction.
Change your view to PaymentView (or any different name):