*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+unsubscr...@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.