def db_get(self, request, model_name, pk): """ As part of the REST API, return a specific instance of the given model with the given pk. """ # get model try: model = get_class_from_string(model_name) except: return self._db_error('Unknown model.') # get instance try: qs = model.objects.filter(pk=pk) instance = Acl.of(model).filter(request, qs)[0] except: return self._db_error('Unknown pk.') # result return { 'success': True, 'message': 'OK', 'result': model_to_dict(instance, exclude_many_to_many=True, json=True) }
def test_model_to_dict_should_only_return_fields_in_the_schema(self): self.instance.foo = 'bar' self.instance.save() def _model_to_dict_does_not_contain_field(): model_to_dict(self.instance)['foo'] self.assertEqual(len(model_to_dict(self.instance)), 4) self.assertRaises(KeyError, _model_to_dict_does_not_contain_field)
def test_model_to_dict_should_return_reverse_fields_if_specified(self): m = TestModelWithManyToMany(id=1, title='Foo') m.save() try: d = model_to_dict(m, fetch_related=True) self.assertIsInstance(d.get('pages'), QuerySet) self.assertEqual(1, d.get('id')) self.assertEqual('Foo', d.get('title')) finally: m.delete()
def db_get_all(self, request, model_name): """ As part of the REST API, return a list of all model instances. """ # get model try: model = get_class_from_string(model_name) except: return self._db_error('Unknown model.') # get list qs = model.objects.all() instances = Acl.of(model).filter(request, qs) result = [ model_to_dict(instance, exclude_many_to_many=True, json=True) for instance in instances ] # result return {'success': True, 'message': 'OK', 'result': result}
def sku(self, request): # get product product_id = request.GET.get('pk') product = get_object_or_404(get_product_model(), pk=product_id) # get varieties _varieties = Variety.objects.prefetch_related( Prefetch('options', queryset=VarietyOption.objects.order_by('title')) ).filter(sku=True).exclude(options=None).exclude( style=Variety.STYLE_ATTRIBUTE).order_by('title').distinct() skus = ProductSKU.objects.filter(product=product) assigned_option_ids = [ a.variety_option.id for a in VarietyAssignment.objects.select_related('variety_option') .filter(product=product, variety_option__variety__sku=True) ] # initial dataset currently present initial = {} for sku in skus: initial[sku.pk] = sku initial[sku.pk].errors = [] # determine barcode system cms_settings = get_cms_settings() barcode_system = cms_settings.get_barcode_system(product) # create template form form_template = ProductSKUForm() form_template.configure(request, barcode_system) def has_var(prefix, name): return 'f-%s-%s' % (prefix, name) in request.POST def get_var(prefix, name, default=None): return request.POST.get('f-%s-%s' % (prefix, name), default) def get_int_var(prefix, name, default=None): return parse_int(get_var(prefix, name), default) # construct list of variety option names varieties = [] variety_index = {} for variety in _varieties: variety_index[variety.id] = { 'id': variety.id, 'title': variety.title, 'sku': variety.sku, 'options': {} } item = { 'id': variety.id, 'title': variety.title, 'sku': variety.sku, 'options': [], 'n_assigned_options': 0 } for option in variety.options.all(): variety_index[variety.id].get('options')[option.id] = { 'id': option.id, 'title': option.title, 'fullTitle': '%s: <em>%s</em>' % (variety.title, option.title) } item.get('options').append({ 'id': option.id, 'title': option.title, 'assigned': option.id in assigned_option_ids }) if option.pk in assigned_option_ids: item['n_assigned_options'] += 1 varieties.append(item) # sort varieties by number of assigned options, so that varieties that # have been assigned are at the top of the list. The rest remains sorted # alphabetically... varieties.sort(key=lambda x: -x.get('n_assigned_options', 0)) # validation is_valid = True if request.method == 'POST': # process sku records prefixes = request.POST.getlist('skus') assigned_option_ids = [] skus_to_save = [] sku_code_processed = [] barcodes_processed = [] for index, prefix in enumerate(prefixes): # extract relevant informatioin from post for # individual combination _id = get_var(prefix, '_id') d = { 'enabled': get_var(prefix, 'enabled') == 'on', 'sku': get_var(prefix, 'sku'), 'barcode': get_var(prefix, 'barcode'), 'price': get_var(prefix, 'price'), 'stocklevel': get_int_var(prefix, 'stocklevel', 0) } # parse assigned variety options from request data n_variety_option = 1 d['variety_options'] = [] while len(d['variety_options']) <= 16: _name = 'vo_%d' % n_variety_option if has_var(prefix, _name): d['variety_options'].append(get_int_var(prefix, _name)) n_variety_option += 1 else: break # make sure that sku, barcode and price are None # instead of empty if _id == '': _id = None if d.get('sku') == '': d['sku'] = None if d.get('barcode') == '': d['barcode'] = None if d.get('price') == '': d['price'] = None # construct form based on this data and validate form = ProductSKUForm(d) form.configure(request, barcode_system) # get variety options variety_options = VarietyOption.objects.filter( pk__in=d.get('variety_options')) # create or edit? sku = initial.get(_id, None) if sku is None: sku = ProductSKU.objects.get_by_variety_options( product, variety_options) # still not found? -> create new item if sku is None: sku = ProductSKU() sku.product = product # remember the sku record to be saved once we processed # everything. We will not save anything until everything # is considered to be valid. skus_to_save.append(sku) # mark any assigned variety options as selected, so that they # indeed remain selected, even if they have actually not been # properly assigned yet because if from errors for example for _variety in varieties: _options = _variety.get('options') for _option in _options: for _assigned_option in variety_options: if _option.get('id') == _assigned_option.pk: _option['assigned'] = True break # inject error information and keep track of error states sku.errors = [] if form.is_valid(): # update data from from d = form.cleaned_data else: for field, error in form.errors.items(): sku.errors.append({'field': field, 'error': error[0]}) is_valid = False # copy original data or cleaned data sku.enabled = d.get('enabled', False) sku.sku = d.get('sku') sku.barcode = d.get('barcode') sku.price = d.get('price') sku.stocklevel = d.get('stocklevel', 0) # keep track of variety options that should be assigned due to # SKU's that are enabled if sku.enabled: assigned_option_ids.extend( [option.pk for option in variety_options]) # set variety options (saved later) sku._variety_options = variety_options # verify uniqueness of the SKU code if not self._verify_sku(product, sku, sku_code_processed, initial): is_valid = False # verify uniqueness of barcode if not self._verify_barcode(product, sku, barcodes_processed, initial): is_valid = False # maintain changed data in initial data set, so that all # changes make theire way back into the view, even through # we might not have saved changes due to errors _id = ('idx_%d' % index) if sku.pk is None else sku.pk initial[_id] = sku # process if everything is valid if request.method == 'POST' and is_valid: # create missing option assignments assigned_option_ids = list( set(filter(lambda x: x is not None, assigned_option_ids))) for option_id in assigned_option_ids: try: assignment = VarietyAssignment.objects.get( product=product, variety_option__pk=option_id) except VarietyAssignment.DoesNotExist: VarietyAssignment.objects.create( product=product, variety_option_id=option_id) # remove deprecated option assignments deprecated_assignments = VarietyAssignment.objects.select_related( 'variety_option').filter( product=product, variety_option__variety__sku=True).exclude( variety_option__pk__in=assigned_option_ids) for deprecated_assignment in deprecated_assignments: deprecated_assignment.delete() # save changes to sku records. Null sku, so that we would not # collide when making updates sku_ids_saved = [] for sku in skus_to_save: # save product sku itself sku._sku = sku.sku sku.sku = None sku.save() sku_ids_saved.append(sku.id) # assign and save variety options sku.variety_options = sku._variety_options # remove all previous SKU deprecated_skus = ProductSKU.objects.filter( product=product).exclude(pk__in=sku_ids_saved) for deprecated_sku in deprecated_skus: deprecated_sku.delete() # apply new sku names, which is now safe to do for sku in skus_to_save: if request.settings.sku_is_barcode: sku.sku = sku.barcode else: sku.sku = sku._sku sku.save() # redirect and message if request.method == 'POST' and is_valid: messages.add_message( request, messages.SUCCESS, 'Product Varieties and SKUs saved for <em>%s</em>.' % product.title) if request.POST.get('cubane_save_and_continue') is None: return self._redirect(request, 'index') else: return self._redirect(request, 'sku', product) # materialise current initial data _initial = {} for _id, _sku in initial.items(): _initial[_id] = model_to_dict(_sku) if _sku.pk is None: _initial[_id]['variety_options'] = [ option.pk for option in _sku._variety_options ] else: _initial[_id]['variety_options'] = [ option.pk for option in _sku.variety_options.all() ] _initial[_id]['errors'] = _sku.errors if hasattr(_sku, 'errors') else [] # template context return { 'product': product, 'varieties': varieties, 'initial': to_json(_initial), 'variety_index_json': to_json(variety_index), 'form_template': form_template }
def _model_to_dict_does_not_contain_field(): model_to_dict(self.instance)['foo']
def test_model_to_dict_should_return_correct_fields(self): self.assertEqual(len(model_to_dict(self.instance)), 4)
def test_model_to_dict_should_return_dict(self): self.assertIsInstance(model_to_dict(self.instance), dict)