Adds “CategoryForm” to forms.py. It’s about to replace the existing ProductItem form
This commit is contained in:
		
							parent
							
								
									68e7e4e594
								
							
						
					
					
						commit
						745f6db444
					
				
					 3 changed files with 80 additions and 33 deletions
				
			
		|  | @ -3,11 +3,46 @@ import models as rego | |||
| from django import forms | ||||
| 
 | ||||
| 
 | ||||
| class ProductItemForm(forms.Form): | ||||
|     product = forms.ModelChoiceField(queryset=None, empty_label=None) | ||||
|     quantity = forms.IntegerField() | ||||
| def CategoryForm(category): | ||||
| 
 | ||||
|     def __init__(self, category, *a, **k): | ||||
|         super(ProductItemForm, self).__init__(*a, **k) | ||||
|         products = rego.Product.objects.filter(category=category) | ||||
|         self.fields['product'].queryset = products | ||||
|     PREFIX = "product_" | ||||
| 
 | ||||
|     def field_name(product): | ||||
|         return PREFIX + ("%d" % product.id) | ||||
| 
 | ||||
|     class _CategoryForm(forms.Form): | ||||
| 
 | ||||
|         @staticmethod | ||||
|         def initial_data(product_quantities): | ||||
|             ''' Prepares initial data for an instance of this form. | ||||
|             product_quantities is a sequence of (product,quantity) tuples ''' | ||||
|             initial = {} | ||||
|             for product, quantity in product_quantities: | ||||
|                 initial[field_name(product)] = quantity | ||||
| 
 | ||||
|             return initial | ||||
| 
 | ||||
|         def product_quantities(self): | ||||
|             ''' Yields a sequence of (product, quantity) tuples from the | ||||
|             cleaned form data. ''' | ||||
|             for name, value in self.cleaned_data.items(): | ||||
|                 if name.startswith(PREFIX): | ||||
|                     product_id = int(name[len(PREFIX):]) | ||||
|                     yield (product_id, value, name) | ||||
| 
 | ||||
|         def disable_product(self, product): | ||||
|             ''' Removes a given product from this form. ''' | ||||
|             del self.fields[field_name(product)] | ||||
| 
 | ||||
|     products = rego.Product.objects.filter(category=category).order_by("order") | ||||
|     for product in products: | ||||
| 
 | ||||
|         help_text = "$%d -- %s" % (product.price, product.description) | ||||
| 
 | ||||
|         field = forms.IntegerField( | ||||
|             label=product.name, | ||||
|             help_text=help_text, | ||||
|         ) | ||||
|         _CategoryForm.base_fields[field_name(product)] = field | ||||
| 
 | ||||
|     return _CategoryForm | ||||
|  |  | |||
|  | @ -9,12 +9,14 @@ | |||
| 
 | ||||
|   <form method="post" action=""> | ||||
|     {% csrf_token %} | ||||
| 
 | ||||
|     <table> | ||||
|         {{ formset }} | ||||
|         {{ form }} | ||||
|     </table> | ||||
| 
 | ||||
|     <input type="submit"> | ||||
| 
 | ||||
|   </form> | ||||
| 
 | ||||
| 
 | ||||
| {% endblock %} | ||||
|  |  | |||
|  | @ -6,11 +6,10 @@ from registrasion.controllers.product import ProductController | |||
| 
 | ||||
| from django.contrib.auth.decorators import login_required | ||||
| from django.core.exceptions import ObjectDoesNotExist | ||||
| from django.core.exceptions import ValidationError | ||||
| from django.db import transaction | ||||
| from django.forms import formset_factory | ||||
| from django.shortcuts import redirect | ||||
| from django.shortcuts import render | ||||
| from functools import partial, wraps | ||||
| 
 | ||||
| 
 | ||||
| @login_required | ||||
|  | @ -20,50 +19,61 @@ def product_category(request, category_id): | |||
|     category_id = int(category_id)  # Routing is [0-9]+ | ||||
|     category = rego.Category.objects.get(pk=category_id) | ||||
| 
 | ||||
|     ProductItemFormForCategory = ( | ||||
|         wraps(forms.ProductItemForm) | ||||
|         (partial(forms.ProductItemForm, category=category))) | ||||
|     ProductItemFormSet = formset_factory(ProductItemFormForCategory, extra=0) | ||||
|     CategoryForm = forms.CategoryForm(category) | ||||
| 
 | ||||
|     products = rego.Product.objects.filter(category=category) | ||||
|     products = products.order_by("order") | ||||
| 
 | ||||
|     if request.method == "POST": | ||||
|         formset = ProductItemFormSet(request.POST, request.FILES) | ||||
|         if formset.is_valid(): | ||||
|         cat_form = CategoryForm(request.POST, request.FILES) | ||||
|         if cat_form.is_valid(): | ||||
|             current_cart = CartController.for_user(request.user) | ||||
|             with transaction.atomic(): | ||||
|                 for form in formset.forms: | ||||
|                     data = form.cleaned_data | ||||
|                     # TODO set form error instead of failing completely | ||||
|                     current_cart.set_quantity( | ||||
|                         data["product"], data["quantity"], batched=True) | ||||
|                 current_cart.end_batch() | ||||
|             try: | ||||
|                 with transaction.atomic(): | ||||
|                     for product_id, quantity, field_name \ | ||||
|                             in cat_form.product_quantities(): | ||||
|                         product = rego.Product.objects.get(pk=product_id) | ||||
|                         try: | ||||
|                             current_cart.set_quantity( | ||||
|                                 product, quantity, batched=True) | ||||
|                         except ValidationError as ve: | ||||
|                             cat_form.add_error(field_name, ve) | ||||
|                     if cat_form.errors: | ||||
|                         raise ValidationError("Cannot add that stuff") | ||||
|                     current_cart.end_batch() | ||||
|             except ValidationError as ve: | ||||
|                 pass | ||||
| 
 | ||||
|     else: | ||||
|         # Create initial data for each of products in category | ||||
|         initial = [] | ||||
|         products = rego.Product.objects.filter(category=category) | ||||
|         items = rego.ProductItem.objects.filter(product__category=category) | ||||
|         products = products.order_by("order") | ||||
|         quantities = [] | ||||
|         for product in products: | ||||
|             # Only add items that are enabled. | ||||
|             prod = ProductController(product) | ||||
|             if not prod.can_add_with_enabling_conditions(request.user, 0): | ||||
|                 continue | ||||
| 
 | ||||
|             try: | ||||
|                 quantity = items.get(product=product).quantity | ||||
|             except ObjectDoesNotExist: | ||||
|                 quantity = 0 | ||||
|             data = {"product": product, "quantity": quantity} | ||||
|             initial.append(data) | ||||
|             quantities.append((product, quantity)) | ||||
| 
 | ||||
|         formset = ProductItemFormSet(initial=initial) | ||||
|         initial = CategoryForm.initial_data(quantities) | ||||
|         cat_form = CategoryForm(initial=initial) | ||||
| 
 | ||||
|     for product in products: | ||||
|         # Remove fields that do not have an enabling condition. | ||||
|         prod = ProductController(product) | ||||
|         if not prod.can_add_with_enabling_conditions(request.user, 0): | ||||
|             cat_form.disable_product(product) | ||||
| 
 | ||||
|     data = { | ||||
|         "category": category, | ||||
|         "formset": formset, | ||||
|         "form": cat_form, | ||||
|     } | ||||
| 
 | ||||
|     return render(request, "product_category.html", data) | ||||
| 
 | ||||
| 
 | ||||
| @login_required | ||||
| def checkout(request): | ||||
|     ''' Runs checkout for the current cart of items, ideally generating an | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Christopher Neugebauer
						Christopher Neugebauer