I have two apps "orders" and "carts". In my models for carts I got:
-- class CartItem(models.Model):
cart = models.ForeignKey("Cart")
item = models.ForeignKey(Variation)
quantity = models.PositiveIntegerField(default=1)
line_item_total = models.DecimalField(max_digits=10, decimal_places=2)
def __unicode__(self):
return self.item.title
def remove(self):
return self.item.remove_from_cart()
def cart_item_pre_save_receiver(sender, instance, *args, **kwargs):
qty = instance.quantity
if qty >= 1:
price = instance.item.get_price()
line_item_total = Decimal(qty) * Decimal(price)
instance.line_item_total = line_item_total
pre_save.connect(cart_item_pre_save_receiver, sender=CartItem)
def cart_item_post_save_receiver(sender, instance, *args, **kwargs):
instance.cart.update_subtotal()
post_save.connect(cart_item_post_save_receiver, sender=CartItem)
post_delete.connect(cart_item_post_save_receiver, sender=CartItem)
class Cart(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True)
items = models.ManyToManyField(Variation, through=CartItem)
timestamp = models.DateTimeField(auto_now_add=True, auto_now=False)
updated = models.DateTimeField(auto_now_add=False, auto_now=True)
subtotal = models.DecimalField(max_digits=50, decimal_places=2, default=25.00)
tax_percentage = models.DecimalField(max_digits=10, decimal_places=5, default=0.085)
tax_total = models.DecimalField(max_digits=50, decimal_places=2, default=25.00)
total = models.DecimalField(max_digits=50, decimal_places=2, default=25.00)
def __unicode__(self):
return str(self.id)
def update_subtotal(self):
print "updating..."
subtotal = 0
items = self.cartitem_set.all()
for item in items:
subtotal += item.line_item_total
self.subtotal = "%.2f" %(subtotal)
self.save()
def do_tax_and_total_receiver(sender, instance, *args, **kwargs):
subtotal = Decimal(instance.subtotal)
tax_total = round(subtotal * Decimal(instance.tax_percentage), 2) #8.5%
print instance.tax_percentage
total = round(subtotal + Decimal(tax_total), 2)
instance.tax_total = "%.2f" %(tax_total)
instance.total = "%.2f" %(total)
pre_save.connect(do_tax_and_total_receiver, sender=Cart)
In my carts Views.py:
from orders.forms import GuestCheckoutForm
from orders.mixins import CartOrderMixin
from orders.models import UserCheckout, Order, UserAddress
from products.models import Variation
from .models import Cart, CartItem
if settings.DEBUG:
braintree.Configuration.configure(braintree.Environment.Sandbox,
merchant_id=settings.BRAINTREE_MERCHANT_ID,
public_key=settings.BRAINTREE_PUBLIC,
private_key=settings.BRAINTREE_PRIVATE)
class ItemCountView(View):
def get(self, request, *args, **kwargs):
if request.is_ajax():
cart_id = self.request.session.get("cart_id")
if cart_id == None:
count = 0
else:
cart = Cart.objects.get(id=cart_id)
count = cart.items.count()
request.session["cart_item_count"] = count
return JsonResponse({"count": count})
else:
raise Http404
class CartView(SingleObjectMixin, View):
model = Cart
template_name = "carts/view.html"
def get_object(self, *args, **kwargs):
self.request.session.set_expiry(0) #5 minutes
cart_id = self.request.session.get("cart_id")
if cart_id == None:
cart = Cart()
cart.tax_percentage = 0.075
cart.save()
cart_id = cart.id
self.request.session["cart_id"] = cart_id
cart = Cart.objects.get(id=cart_id)
if self.request.user.is_authenticated():
cart.user = self.request.user
cart.save()
return cart
def get(self, request, *args, **kwargs):
cart = self.get_object()
item_id = request.GET.get("item")
delete_item = request.GET.get("delete", False)
flash_message = ""
item_added = False
if item_id:
item_instance = get_object_or_404(Variation, id=item_id)
qty = request.GET.get("qty", 1)
try:
if int(qty) < 1:
delete_item = True
except:
raise Http404
cart_item, created = CartItem.objects.get_or_create(cart=cart, item=item_instance)
if created:
flash_message = "Successfully added to the cart"
item_added = True
if delete_item:
flash_message = "Item removed successfully."
cart_item.delete()
else:
if not created:
flash_message = "Quantity has been updated successfully."
cart_item.quantity = qty
cart_item.save()
if not request.is_ajax():
return HttpResponseRedirect(reverse("cart"))
#return cart_item.cart.get_absolute_url()
if request.is_ajax():
try:
total = cart_item.line_item_total
except:
total = None
try:
subtotal = cart_item.cart.subtotal
except:
subtotal = None
try:
cart_total = cart_item.cart.total
except:
cart_total = None
try:
tax_total = cart_item.cart.tax_total
except:
tax_total = None
try:
total_items = cart_item.cart.items.count()
except:
total_items = 0
data = {
"deleted": delete_item,
"item_added": item_added,
"line_total": total,
"subtotal": subtotal,
"cart_total": cart_total,
"tax_total": tax_total,
"flash_message": flash_message,
"total_items": total_items
}
return JsonResponse(data)
context = {
"object": self.get_object()
}
template = self.template_name
return render(request, template, context)
class CheckoutView(CartOrderMixin, FormMixin, DetailView):
model = Cart
template_name = "carts/checkout_view.html"
form_class = GuestCheckoutForm
def get_object(self, *args, **kwargs):
cart = self.get_cart()
if cart == None:
return None
return cart
def get_context_data(self, *args, **kwargs):
context = super(CheckoutView, self).get_context_data(*args, **kwargs)
user_can_continue = False
user_check_id = self.request.session.get("user_checkout_id")
if self.request.user.is_authenticated():
user_can_continue = True
user_checkout, created = UserCheckout.objects.get_or_create(email=self.request.user.email)
user_checkout.user = self.request.user
user_checkout.save()
context["client_token"] = user_checkout.get_client_token()
self.request.session["user_checkout_id"] = user_checkout.id
elif not self.request.user.is_authenticated() and user_check_id == None:
context["login_form"] = AuthenticationForm()
context["next_url"] = self.request.build_absolute_uri()
else:
pass
if user_check_id != None:
user_can_continue = True
if not self.request.user.is_authenticated(): #GUEST USER
user_checkout_2 = UserCheckout.objects.get(id=user_check_id)
context["client_token"] = user_checkout_2.get_client_token()
#if self.get_cart() is not None:
context["order"] = self.get_order()
context["user_can_continue"] = user_can_continue
context["form"] = self.get_form()
return context
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form = self.get_form()
if form.is_valid():
email = form.cleaned_data.get("email")
user_checkout, created = UserCheckout.objects.get_or_create(email=email)
request.session["user_checkout_id"] = user_checkout.id
return self.form_valid(form)
else:
return self.form_invalid(form)
def get_success_url(self):
return reverse("checkout")
def get(self, request, *args, **kwargs):
get_data = super(CheckoutView, self).get(request, *args, **kwargs)
cart = self.get_object()
if cart == None:
return redirect("cart")
new_order = self.get_order()
user_checkout_id = request.session.get("user_checkout_id")
if user_checkout_id != None:
user_checkout = UserCheckout.objects.get(id=user_checkout_id)
if new_order.billing_address == None or new_order.shipping_address == None:
return redirect("order_address")
new_order.user = user_checkout
new_order.save()
return get_data
class CheckoutFinalView(CartOrderMixin, View):
def post(self, request, *args, **kwargs):
order = self.get_order()
order_total = order.order_total
nonce = request.POST.get("payment_method_nonce")
if nonce:
result = braintree.Transaction.sale({
"amount": order_total,
"payment_method_nonce": nonce,
"billing": {
"postal_code": "%s" %(order.billing_address.zipcode),
},
"options": {
"submit_for_settlement": True
}
})
if result.is_success:
#result.transaction.id to order
order.mark_completed(order_id=result.transaction.id)
messages.success(request, "Thank you for your order.")
del request.session["cart_id"]
del request.session["order_id"]
else:
#messages.success(request, "There was a problem with your order.")
messages.success(request, "%s" %(result.message))
return redirect("checkout")
return redirect("order_detail", pk=order.pk)
def get(self, request, *args, **kwargs):
return redirect("checkout")
My orders app models.py:
import braintree
if settings.DEBUG:
braintree.Configuration.configure(braintree.Environment.Sandbox,
merchant_id=settings.BRAINTREE_MERCHANT_ID,
public_key=settings.BRAINTREE_PUBLIC,
private_key=settings.BRAINTREE_PRIVATE)
class UserCheckout(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, null=True, blank=True) #not required
email = models.EmailField(unique=True) #--> required
braintree_id = models.CharField(max_length=120, null=True, blank=True)
def __unicode__(self): #def __str__(self):
return self.email
@property
def get_braintree_id(self,):
instance = self
if not instance.braintree_id:
result = braintree.Customer.create({
"email": instance.email,
})
if result.is_success:
instance.braintree_id = result.customer.id
instance.save()
return instance.braintree_id
def get_client_token(self):
customer_id = self.get_braintree_id
if customer_id:
client_token = braintree.ClientToken.generate({
"customer_id": customer_id
})
return client_token
return None
def update_braintree_id(sender, instance, *args, **kwargs):
if not instance.braintree_id:
instance.get_braintree_id
post_save.connect(update_braintree_id, sender=UserCheckout)
ADDRESS_TYPE = (
('billing', 'Billing'),
('shipping', 'Shipping'),
)
class UserAddress(models.Model):
user = models.ForeignKey(UserCheckout)
type = models.CharField(max_length=120, choices=ADDRESS_TYPE)
street = models.CharField(max_length=120)
city = models.CharField(max_length=120)
state = models.CharField(max_length=120)
zipcode = models.CharField(max_length=120)
def __unicode__(self):
return self.street
def get_address(self):
return "%s, %s, %s %s" %(self.street, self.city, self.state, self.zipcode)
ORDER_STATUS_CHOICES = (
('created', 'Created'),
('paid', 'Paid'),
('shipped', 'Shipped'),
('refunded', 'Refunded'),
)
class Order(models.Model):
status = models.CharField(max_length=120, choices=ORDER_STATUS_CHOICES, default='created')
cart = models.ForeignKey(Cart)
user = models.ForeignKey(UserCheckout, null=True)
billing_address = models.ForeignKey(UserAddress, related_name='billing_address', null=True)
shipping_address = models.ForeignKey(UserAddress, related_name='shipping_address', null=True)
shipping_total_price = models.DecimalField(max_digits=50, decimal_places=2, default=5.99)
order_total = models.DecimalField(max_digits=50, decimal_places=2, )
order_id = models.CharField(max_length=20, null=True, blank=True)
def __unicode__(self):
return str(self.cart.id)
class Meta:
ordering = ['-id']
def get_absolute_url(self):
return reverse("order_detail", kwargs={"pk": self.pk})
def mark_completed(self, order_id=None):
self.status = "paid"
if order_id and not self.order_id:
self.order_id = order_id
self.save()
def order_pre_save(sender, instance, *args, **kwargs):
shipping_total_price = instance.shipping_total_price
cart_total = instance.cart.total
order_total = Decimal(shipping_total_price) + Decimal(cart_total)
instance.order_total = order_total
pre_save.connect(order_pre_save, sender=Order)
My orders views.py:
class OrderDetail(DetailView):
model = Order
def dispatch(self, request, *args, **kwargs):
try:
user_check_id = self.request.session.get("user_checkout_id")
user_checkout = UserCheckout.objects.get(id=user_check_id)
except UserCheckout.DoesNotExist:
user_checkout = UserCheckout.objects.get(user=request.user)
except:
user_checkout = None
obj = self.get_object()
if obj.user == user_checkout and user_checkout is not None:
return super(OrderDetail, self).dispatch(request, *args, **kwargs)
else:
raise Http404
class OrderList(ListView):
queryset = Order.objects.all()
def get_queryset(self):
user_check_id = self.request.user.id
user_checkout = UserCheckout.objects.get(id=user_check_id)
return super(OrderList, self).get_queryset().filter(user=user_checkout)
class UserAddressCreateView(CreateView):
form_class = UserAddressForm
template_name = "forms.html"
success_url = "/checkout/address/"
def get_checkout_user(self):
user_check_id = self.request.session.get("user_checkout_id")
user_checkout = UserCheckout.objects.get(id=user_check_id)
return user_checkout
def form_valid(self, form, *args, **kwargs):
form.instance.user = self.get_checkout_user()
return super(UserAddressCreateView, self).form_valid(form, *args, **kwargs)
class AddressSelectFormView(CartOrderMixin, FormView):
form_class = AddressForm
template_name = "orders/address_select.html"
def dispatch(self, *args, **kwargs):
b_address, s_address = self.get_addresses()
if b_address.count() == 0:
messages.success(self.request, "Please add a billing address before continuing")
return redirect("user_address_create")
elif s_address.count() == 0:
messages.success(self.request, "Please add a shipping address before continuing")
return redirect("user_address_create")
else:
return super(AddressSelectFormView, self).dispatch(*args, **kwargs)
def get_addresses(self, *args, **kwargs):
user_check_id = self.request.session.get("user_checkout_id")
user_checkout = UserCheckout.objects.get(id=user_check_id)
b_address = UserAddress.objects.filter(
user=user_checkout,
type='billing',
)
s_address = UserAddress.objects.filter(
user=user_checkout,
type='shipping',
)
return b_address, s_address
def get_form(self, *args, **kwargs):
form = super(AddressSelectFormView, self).get_form(*args, **kwargs)
b_address, s_address = self.get_addresses()
form.fields["billing_address"].queryset = b_address
form.fields["shipping_address"].queryset = s_address
return form
def form_valid(self, form, *args, **kwargs):
billing_address = form.cleaned_data["billing_address"]
shipping_address = form.cleaned_data["shipping_address"]
order = self.get_order()
order.billing_address = billing_address
order.shipping_address = shipping_address
order.save()
return super(AddressSelectFormView, self).form_valid(form, *args, **kwargs)
def get_success_url(self, *args, **kwargs):
return "/checkout/"
Error I get when checking out is:
Environment:
Request Method: GET
Request URL: http://localhost:8000/checkout/
Django Version: 1.8.5
Python Version: 2.7.9
Installed Applications:
('django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
'blog',
'products',
'orders',
'carts',
'newsletter',
'crispy_forms',
'registration',
'colorfield',
'hitcount')
Installed Middleware:
('django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware')
Traceback:
File "C:\Users\Mudassar\dressikarepo\lib\site-packages\django\core\handlers\base.py" in get_response
132. response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\Mudassar\dressikarepo\lib\site-packages\django\views\generic\base.py" in view
71. return self.dispatch(request, *args, **kwargs)
File "C:\Users\Mudassar\dressikarepo\lib\site-packages\django\views\generic\base.py" in dispatch
89. return handler(request, *args, **kwargs)
File "C:\Users\Mudassar\dressikarepo\src\carts\views.py" in get
188. get_data = super(CheckoutView, self).get(request, *args, **kwargs)
File "C:\Users\Mudassar\dressikarepo\lib\site-packages\django\views\generic\detail.py" in get
116. context = self.get_context_data(object=self.object)
File "C:\Users\Mudassar\dressikarepo\src\carts\views.py" in get_context_data
167. context["order"] = self.get_order()
File "C:\Users\Mudassar\dressikarepo\src\orders\mixins.py" in get_order
22. new_order = Order.objects.create(cart=cart)
File "C:\Users\Mudassar\dressikarepo\lib\site-packages\django\db\models\manager.py" in manager_method
127. return getattr(self.get_queryset(), name)(*args, **kwargs)
File "C:\Users\Mudassar\dressikarepo\lib\site-packages\django\db\models\query.py" in create
348. obj.save(force_insert=True, using=self.db)
File "C:\Users\Mudassar\dressikarepo\lib\site-packages\django\db\models\base.py" in save
734. force_update=force_update, update_fields=update_fields)
File "C:\Users\Mudassar\dressikarepo\lib\site-packages\django\db\models\base.py" in save_base
762. updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
File "C:\Users\Mudassar\dressikarepo\lib\site-packages\django\db\models\base.py" in _save_table
846. result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
File "C:\Users\Mudassar\dressikarepo\lib\site-packages\django\db\models\base.py" in _do_insert
885. using=using, raw=raw)
File "C:\Users\Mudassar\dressikarepo\lib\site-packages\django\db\models\manager.py" in manager_method
127. return getattr(self.get_queryset(), name)(*args, **kwargs)
File "C:\Users\Mudassar\dressikarepo\lib\site-packages\django\db\models\query.py" in _insert
920. return query.get_compiler(using=using).execute_sql(return_id)
File "C:\Users\Mudassar\dressikarepo\lib\site-packages\django\db\models\sql\compiler.py" in execute_sql
974. cursor.execute(sql, params)
File "C:\Users\Mudassar\dressikarepo\lib\site-packages\django\db\backends\utils.py" in execute
79. return super(CursorDebugWrapper, self).execute(sql, params)
File "C:\Users\Mudassar\dressikarepo\lib\site-packages\django\db\backends\utils.py" in execute
64. return self.cursor.execute(sql, params)
File "C:\Users\Mudassar\dressikarepo\lib\site-packages\django\db\utils.py" in __exit__
97. six.reraise(dj_exc_type, dj_exc_value, traceback)
File "C:\Users\Mudassar\dressikarepo\lib\site-packages\django\db\backends\utils.py" in execute
64. return self.cursor.execute(sql, params)
File "C:\Users\Mudassar\dressikarepo\lib\site-packages\django\db\backends\sqlite3\base.py" in execute
318. return Database.Cursor.execute(self, query, params)
Exception Type: OperationalError at /checkout/
Exception Value: table orders_order has no column named order_id
...........
My migrations table for orders shows:
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('carts', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='Order',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('status', models.CharField(default=b'created', max_length=120, choices=[(b'created', b'Created'), (b'paid', b'Paid'), (b'shipped', b'Shipped'), (b'refunded', b'Refunded')])),
('shipping_total_price', models.DecimalField(default=5.99, max_digits=50, decimal_places=2)),
('order_total', models.DecimalField(max_digits=50, decimal_places=2)),
('order_id', models.CharField(max_length=20, null=True, blank=True)),
],
options={
'ordering': ['-id'],
},
),
migrations.CreateModel(
name='UserAddress',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('type', models.CharField(max_length=120, choices=[(b'billing', b'Billing'), (b'shipping', b'Shipping')])),
('street', models.CharField(max_length=120)),
('city', models.CharField(max_length=120)),
('state', models.CharField(max_length=120)),
('zipcode', models.CharField(max_length=120)),
],
),
migrations.CreateModel(
name='UserCheckout',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('email', models.EmailField(unique=True, max_length=254)),
('braintree_id', models.CharField(max_length=120, null=True, blank=True)),
('user', models.OneToOneField(null=True, blank=True, to=settings.AUTH_USER_MODEL)),
],
),
migrations.AddField(
model_name='useraddress',
name='user',
field=models.ForeignKey(to='orders.UserCheckout'),
),
migrations.AddField(
model_name='order',
name='billing_address',
field=models.ForeignKey(related_name='billing_address', to='orders.UserAddress', null=True),
),
migrations.AddField(
model_name='order',
name='cart',
field=models.ForeignKey(to='carts.Cart'),
),
migrations.AddField(
model_name='order',
name='shipping_address',
field=models.ForeignKey(related_name='shipping_address', to='orders.UserAddress', null=True),
),
migrations.AddField(
model_name='order',
name='user',
field=models.ForeignKey(to='orders.UserCheckout', null=True),
),
]
It creates a cart but isn't processing orders due to the error above. Please advise
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscribe@googlegroups.com.
To post to this group, send email to django-users@googlegroups.com.
Visit this group at https://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/CANoUts4sptWyG7ayJgOZWe7S66L2_GuribOVj_TRii8VoKHokg%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.
No comments:
Post a Comment