From b888094d61fde426e047f4c101405dcfe07c7460 Mon Sep 17 00:00:00 2001 From: Dmitry Falk Date: Mon, 3 Sep 2012 02:33:32 +0400 Subject: [PATCH 1/9] store wishlist in database --- cartridge/shop/middleware.py | 12 +- ..._wishlist__add_unique_wishlist_user_sku.py | 298 ++++++++++++++++++ cartridge/shop/models.py | 36 ++- .../templates/email/wishlist_notification.txt | 11 + cartridge/shop/templates/shop/wishlist.html | 2 +- cartridge/shop/views.py | 33 +- 6 files changed, 378 insertions(+), 14 deletions(-) create mode 100644 cartridge/shop/migrations/0017_auto__add_wishlist__add_unique_wishlist_user_sku.py create mode 100644 cartridge/shop/templates/email/wishlist_notification.txt diff --git a/cartridge/shop/middleware.py b/cartridge/shop/middleware.py index 4e595bd9a..fed530465 100644 --- a/cartridge/shop/middleware.py +++ b/cartridge/shop/middleware.py @@ -1,7 +1,7 @@ from mezzanine.conf import settings -from cartridge.shop.models import Cart +from cartridge.shop.models import Cart, Wishlist class SSLRedirect(object): @@ -29,7 +29,13 @@ class ShopMiddleware(SSLRedirect): """ def process_request(self, request): request.cart = Cart.objects.from_request(request) - wishlist = request.COOKIES.get("wishlist", "").split(",") - if not wishlist[0]: + if not request.user.is_authenticated(): + wishlist = request.COOKIES.get("wishlist", "").split(",") + if not wishlist[0]: + wishlist = [] + else: + wishlist_items = Wishlist.objects.filter(user=request.user) wishlist = [] + for item in wishlist_items: + wishlist.append(item.sku) request.wishlist = wishlist diff --git a/cartridge/shop/migrations/0017_auto__add_wishlist__add_unique_wishlist_user_sku.py b/cartridge/shop/migrations/0017_auto__add_wishlist__add_unique_wishlist_user_sku.py new file mode 100644 index 000000000..12576525c --- /dev/null +++ b/cartridge/shop/migrations/0017_auto__add_wishlist__add_unique_wishlist_user_sku.py @@ -0,0 +1,298 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'Wishlist' + db.create_table('shop_wishlist', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])), + ('sku', self.gf('cartridge.shop.fields.SKUField')(max_length=20)), + )) + db.send_create_signal('shop', ['Wishlist']) + + # Adding unique constraint on 'Wishlist', fields ['user', 'sku'] + db.create_unique('shop_wishlist', ['user_id', 'sku']) + + + def backwards(self, orm): + # Removing unique constraint on 'Wishlist', fields ['user', 'sku'] + db.delete_unique('shop_wishlist', ['user_id', 'sku']) + + # Deleting model 'Wishlist' + db.delete_table('shop_wishlist') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'generic.assignedkeyword': { + 'Meta': {'ordering': "('_order',)", 'object_name': 'AssignedKeyword'}, + '_order': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'keyword': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'assignments'", 'to': "orm['generic.Keyword']"}), + 'object_pk': ('django.db.models.fields.IntegerField', [], {}) + }, + 'generic.keyword': { + 'Meta': {'object_name': 'Keyword'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '2000', 'null': 'True', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '500'}) + }, + 'generic.rating': { + 'Meta': {'object_name': 'Rating'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_pk': ('django.db.models.fields.IntegerField', [], {}), + 'value': ('django.db.models.fields.IntegerField', [], {}) + }, + 'pages.page': { + 'Meta': {'ordering': "('titles',)", 'object_name': 'Page'}, + '_meta_title': ('django.db.models.fields.CharField', [], {'max_length': '500', 'null': 'True', 'blank': 'True'}), + '_order': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'content_model': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'expiry_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'gen_description': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'in_menus': ('mezzanine.pages.fields.MenusField', [], {'default': '[1, 2, 3]', 'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'keywords': ('mezzanine.generic.fields.KeywordsField', [], {'object_id_field': "'object_pk'", 'to': "orm['generic.AssignedKeyword']", 'frozen_by_south': 'True'}), + 'keywords_string': ('django.db.models.fields.CharField', [], {'max_length': '500', 'blank': 'True'}), + 'login_required': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['pages.Page']"}), + 'publish_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'short_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '2000', 'null': 'True', 'blank': 'True'}), + 'status': ('django.db.models.fields.IntegerField', [], {'default': '2'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '500'}), + 'titles': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True'}) + }, + 'shop.cart': { + 'Meta': {'object_name': 'Cart'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_updated': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}) + }, + 'shop.cartitem': { + 'Meta': {'object_name': 'CartItem'}, + 'cart': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'items'", 'to': "orm['shop.Cart']"}), + 'description': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}), + 'quantity': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'sku': ('cartridge.shop.fields.SKUField', [], {'max_length': '20'}), + 'total_price': ('cartridge.shop.fields.MoneyField', [], {'default': "'0'", 'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'unit_price': ('cartridge.shop.fields.MoneyField', [], {'default': "'0'", 'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'url': ('django.db.models.fields.CharField', [], {'max_length': '200'}) + }, + 'shop.category': { + 'Meta': {'ordering': "('_order',)", 'object_name': 'Category', '_ormbases': ['pages.Page']}, + 'combined': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'content': ('mezzanine.core.fields.RichTextField', [], {}), + 'options': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'product_options'", 'blank': 'True', 'to': "orm['shop.ProductOption']"}), + 'page_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['pages.Page']", 'unique': 'True', 'primary_key': 'True'}), + 'price_max': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'price_min': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'products': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['shop.Product']", 'symmetrical': 'False', 'blank': 'True'}), + 'sale': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['shop.Sale']", 'null': 'True', 'blank': 'True'}) + }, + 'shop.discountcode': { + 'Meta': {'object_name': 'DiscountCode'}, + 'active': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'categories': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'discountcode_related'", 'blank': 'True', 'to': "orm['shop.Category']"}), + 'code': ('cartridge.shop.fields.DiscountCodeField', [], {'unique': 'True', 'max_length': '20'}), + 'discount_deduct': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'discount_exact': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'discount_percent': ('cartridge.shop.fields.PercentageField', [], {'null': 'True', 'max_digits': '5', 'decimal_places': '2', 'blank': 'True'}), + 'free_shipping': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'min_purchase': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'products': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['shop.Product']", 'symmetrical': 'False', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'uses_remaining': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'valid_from': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'valid_to': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}) + }, + 'shop.order': { + 'Meta': {'ordering': "('-id',)", 'object_name': 'Order'}, + 'additional_instructions': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'billing_detail_city': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'billing_detail_country': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'billing_detail_email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}), + 'billing_detail_first_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'billing_detail_last_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'billing_detail_phone': ('django.db.models.fields.CharField', [], {'max_length': '20'}), + 'billing_detail_postcode': ('django.db.models.fields.CharField', [], {'max_length': '10'}), + 'billing_detail_state': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'billing_detail_street': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'discount_code': ('cartridge.shop.fields.DiscountCodeField', [], {'max_length': '20', 'blank': 'True'}), + 'discount_total': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'item_total': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'key': ('django.db.models.fields.CharField', [], {'max_length': '40'}), + 'shipping_detail_city': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'shipping_detail_country': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'shipping_detail_first_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'shipping_detail_last_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'shipping_detail_phone': ('django.db.models.fields.CharField', [], {'max_length': '20'}), + 'shipping_detail_postcode': ('django.db.models.fields.CharField', [], {'max_length': '10'}), + 'shipping_detail_state': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'shipping_detail_street': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'shipping_total': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'shipping_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), + 'status': ('django.db.models.fields.IntegerField', [], {'default': '1'}), + 'time': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}), + 'total': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'transaction_id': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'user_id': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) + }, + 'shop.orderitem': { + 'Meta': {'object_name': 'OrderItem'}, + 'description': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'order': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'items'", 'to': "orm['shop.Order']"}), + 'quantity': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'sku': ('cartridge.shop.fields.SKUField', [], {'max_length': '20'}), + 'total_price': ('cartridge.shop.fields.MoneyField', [], {'default': "'0'", 'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'unit_price': ('cartridge.shop.fields.MoneyField', [], {'default': "'0'", 'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}) + }, + 'shop.product': { + 'Meta': {'object_name': 'Product'}, + '_meta_title': ('django.db.models.fields.CharField', [], {'max_length': '500', 'null': 'True', 'blank': 'True'}), + 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'categories': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['shop.Category']", 'symmetrical': 'False', 'blank': 'True'}), + 'content': ('mezzanine.core.fields.RichTextField', [], {}), + 'date_added': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'expiry_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'gen_description': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'keywords': ('mezzanine.generic.fields.KeywordsField', [], {'object_id_field': "'object_pk'", 'to': "orm['generic.AssignedKeyword']", 'frozen_by_south': 'True'}), + 'keywords_string': ('django.db.models.fields.CharField', [], {'max_length': '500', 'blank': 'True'}), + 'num_in_stock': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'publish_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'rating': ('mezzanine.generic.fields.RatingField', [], {'object_id_field': "'object_pk'", 'to': "orm['generic.Rating']", 'frozen_by_south': 'True'}), + 'rating_average': ('django.db.models.fields.FloatField', [], {'default': '0'}), + 'rating_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'related_products': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'related_products_rel_+'", 'blank': 'True', 'to': "orm['shop.Product']"}), + 'sale_from': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'sale_id': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'sale_price': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'sale_to': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'short_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"}), + 'sku': ('cartridge.shop.fields.SKUField', [], {'max_length': '20', 'unique': 'True', 'null': 'True', 'blank': 'True'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '2000', 'null': 'True', 'blank': 'True'}), + 'status': ('django.db.models.fields.IntegerField', [], {'default': '2'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '500'}), + 'unit_price': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'upsell_products': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'upsell_products_rel_+'", 'blank': 'True', 'to': "orm['shop.Product']"}) + }, + 'shop.productaction': { + 'Meta': {'unique_together': "(('product', 'timestamp'),)", 'object_name': 'ProductAction'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'product': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['shop.Product']"}), + 'timestamp': ('django.db.models.fields.IntegerField', [], {}), + 'total_cart': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'total_purchase': ('django.db.models.fields.IntegerField', [], {'default': '0'}) + }, + 'shop.productimage': { + 'Meta': {'ordering': "('_order',)", 'object_name': 'ProductImage'}, + '_order': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'description': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), + 'file': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'product': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'images'", 'to': "orm['shop.Product']"}) + }, + 'shop.productoption': { + 'Meta': {'object_name': 'ProductOption'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('cartridge.shop.fields.OptionField', [], {'max_length': '50', 'null': 'True'}), + 'type': ('django.db.models.fields.IntegerField', [], {}) + }, + 'shop.productvariation': { + 'Meta': {'ordering': "('-default',)", 'object_name': 'ProductVariation'}, + 'default': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['shop.ProductImage']", 'null': 'True', 'blank': 'True'}), + 'num_in_stock': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'option1': ('cartridge.shop.fields.OptionField', [], {'max_length': '50', 'null': 'True'}), + 'option2': ('cartridge.shop.fields.OptionField', [], {'max_length': '50', 'null': 'True'}), + 'product': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'variations'", 'to': "orm['shop.Product']"}), + 'sale_from': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'sale_id': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'sale_price': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'sale_to': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'sku': ('cartridge.shop.fields.SKUField', [], {'max_length': '20', 'unique': 'True', 'null': 'True', 'blank': 'True'}), + 'unit_price': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}) + }, + 'shop.sale': { + 'Meta': {'object_name': 'Sale'}, + 'active': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'categories': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'sale_related'", 'blank': 'True', 'to': "orm['shop.Category']"}), + 'discount_deduct': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'discount_exact': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'discount_percent': ('cartridge.shop.fields.PercentageField', [], {'null': 'True', 'max_digits': '5', 'decimal_places': '2', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'products': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['shop.Product']", 'symmetrical': 'False', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'valid_from': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'valid_to': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}) + }, + 'shop.wishlist': { + 'Meta': {'unique_together': "(('user', 'sku'),)", 'object_name': 'Wishlist'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'sku': ('cartridge.shop.fields.SKUField', [], {'max_length': '20'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) + }, + 'sites.site': { + 'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"}, + 'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + } + } + + complete_apps = ['shop'] \ No newline at end of file diff --git a/cartridge/shop/models.py b/cartridge/shop/models.py index e9e877821..42a54d927 100644 --- a/cartridge/shop/models.py +++ b/cartridge/shop/models.py @@ -1,9 +1,10 @@ from decimal import Decimal from operator import iand, ior +from django.contrib.auth.models import User from django.core.urlresolvers import reverse from django.db import models -from django.db.models.signals import m2m_changed +from django.db.models.signals import m2m_changed, pre_save from django.db.models import CharField, F, Q from django.db.models.base import ModelBase from django.db.utils import DatabaseError @@ -18,6 +19,7 @@ from mezzanine.generic.fields import RatingField from mezzanine.pages.models import Page from mezzanine.utils.models import AdminThumbMixin, upload_to +from mezzanine.utils.email import send_mail_template from cartridge.shop import fields, managers @@ -305,6 +307,27 @@ def update_stock(self, quantity): self.product.save() +@receiver(pre_save, sender=ProductVariation) +def wishlist_notifications_on_save(sender, instance, **kwargs): + if instance.id: + productvariation = ProductVariation.objects.get(pk=instance.id) + old_stock = productvariation.num_in_stock + if (old_stock == 0) and (instance.num_in_stock > old_stock): + # Send email + email_from = settings.DEFAULT_FROM_EMAIL + wishlist = Wishlist.objects.filter(sku = productvariation.sku) + for item in wishlist: + email_to = item.user.email + subject = _("Notification from wishlist") + context = { + "productvariation": productvariation, + "user": item.user, + } + send_mail_template(subject, "email/wishlist_notification", + email_from, email_to, context, + fail_silently=settings.DEBUG) + + class Category(Page, RichText): """ A category of products on the website. @@ -843,3 +866,14 @@ def calculate(self, amount): class Meta: verbose_name = _("Discount code") verbose_name_plural = _("Discount codes") + + +class Wishlist(models.Model): + + user = models.ForeignKey(User) + sku = fields.SKUField() + + class Meta: + unique_together = ('user','sku',) + verbose_name = _("Wishlist item") + verbose_name_plural = _("Wishlist items") diff --git a/cartridge/shop/templates/email/wishlist_notification.txt b/cartridge/shop/templates/email/wishlist_notification.txt new file mode 100644 index 000000000..8e7868d5d --- /dev/null +++ b/cartridge/shop/templates/email/wishlist_notification.txt @@ -0,0 +1,11 @@ +{% extends "email/base.txt" %} +{% load shop_tags i18n %} + +{% block main %} +{% trans "Dear" %} {{ user }}, + +{% trans "This product is available for order" %}: + +{{ productvariation }} + +{% endblock %} diff --git a/cartridge/shop/templates/shop/wishlist.html b/cartridge/shop/templates/shop/wishlist.html index 3c4dc97f5..6ce72816b 100644 --- a/cartridge/shop/templates/shop/wishlist.html +++ b/cartridge/shop/templates/shop/wishlist.html @@ -11,7 +11,7 @@ {% block main %} {% if error %}{{ error }}{% endif %} -{% if request.wishlist %} +{% if wishlist_items %} {% for item in wishlist_items %} diff --git a/cartridge/shop/views.py b/cartridge/shop/views.py index 7926893fb..82a193579 100644 --- a/cartridge/shop/views.py +++ b/cartridge/shop/views.py @@ -3,6 +3,7 @@ from django.contrib.auth.decorators import login_required from django.contrib.messages import info from django.core.urlresolvers import get_callable, reverse +from django.db import IntegrityError from django.http import Http404, HttpResponse from django.shortcuts import get_object_or_404, redirect from django.template import RequestContext @@ -19,7 +20,7 @@ from cartridge.shop import checkout from cartridge.shop.forms import AddProductForm, DiscountForm, CartItemFormSet from cartridge.shop.models import Product, ProductVariation, Order, OrderItem -from cartridge.shop.models import DiscountCode +from cartridge.shop.models import DiscountCode, Wishlist from cartridge.shop.utils import recalculate_discount, sign @@ -60,13 +61,22 @@ def product(request, slug, template="shop/product.html"): info(request, _("Item added to cart")) return redirect("shop_cart") else: - skus = request.wishlist - sku = add_product_form.variation.sku - if sku not in skus: - skus.append(sku) - info(request, _("Item added to wishlist")) response = redirect("shop_wishlist") - set_cookie(response, "wishlist", ",".join(skus)) + if not request.user.is_authenticated(): + skus = request.wishlist + sku = add_product_form.variation.sku + if sku not in skus: + skus.append(sku) + set_cookie(response, "wishlist", ",".join(skus)) + else: + wishlist = Wishlist() + wishlist.user = request.user + wishlist.sku = add_product_form.variation.sku + try: + wishlist.save() + except IntegrityError: + pass + info(request, _("Item added to wishlist")) return response context = { "product": product, @@ -111,11 +121,16 @@ def wishlist(request, template="shop/wishlist.html"): url = "shop_wishlist" sku = request.POST.get("sku") if sku in skus: - skus.remove(sku) + if not request.user.is_authenticated(): + skus.remove(sku) + else: + wishlist_item = Wishlist.objects.get(user=request.user, sku=sku) + wishlist_item.delete() if not error: info(request, message) response = redirect(url) - set_cookie(response, "wishlist", ",".join(skus)) + if not request.user.is_authenticated(): + set_cookie(response, "wishlist", ",".join(skus)) return response # Remove skus from the cookie that no longer exist. From 9d389e09cb50b8fdad5ddac8c75d5fa675b2f66c Mon Sep 17 00:00:00 2001 From: Dmitry Falk Date: Mon, 3 Sep 2012 10:36:32 +0400 Subject: [PATCH 2/9] pep8 fixes --- cartridge/shop/models.py | 4 ++-- cartridge/shop/views.py | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/cartridge/shop/models.py b/cartridge/shop/models.py index 42a54d927..eab0ba5ba 100644 --- a/cartridge/shop/models.py +++ b/cartridge/shop/models.py @@ -315,7 +315,7 @@ def wishlist_notifications_on_save(sender, instance, **kwargs): if (old_stock == 0) and (instance.num_in_stock > old_stock): # Send email email_from = settings.DEFAULT_FROM_EMAIL - wishlist = Wishlist.objects.filter(sku = productvariation.sku) + wishlist = Wishlist.objects.filter(sku=productvariation.sku) for item in wishlist: email_to = item.user.email subject = _("Notification from wishlist") @@ -874,6 +874,6 @@ class Wishlist(models.Model): sku = fields.SKUField() class Meta: - unique_together = ('user','sku',) + unique_together = ('user', 'sku') verbose_name = _("Wishlist item") verbose_name_plural = _("Wishlist items") diff --git a/cartridge/shop/views.py b/cartridge/shop/views.py index 82a193579..174ab5bfa 100644 --- a/cartridge/shop/views.py +++ b/cartridge/shop/views.py @@ -124,7 +124,8 @@ def wishlist(request, template="shop/wishlist.html"): if not request.user.is_authenticated(): skus.remove(sku) else: - wishlist_item = Wishlist.objects.get(user=request.user, sku=sku) + wishlist_item = Wishlist.objects.get(user=request.user, + sku=sku) wishlist_item.delete() if not error: info(request, message) From 1f927d8d442c46327bc1d910873ac5d2aff491f2 Mon Sep 17 00:00:00 2001 From: Tzu-ping Chung Date: Sat, 27 Apr 2013 21:20:23 +0800 Subject: [PATCH 3/9] Extract middleware wishlist loading into WishlistManager and improve notification sending --- cartridge/shop/defaults.py | 12 ++++++++++++ cartridge/shop/managers.py | 21 +++++++++++++++++++++ cartridge/shop/middleware.py | 11 +---------- cartridge/shop/models.py | 7 ++++++- 4 files changed, 40 insertions(+), 11 deletions(-) diff --git a/cartridge/shop/defaults.py b/cartridge/shop/defaults.py index 31e20ef2c..43661c63e 100644 --- a/cartridge/shop/defaults.py +++ b/cartridge/shop/defaults.py @@ -293,3 +293,15 @@ editable=False, default=True, ) + +register_setting( + name="SHOP_WISHLIST_NOTIFICATIONS", + label=_( + "Sends email notifications if an item in user's wishlist is in stock" + ), + description=_( + "Sends email notifications if an item in user's wishlist is in stock" + ), + editable=True, + default=True, +) diff --git a/cartridge/shop/managers.py b/cartridge/shop/managers.py index 0433aca98..197ca71f8 100644 --- a/cartridge/shop/managers.py +++ b/cartridge/shop/managers.py @@ -202,3 +202,24 @@ def get_valid(self, code, cart): if products.filter(variations__sku__in=cart.skus()).count() == 0: raise self.model.DoesNotExist return discount + + +class WishlistManager(Manager): + + def from_request(self, request): + """ + Gets current user's wishlist. Authenticated users' wishlists are stored + in the database, while unauthenticated users' are stored in a cookie. + Note that this method returns a `list` of SKUs in both cases, not a + `QuerySet` of `ProductVariation` objects. + """ + if request.user.is_authenticated(): + wishlist = [] + skus = self.filter(user=request.user).values_list("sku", flat=True) + for sku in skus: + wishlist.append(sku) + else: + wishlist = request.COOKIES.get("wishlist", "").split(",") + if not wishlist[0]: + wishlist = [] + return wishlist diff --git a/cartridge/shop/middleware.py b/cartridge/shop/middleware.py index fed530465..85567906e 100644 --- a/cartridge/shop/middleware.py +++ b/cartridge/shop/middleware.py @@ -29,13 +29,4 @@ class ShopMiddleware(SSLRedirect): """ def process_request(self, request): request.cart = Cart.objects.from_request(request) - if not request.user.is_authenticated(): - wishlist = request.COOKIES.get("wishlist", "").split(",") - if not wishlist[0]: - wishlist = [] - else: - wishlist_items = Wishlist.objects.filter(user=request.user) - wishlist = [] - for item in wishlist_items: - wishlist.append(item.sku) - request.wishlist = wishlist + request.wishlist = Wishlist.objects.from_request(request) diff --git a/cartridge/shop/models.py b/cartridge/shop/models.py index eab0ba5ba..1e3661eb3 100644 --- a/cartridge/shop/models.py +++ b/cartridge/shop/models.py @@ -307,8 +307,11 @@ def update_stock(self, quantity): self.product.save() -@receiver(pre_save, sender=ProductVariation) +@receiver(pre_save, sender=ProductVariation, + dispatch_uid="wishlist_notifications_on_save") def wishlist_notifications_on_save(sender, instance, **kwargs): + if settings.SHOP_WISHLIST_NOTIFICATIONS is not True: + return if instance.id: productvariation = ProductVariation.objects.get(pk=instance.id) old_stock = productvariation.num_in_stock @@ -873,6 +876,8 @@ class Wishlist(models.Model): user = models.ForeignKey(User) sku = fields.SKUField() + objects = managers.WishlistManager() + class Meta: unique_together = ('user', 'sku') verbose_name = _("Wishlist item") From 7b4e30ec5eeabd330ba2cde9baec0e95cf585cae Mon Sep 17 00:00:00 2001 From: Tzu-ping Chung Date: Sat, 27 Apr 2013 22:28:29 +0800 Subject: [PATCH 4/9] Extract wishlist adding and removing --- cartridge/shop/managers.py | 12 ++++++++++++ cartridge/shop/utils.py | 24 +++++++++++++++++++++++ cartridge/shop/views.py | 40 +++++++++++++++----------------------- 3 files changed, 52 insertions(+), 24 deletions(-) diff --git a/cartridge/shop/managers.py b/cartridge/shop/managers.py index 197ca71f8..38d074066 100644 --- a/cartridge/shop/managers.py +++ b/cartridge/shop/managers.py @@ -223,3 +223,15 @@ def from_request(self, request): if not wishlist[0]: wishlist = [] return wishlist + + def delete_for_request(self, sku_to_delete, request): + """ + Delete item from user's wishlist. Authenticated users' wishlists are + stored in the database, while unauthenticated users' are stored in a + cookie. In the latter case, the SKU is removed directly from + `request.wishlist`, which is provided by `ShopMiddleware`. + """ + if request.user.is_authenticated(): + self.get(user=request.user, sku=sku_to_delete).delete() + else: + request.wishlist.remove(sku_to_delete) diff --git a/cartridge/shop/utils.py b/cartridge/shop/utils.py index 2c73ae3b4..575e74333 100644 --- a/cartridge/shop/utils.py +++ b/cartridge/shop/utils.py @@ -11,6 +11,8 @@ from mezzanine.conf import settings +from .models import Wishlist + class EmptyCart(object): """ @@ -48,6 +50,20 @@ def add_item(self, *args, **kwargs): self._request.session["cart"] = cart.id +class CookieBackedWishlist(object): + """ + A dummy wishlist object used for unauthenticated users, backed by cookie + storage. + """ + def __init__(self, request): + super(CookieBackedWishlist, self).__init__() + self.request = request + + def save(self, *args, **kwargs): + if self.sku not in self.request.wishlist: + self.request.wishlist.append(self.sku) + + def make_choices(choices): """ Zips a list with itself for field choices. @@ -113,3 +129,11 @@ def set_locale(): "configure the SHOP_CURRENCY_LOCALE setting in your settings " "module.") raise ImproperlyConfigured(msg % currency_locale) + + +def get_wishlist(request): + if request.user.is_authenticated(): + wishlist = Wishlist() + else: + wishlist = CookieBackedWishlist(request) + return wishlist diff --git a/cartridge/shop/views.py b/cartridge/shop/views.py index 174ab5bfa..66ec075d3 100644 --- a/cartridge/shop/views.py +++ b/cartridge/shop/views.py @@ -23,6 +23,8 @@ from cartridge.shop.models import DiscountCode, Wishlist from cartridge.shop.utils import recalculate_discount, sign +from .utils import get_wishlist + # Set up checkout handlers. handler = lambda s: import_dotted_path(s) if s else lambda *args: None @@ -62,20 +64,14 @@ def product(request, slug, template="shop/product.html"): return redirect("shop_cart") else: response = redirect("shop_wishlist") - if not request.user.is_authenticated(): - skus = request.wishlist - sku = add_product_form.variation.sku - if sku not in skus: - skus.append(sku) - set_cookie(response, "wishlist", ",".join(skus)) - else: - wishlist = Wishlist() - wishlist.user = request.user - wishlist.sku = add_product_form.variation.sku - try: - wishlist.save() - except IntegrityError: - pass + wishlist = get_wishlist(request) + wishlist.user = request.user + wishlist.sku = add_product_form.variation.sku + try: + wishlist.save() + except IntegrityError: + pass + set_cookie(response, "wishlist", ",".join(request.wishlist)) info(request, _("Item added to wishlist")) return response context = { @@ -86,7 +82,8 @@ def product(request, slug, template="shop/product.html"): "variations_json": variations_json, "has_available_variations": any([v.has_price() for v in variations]), "related_products": product.related_products.published( - for_user=request.user), + for_user=request.user + ), "add_product_form": add_product_form } return render(request, template, context) @@ -120,21 +117,16 @@ def wishlist(request, template="shop/wishlist.html"): message = _("Item removed from wishlist") url = "shop_wishlist" sku = request.POST.get("sku") - if sku in skus: - if not request.user.is_authenticated(): - skus.remove(sku) - else: - wishlist_item = Wishlist.objects.get(user=request.user, - sku=sku) - wishlist_item.delete() + if sku in request.wishlist: + Wishlist.objects.delete_for_request(sku, request) if not error: info(request, message) response = redirect(url) - if not request.user.is_authenticated(): - set_cookie(response, "wishlist", ",".join(skus)) + set_cookie(response, "wishlist", ",".join(request.wishlist)) return response # Remove skus from the cookie that no longer exist. + skus = request.wishlist published_products = Product.objects.published(for_user=request.user) f = {"product__in": published_products, "sku__in": skus} wishlist = ProductVariation.objects.filter(**f).select_related(depth=1) From fadb96f55a0f65360a5843cc6452e066371dbca2 Mon Sep 17 00:00:00 2001 From: Tzu-ping Chung Date: Sat, 27 Apr 2013 22:43:45 +0800 Subject: [PATCH 5/9] Add hook to transfer cookie-stored wishlist to database when user logs in --- cartridge/shop/models.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/cartridge/shop/models.py b/cartridge/shop/models.py index 1e3661eb3..915d97b34 100644 --- a/cartridge/shop/models.py +++ b/cartridge/shop/models.py @@ -2,6 +2,7 @@ from operator import iand, ior from django.contrib.auth.models import User +from django.contrib.auth.signals import user_logged_in from django.core.urlresolvers import reverse from django.db import models from django.db.models.signals import m2m_changed, pre_save @@ -882,3 +883,16 @@ class Meta: unique_together = ('user', 'sku') verbose_name = _("Wishlist item") verbose_name_plural = _("Wishlist items") + + +@receiver(user_logged_in, sender=User) +def transfer_wishlist_data(sender, request, user): + skus = request.wishlist + existed = (Wishlist.objects.filter(user=user, sku__in=skus) + .values_list("sku", flat=True)) + for sku in skus: + if sku not in existed: + wishlist = Wishlist() + wishlist.user = user + wishlist.sku = sku + wishlist.save() From 0f62937d1430aa507e0e9d2775ced952bfa645f6 Mon Sep 17 00:00:00 2001 From: Tzu-ping Chung Date: Sat, 27 Apr 2013 23:09:28 +0800 Subject: [PATCH 6/9] Use absolute import --- cartridge/shop/utils.py | 2 +- cartridge/shop/views.py | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/cartridge/shop/utils.py b/cartridge/shop/utils.py index 575e74333..5a9516e13 100644 --- a/cartridge/shop/utils.py +++ b/cartridge/shop/utils.py @@ -11,7 +11,7 @@ from mezzanine.conf import settings -from .models import Wishlist +from cartridge.shop.models import Wishlist class EmptyCart(object): diff --git a/cartridge/shop/views.py b/cartridge/shop/views.py index 66ec075d3..21886bf46 100644 --- a/cartridge/shop/views.py +++ b/cartridge/shop/views.py @@ -21,9 +21,7 @@ from cartridge.shop.forms import AddProductForm, DiscountForm, CartItemFormSet from cartridge.shop.models import Product, ProductVariation, Order, OrderItem from cartridge.shop.models import DiscountCode, Wishlist -from cartridge.shop.utils import recalculate_discount, sign - -from .utils import get_wishlist +from cartridge.shop.utils import recalculate_discount, sign, get_wishlist # Set up checkout handlers. From dbc17b4da14cc825971dfff4ec05df0f7904cb1e Mon Sep 17 00:00:00 2001 From: Tzu-ping Chung Date: Sat, 27 Apr 2013 23:20:16 +0800 Subject: [PATCH 7/9] Bug fixes and migration rename --- ..._wishlist__add_unique_wishlist_user_sku.py | 298 ++++++++++++++++++ cartridge/shop/models.py | 2 +- cartridge/shop/utils.py | 3 +- 3 files changed, 300 insertions(+), 3 deletions(-) create mode 100644 cartridge/shop/migrations/0021_auto__add_wishlist__add_unique_wishlist_user_sku.py diff --git a/cartridge/shop/migrations/0021_auto__add_wishlist__add_unique_wishlist_user_sku.py b/cartridge/shop/migrations/0021_auto__add_wishlist__add_unique_wishlist_user_sku.py new file mode 100644 index 000000000..12576525c --- /dev/null +++ b/cartridge/shop/migrations/0021_auto__add_wishlist__add_unique_wishlist_user_sku.py @@ -0,0 +1,298 @@ +# -*- coding: utf-8 -*- +import datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + # Adding model 'Wishlist' + db.create_table('shop_wishlist', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])), + ('sku', self.gf('cartridge.shop.fields.SKUField')(max_length=20)), + )) + db.send_create_signal('shop', ['Wishlist']) + + # Adding unique constraint on 'Wishlist', fields ['user', 'sku'] + db.create_unique('shop_wishlist', ['user_id', 'sku']) + + + def backwards(self, orm): + # Removing unique constraint on 'Wishlist', fields ['user', 'sku'] + db.delete_unique('shop_wishlist', ['user_id', 'sku']) + + # Deleting model 'Wishlist' + db.delete_table('shop_wishlist') + + + models = { + 'auth.group': { + 'Meta': {'object_name': 'Group'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), + 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) + }, + 'auth.permission': { + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + }, + 'auth.user': { + 'Meta': {'object_name': 'User'}, + 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), + 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), + 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), + 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), + 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), + 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) + }, + 'contenttypes.contenttype': { + 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, + 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) + }, + 'generic.assignedkeyword': { + 'Meta': {'ordering': "('_order',)", 'object_name': 'AssignedKeyword'}, + '_order': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'keyword': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'assignments'", 'to': "orm['generic.Keyword']"}), + 'object_pk': ('django.db.models.fields.IntegerField', [], {}) + }, + 'generic.keyword': { + 'Meta': {'object_name': 'Keyword'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '2000', 'null': 'True', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '500'}) + }, + 'generic.rating': { + 'Meta': {'object_name': 'Rating'}, + 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'object_pk': ('django.db.models.fields.IntegerField', [], {}), + 'value': ('django.db.models.fields.IntegerField', [], {}) + }, + 'pages.page': { + 'Meta': {'ordering': "('titles',)", 'object_name': 'Page'}, + '_meta_title': ('django.db.models.fields.CharField', [], {'max_length': '500', 'null': 'True', 'blank': 'True'}), + '_order': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'content_model': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'expiry_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'gen_description': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'in_menus': ('mezzanine.pages.fields.MenusField', [], {'default': '[1, 2, 3]', 'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'keywords': ('mezzanine.generic.fields.KeywordsField', [], {'object_id_field': "'object_pk'", 'to': "orm['generic.AssignedKeyword']", 'frozen_by_south': 'True'}), + 'keywords_string': ('django.db.models.fields.CharField', [], {'max_length': '500', 'blank': 'True'}), + 'login_required': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['pages.Page']"}), + 'publish_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'short_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '2000', 'null': 'True', 'blank': 'True'}), + 'status': ('django.db.models.fields.IntegerField', [], {'default': '2'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '500'}), + 'titles': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True'}) + }, + 'shop.cart': { + 'Meta': {'object_name': 'Cart'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'last_updated': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}) + }, + 'shop.cartitem': { + 'Meta': {'object_name': 'CartItem'}, + 'cart': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'items'", 'to': "orm['shop.Cart']"}), + 'description': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}), + 'quantity': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'sku': ('cartridge.shop.fields.SKUField', [], {'max_length': '20'}), + 'total_price': ('cartridge.shop.fields.MoneyField', [], {'default': "'0'", 'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'unit_price': ('cartridge.shop.fields.MoneyField', [], {'default': "'0'", 'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'url': ('django.db.models.fields.CharField', [], {'max_length': '200'}) + }, + 'shop.category': { + 'Meta': {'ordering': "('_order',)", 'object_name': 'Category', '_ormbases': ['pages.Page']}, + 'combined': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'content': ('mezzanine.core.fields.RichTextField', [], {}), + 'options': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'product_options'", 'blank': 'True', 'to': "orm['shop.ProductOption']"}), + 'page_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['pages.Page']", 'unique': 'True', 'primary_key': 'True'}), + 'price_max': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'price_min': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'products': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['shop.Product']", 'symmetrical': 'False', 'blank': 'True'}), + 'sale': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['shop.Sale']", 'null': 'True', 'blank': 'True'}) + }, + 'shop.discountcode': { + 'Meta': {'object_name': 'DiscountCode'}, + 'active': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'categories': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'discountcode_related'", 'blank': 'True', 'to': "orm['shop.Category']"}), + 'code': ('cartridge.shop.fields.DiscountCodeField', [], {'unique': 'True', 'max_length': '20'}), + 'discount_deduct': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'discount_exact': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'discount_percent': ('cartridge.shop.fields.PercentageField', [], {'null': 'True', 'max_digits': '5', 'decimal_places': '2', 'blank': 'True'}), + 'free_shipping': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'min_purchase': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'products': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['shop.Product']", 'symmetrical': 'False', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'uses_remaining': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'valid_from': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'valid_to': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}) + }, + 'shop.order': { + 'Meta': {'ordering': "('-id',)", 'object_name': 'Order'}, + 'additional_instructions': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'billing_detail_city': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'billing_detail_country': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'billing_detail_email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}), + 'billing_detail_first_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'billing_detail_last_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'billing_detail_phone': ('django.db.models.fields.CharField', [], {'max_length': '20'}), + 'billing_detail_postcode': ('django.db.models.fields.CharField', [], {'max_length': '10'}), + 'billing_detail_state': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'billing_detail_street': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'discount_code': ('cartridge.shop.fields.DiscountCodeField', [], {'max_length': '20', 'blank': 'True'}), + 'discount_total': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'item_total': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'key': ('django.db.models.fields.CharField', [], {'max_length': '40'}), + 'shipping_detail_city': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'shipping_detail_country': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'shipping_detail_first_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'shipping_detail_last_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'shipping_detail_phone': ('django.db.models.fields.CharField', [], {'max_length': '20'}), + 'shipping_detail_postcode': ('django.db.models.fields.CharField', [], {'max_length': '10'}), + 'shipping_detail_state': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'shipping_detail_street': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'shipping_total': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'shipping_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), + 'status': ('django.db.models.fields.IntegerField', [], {'default': '1'}), + 'time': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}), + 'total': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'transaction_id': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), + 'user_id': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) + }, + 'shop.orderitem': { + 'Meta': {'object_name': 'OrderItem'}, + 'description': ('django.db.models.fields.CharField', [], {'max_length': '200'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'order': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'items'", 'to': "orm['shop.Order']"}), + 'quantity': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'sku': ('cartridge.shop.fields.SKUField', [], {'max_length': '20'}), + 'total_price': ('cartridge.shop.fields.MoneyField', [], {'default': "'0'", 'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'unit_price': ('cartridge.shop.fields.MoneyField', [], {'default': "'0'", 'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}) + }, + 'shop.product': { + 'Meta': {'object_name': 'Product'}, + '_meta_title': ('django.db.models.fields.CharField', [], {'max_length': '500', 'null': 'True', 'blank': 'True'}), + 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'categories': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['shop.Category']", 'symmetrical': 'False', 'blank': 'True'}), + 'content': ('mezzanine.core.fields.RichTextField', [], {}), + 'date_added': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'expiry_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'gen_description': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), + 'keywords': ('mezzanine.generic.fields.KeywordsField', [], {'object_id_field': "'object_pk'", 'to': "orm['generic.AssignedKeyword']", 'frozen_by_south': 'True'}), + 'keywords_string': ('django.db.models.fields.CharField', [], {'max_length': '500', 'blank': 'True'}), + 'num_in_stock': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'publish_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'rating': ('mezzanine.generic.fields.RatingField', [], {'object_id_field': "'object_pk'", 'to': "orm['generic.Rating']", 'frozen_by_south': 'True'}), + 'rating_average': ('django.db.models.fields.FloatField', [], {'default': '0'}), + 'rating_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'related_products': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'related_products_rel_+'", 'blank': 'True', 'to': "orm['shop.Product']"}), + 'sale_from': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'sale_id': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'sale_price': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'sale_to': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'short_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), + 'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"}), + 'sku': ('cartridge.shop.fields.SKUField', [], {'max_length': '20', 'unique': 'True', 'null': 'True', 'blank': 'True'}), + 'slug': ('django.db.models.fields.CharField', [], {'max_length': '2000', 'null': 'True', 'blank': 'True'}), + 'status': ('django.db.models.fields.IntegerField', [], {'default': '2'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '500'}), + 'unit_price': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'upsell_products': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'upsell_products_rel_+'", 'blank': 'True', 'to': "orm['shop.Product']"}) + }, + 'shop.productaction': { + 'Meta': {'unique_together': "(('product', 'timestamp'),)", 'object_name': 'ProductAction'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'product': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['shop.Product']"}), + 'timestamp': ('django.db.models.fields.IntegerField', [], {}), + 'total_cart': ('django.db.models.fields.IntegerField', [], {'default': '0'}), + 'total_purchase': ('django.db.models.fields.IntegerField', [], {'default': '0'}) + }, + 'shop.productimage': { + 'Meta': {'ordering': "('_order',)", 'object_name': 'ProductImage'}, + '_order': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'description': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), + 'file': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'product': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'images'", 'to': "orm['shop.Product']"}) + }, + 'shop.productoption': { + 'Meta': {'object_name': 'ProductOption'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('cartridge.shop.fields.OptionField', [], {'max_length': '50', 'null': 'True'}), + 'type': ('django.db.models.fields.IntegerField', [], {}) + }, + 'shop.productvariation': { + 'Meta': {'ordering': "('-default',)", 'object_name': 'ProductVariation'}, + 'default': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'image': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['shop.ProductImage']", 'null': 'True', 'blank': 'True'}), + 'num_in_stock': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), + 'option1': ('cartridge.shop.fields.OptionField', [], {'max_length': '50', 'null': 'True'}), + 'option2': ('cartridge.shop.fields.OptionField', [], {'max_length': '50', 'null': 'True'}), + 'product': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'variations'", 'to': "orm['shop.Product']"}), + 'sale_from': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'sale_id': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), + 'sale_price': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'sale_to': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'sku': ('cartridge.shop.fields.SKUField', [], {'max_length': '20', 'unique': 'True', 'null': 'True', 'blank': 'True'}), + 'unit_price': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}) + }, + 'shop.sale': { + 'Meta': {'object_name': 'Sale'}, + 'active': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'categories': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'sale_related'", 'blank': 'True', 'to': "orm['shop.Category']"}), + 'discount_deduct': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'discount_exact': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), + 'discount_percent': ('cartridge.shop.fields.PercentageField', [], {'null': 'True', 'max_digits': '5', 'decimal_places': '2', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'products': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['shop.Product']", 'symmetrical': 'False', 'blank': 'True'}), + 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'valid_from': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), + 'valid_to': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}) + }, + 'shop.wishlist': { + 'Meta': {'unique_together': "(('user', 'sku'),)", 'object_name': 'Wishlist'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'sku': ('cartridge.shop.fields.SKUField', [], {'max_length': '20'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) + }, + 'sites.site': { + 'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"}, + 'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) + } + } + + complete_apps = ['shop'] \ No newline at end of file diff --git a/cartridge/shop/models.py b/cartridge/shop/models.py index 915d97b34..5584b3c0b 100644 --- a/cartridge/shop/models.py +++ b/cartridge/shop/models.py @@ -886,7 +886,7 @@ class Meta: @receiver(user_logged_in, sender=User) -def transfer_wishlist_data(sender, request, user): +def transfer_wishlist_data(sender, request, user, *args, **kwargs): skus = request.wishlist existed = (Wishlist.objects.filter(user=user, sku__in=skus) .values_list("sku", flat=True)) diff --git a/cartridge/shop/utils.py b/cartridge/shop/utils.py index 5a9516e13..da4604d36 100644 --- a/cartridge/shop/utils.py +++ b/cartridge/shop/utils.py @@ -11,8 +11,6 @@ from mezzanine.conf import settings -from cartridge.shop.models import Wishlist - class EmptyCart(object): """ @@ -133,6 +131,7 @@ def set_locale(): def get_wishlist(request): if request.user.is_authenticated(): + from cartridge.shop.models import Wishlist wishlist = Wishlist() else: wishlist = CookieBackedWishlist(request) From 2f99de597d38dd59799b053faa26d391b2ed1ca6 Mon Sep 17 00:00:00 2001 From: Tzu-ping Chung Date: Sun, 28 Apr 2013 14:07:32 +0800 Subject: [PATCH 8/9] Remove duplicate migration file --- ..._wishlist__add_unique_wishlist_user_sku.py | 298 ------------------ 1 file changed, 298 deletions(-) delete mode 100644 cartridge/shop/migrations/0017_auto__add_wishlist__add_unique_wishlist_user_sku.py diff --git a/cartridge/shop/migrations/0017_auto__add_wishlist__add_unique_wishlist_user_sku.py b/cartridge/shop/migrations/0017_auto__add_wishlist__add_unique_wishlist_user_sku.py deleted file mode 100644 index 12576525c..000000000 --- a/cartridge/shop/migrations/0017_auto__add_wishlist__add_unique_wishlist_user_sku.py +++ /dev/null @@ -1,298 +0,0 @@ -# -*- coding: utf-8 -*- -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - - -class Migration(SchemaMigration): - - def forwards(self, orm): - # Adding model 'Wishlist' - db.create_table('shop_wishlist', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'])), - ('sku', self.gf('cartridge.shop.fields.SKUField')(max_length=20)), - )) - db.send_create_signal('shop', ['Wishlist']) - - # Adding unique constraint on 'Wishlist', fields ['user', 'sku'] - db.create_unique('shop_wishlist', ['user_id', 'sku']) - - - def backwards(self, orm): - # Removing unique constraint on 'Wishlist', fields ['user', 'sku'] - db.delete_unique('shop_wishlist', ['user_id', 'sku']) - - # Deleting model 'Wishlist' - db.delete_table('shop_wishlist') - - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'Meta': {'object_name': 'User'}, - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'generic.assignedkeyword': { - 'Meta': {'ordering': "('_order',)", 'object_name': 'AssignedKeyword'}, - '_order': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'keyword': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'assignments'", 'to': "orm['generic.Keyword']"}), - 'object_pk': ('django.db.models.fields.IntegerField', [], {}) - }, - 'generic.keyword': { - 'Meta': {'object_name': 'Keyword'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"}), - 'slug': ('django.db.models.fields.CharField', [], {'max_length': '2000', 'null': 'True', 'blank': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '500'}) - }, - 'generic.rating': { - 'Meta': {'object_name': 'Rating'}, - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'object_pk': ('django.db.models.fields.IntegerField', [], {}), - 'value': ('django.db.models.fields.IntegerField', [], {}) - }, - 'pages.page': { - 'Meta': {'ordering': "('titles',)", 'object_name': 'Page'}, - '_meta_title': ('django.db.models.fields.CharField', [], {'max_length': '500', 'null': 'True', 'blank': 'True'}), - '_order': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), - 'content_model': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), - 'expiry_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'gen_description': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'in_menus': ('mezzanine.pages.fields.MenusField', [], {'default': '[1, 2, 3]', 'max_length': '100', 'null': 'True', 'blank': 'True'}), - 'keywords': ('mezzanine.generic.fields.KeywordsField', [], {'object_id_field': "'object_pk'", 'to': "orm['generic.AssignedKeyword']", 'frozen_by_south': 'True'}), - 'keywords_string': ('django.db.models.fields.CharField', [], {'max_length': '500', 'blank': 'True'}), - 'login_required': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'null': 'True', 'to': "orm['pages.Page']"}), - 'publish_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'short_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), - 'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"}), - 'slug': ('django.db.models.fields.CharField', [], {'max_length': '2000', 'null': 'True', 'blank': 'True'}), - 'status': ('django.db.models.fields.IntegerField', [], {'default': '2'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '500'}), - 'titles': ('django.db.models.fields.CharField', [], {'max_length': '1000', 'null': 'True'}) - }, - 'shop.cart': { - 'Meta': {'object_name': 'Cart'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'last_updated': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}) - }, - 'shop.cartitem': { - 'Meta': {'object_name': 'CartItem'}, - 'cart': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'items'", 'to': "orm['shop.Cart']"}), - 'description': ('django.db.models.fields.CharField', [], {'max_length': '200'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'image': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}), - 'quantity': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'sku': ('cartridge.shop.fields.SKUField', [], {'max_length': '20'}), - 'total_price': ('cartridge.shop.fields.MoneyField', [], {'default': "'0'", 'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), - 'unit_price': ('cartridge.shop.fields.MoneyField', [], {'default': "'0'", 'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), - 'url': ('django.db.models.fields.CharField', [], {'max_length': '200'}) - }, - 'shop.category': { - 'Meta': {'ordering': "('_order',)", 'object_name': 'Category', '_ormbases': ['pages.Page']}, - 'combined': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'content': ('mezzanine.core.fields.RichTextField', [], {}), - 'options': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'product_options'", 'blank': 'True', 'to': "orm['shop.ProductOption']"}), - 'page_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['pages.Page']", 'unique': 'True', 'primary_key': 'True'}), - 'price_max': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), - 'price_min': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), - 'products': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['shop.Product']", 'symmetrical': 'False', 'blank': 'True'}), - 'sale': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['shop.Sale']", 'null': 'True', 'blank': 'True'}) - }, - 'shop.discountcode': { - 'Meta': {'object_name': 'DiscountCode'}, - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'categories': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'discountcode_related'", 'blank': 'True', 'to': "orm['shop.Category']"}), - 'code': ('cartridge.shop.fields.DiscountCodeField', [], {'unique': 'True', 'max_length': '20'}), - 'discount_deduct': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), - 'discount_exact': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), - 'discount_percent': ('cartridge.shop.fields.PercentageField', [], {'null': 'True', 'max_digits': '5', 'decimal_places': '2', 'blank': 'True'}), - 'free_shipping': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'min_purchase': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), - 'products': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['shop.Product']", 'symmetrical': 'False', 'blank': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'uses_remaining': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), - 'valid_from': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'valid_to': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}) - }, - 'shop.order': { - 'Meta': {'ordering': "('-id',)", 'object_name': 'Order'}, - 'additional_instructions': ('django.db.models.fields.TextField', [], {'blank': 'True'}), - 'billing_detail_city': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'billing_detail_country': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'billing_detail_email': ('django.db.models.fields.EmailField', [], {'max_length': '75'}), - 'billing_detail_first_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'billing_detail_last_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'billing_detail_phone': ('django.db.models.fields.CharField', [], {'max_length': '20'}), - 'billing_detail_postcode': ('django.db.models.fields.CharField', [], {'max_length': '10'}), - 'billing_detail_state': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'billing_detail_street': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'discount_code': ('cartridge.shop.fields.DiscountCodeField', [], {'max_length': '20', 'blank': 'True'}), - 'discount_total': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'item_total': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), - 'key': ('django.db.models.fields.CharField', [], {'max_length': '40'}), - 'shipping_detail_city': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'shipping_detail_country': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'shipping_detail_first_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'shipping_detail_last_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'shipping_detail_phone': ('django.db.models.fields.CharField', [], {'max_length': '20'}), - 'shipping_detail_postcode': ('django.db.models.fields.CharField', [], {'max_length': '10'}), - 'shipping_detail_state': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'shipping_detail_street': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'shipping_total': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), - 'shipping_type': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'}), - 'status': ('django.db.models.fields.IntegerField', [], {'default': '1'}), - 'time': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}), - 'total': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), - 'transaction_id': ('django.db.models.fields.CharField', [], {'max_length': '255', 'null': 'True', 'blank': 'True'}), - 'user_id': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}) - }, - 'shop.orderitem': { - 'Meta': {'object_name': 'OrderItem'}, - 'description': ('django.db.models.fields.CharField', [], {'max_length': '200'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'order': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'items'", 'to': "orm['shop.Order']"}), - 'quantity': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'sku': ('cartridge.shop.fields.SKUField', [], {'max_length': '20'}), - 'total_price': ('cartridge.shop.fields.MoneyField', [], {'default': "'0'", 'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), - 'unit_price': ('cartridge.shop.fields.MoneyField', [], {'default': "'0'", 'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}) - }, - 'shop.product': { - 'Meta': {'object_name': 'Product'}, - '_meta_title': ('django.db.models.fields.CharField', [], {'max_length': '500', 'null': 'True', 'blank': 'True'}), - 'available': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'categories': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['shop.Category']", 'symmetrical': 'False', 'blank': 'True'}), - 'content': ('mezzanine.core.fields.RichTextField', [], {}), - 'date_added': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}), - 'expiry_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'gen_description': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'image': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True', 'blank': 'True'}), - 'keywords': ('mezzanine.generic.fields.KeywordsField', [], {'object_id_field': "'object_pk'", 'to': "orm['generic.AssignedKeyword']", 'frozen_by_south': 'True'}), - 'keywords_string': ('django.db.models.fields.CharField', [], {'max_length': '500', 'blank': 'True'}), - 'num_in_stock': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), - 'publish_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'rating': ('mezzanine.generic.fields.RatingField', [], {'object_id_field': "'object_pk'", 'to': "orm['generic.Rating']", 'frozen_by_south': 'True'}), - 'rating_average': ('django.db.models.fields.FloatField', [], {'default': '0'}), - 'rating_count': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'related_products': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'related_products_rel_+'", 'blank': 'True', 'to': "orm['shop.Product']"}), - 'sale_from': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'sale_id': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), - 'sale_price': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), - 'sale_to': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'short_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}), - 'site': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['sites.Site']"}), - 'sku': ('cartridge.shop.fields.SKUField', [], {'max_length': '20', 'unique': 'True', 'null': 'True', 'blank': 'True'}), - 'slug': ('django.db.models.fields.CharField', [], {'max_length': '2000', 'null': 'True', 'blank': 'True'}), - 'status': ('django.db.models.fields.IntegerField', [], {'default': '2'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '500'}), - 'unit_price': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), - 'upsell_products': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'upsell_products_rel_+'", 'blank': 'True', 'to': "orm['shop.Product']"}) - }, - 'shop.productaction': { - 'Meta': {'unique_together': "(('product', 'timestamp'),)", 'object_name': 'ProductAction'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'product': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'actions'", 'to': "orm['shop.Product']"}), - 'timestamp': ('django.db.models.fields.IntegerField', [], {}), - 'total_cart': ('django.db.models.fields.IntegerField', [], {'default': '0'}), - 'total_purchase': ('django.db.models.fields.IntegerField', [], {'default': '0'}) - }, - 'shop.productimage': { - 'Meta': {'ordering': "('_order',)", 'object_name': 'ProductImage'}, - '_order': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), - 'description': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}), - 'file': ('django.db.models.fields.files.ImageField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'product': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'images'", 'to': "orm['shop.Product']"}) - }, - 'shop.productoption': { - 'Meta': {'object_name': 'ProductOption'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('cartridge.shop.fields.OptionField', [], {'max_length': '50', 'null': 'True'}), - 'type': ('django.db.models.fields.IntegerField', [], {}) - }, - 'shop.productvariation': { - 'Meta': {'ordering': "('-default',)", 'object_name': 'ProductVariation'}, - 'default': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'image': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['shop.ProductImage']", 'null': 'True', 'blank': 'True'}), - 'num_in_stock': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), - 'option1': ('cartridge.shop.fields.OptionField', [], {'max_length': '50', 'null': 'True'}), - 'option2': ('cartridge.shop.fields.OptionField', [], {'max_length': '50', 'null': 'True'}), - 'product': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'variations'", 'to': "orm['shop.Product']"}), - 'sale_from': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'sale_id': ('django.db.models.fields.IntegerField', [], {'null': 'True'}), - 'sale_price': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), - 'sale_to': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'sku': ('cartridge.shop.fields.SKUField', [], {'max_length': '20', 'unique': 'True', 'null': 'True', 'blank': 'True'}), - 'unit_price': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}) - }, - 'shop.sale': { - 'Meta': {'object_name': 'Sale'}, - 'active': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'categories': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'related_name': "'sale_related'", 'blank': 'True', 'to': "orm['shop.Category']"}), - 'discount_deduct': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), - 'discount_exact': ('cartridge.shop.fields.MoneyField', [], {'null': 'True', 'max_digits': '10', 'decimal_places': '2', 'blank': 'True'}), - 'discount_percent': ('cartridge.shop.fields.PercentageField', [], {'null': 'True', 'max_digits': '5', 'decimal_places': '2', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'products': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['shop.Product']", 'symmetrical': 'False', 'blank': 'True'}), - 'title': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'valid_from': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'valid_to': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}) - }, - 'shop.wishlist': { - 'Meta': {'unique_together': "(('user', 'sku'),)", 'object_name': 'Wishlist'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'sku': ('cartridge.shop.fields.SKUField', [], {'max_length': '20'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}) - }, - 'sites.site': { - 'Meta': {'ordering': "('domain',)", 'object_name': 'Site', 'db_table': "'django_site'"}, - 'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - } - } - - complete_apps = ['shop'] \ No newline at end of file From c6f0abc7ade3c9ed7fe64604811d892e67c326c3 Mon Sep 17 00:00:00 2001 From: Tzu-ping Chung Date: Sun, 28 Apr 2013 14:16:35 +0800 Subject: [PATCH 9/9] Fix AttributeError in login hook --- cartridge/shop/models.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cartridge/shop/models.py b/cartridge/shop/models.py index 5584b3c0b..abe9e8816 100644 --- a/cartridge/shop/models.py +++ b/cartridge/shop/models.py @@ -887,7 +887,9 @@ class Meta: @receiver(user_logged_in, sender=User) def transfer_wishlist_data(sender, request, user, *args, **kwargs): - skus = request.wishlist + skus = getattr(request, "wishlist", []) + if not skus: + return existed = (Wishlist.objects.filter(user=user, sku__in=skus) .values_list("sku", flat=True)) for sku in skus: