def __init__(self, **kwargs): # make sure we have at least one required key valid_response = False for k in [ 'results', 'modal', 'toast', 'html' ]: if k in kwargs: valid_response = True break if not valid_response: raise Exception('AJAX mixed response requested but no recognized response types provided') # validate each of our possible sub-keys and # make sure they're JSON-able if 'modal' in kwargs: modal = kwargs['modal'] if 'code' not in modal or 'message' not in modal: raise Exception('AJAX modal response requested but code and message values are required') # JSON-safe the acceptable bits attrs = [ 'code', 'title', 'message' ] if 'size' in modal and modal['size'] != None: # NOTE: we ignore size if it's None as it confuses the JavaScript attrs.append('size') kwargs['modal'] = to_json(modal, attrs) if 'toast' in kwargs: toast_list = kwargs['toast'] if isinstance(toast_list, dict): toast_list = [ toast_list ] # a single dict is permitted, wrap as list for toast in toast_list: if 'duration' not in toast or 'html' not in toast: raise Exception('AJAX toast response requested but a toast is missing required duration or message values') kwargs['toast'] = to_json(toast_list) if 'html' in kwargs: html_list = kwargs['html'] for html in html_list: if 'id' not in html or 'html' not in html: raise Exception('AJAX HTML update response requested but an update is missing required id or html values') kwargs['html'] = to_json(html_list) # NOTE: we don't apply to_json() to any "results" # data, as we assume this is done by the calling # code in order to control object serialization # this value is a marker to the client-side code # that indicates it adheres to the correct JSON # response format kwargs['sculpt'] = 'ajax' super(AjaxMixedResponse, self).__init__(kwargs)
def __init__(self, response = None, **kwargs): if not response: response = to_json(kwargs, [ 'code', 'title', 'message' ]) if 'size' in kwargs: response['size'] = kwargs['size'] # this really should verify the required keys are present in the response # (code, title, message) super(AjaxErrorResponse, self).__init__({ 'sculpt': 'ajax', 'error' : response })
def __init__(self, form, last_field = None, focus_field = None, error = None): # check whether this is a partial validation response is_partial = last_field != None # we shouldn't do this unless we actually have form errors; # that would be a programming mistake # NOTE: we'll accept a partial-validation error-free state if not is_partial and not form._errors: raise Exception('attempt to return form errors when there are none') # we need to format the errors in the form in a way that # is suitable for our AJAX handler on the client # # NOTE: Django's method is that the ValidationError and # ErrorList classes should "know" how to format themselves, # but they left very little in the way of ability to # intelligently override that. Instead, we act as though # errors are collected into a well-defined format, and # the layer that returns these errors to the client is # responsible for correctly formatting them. # we walk the error list in field declaration order error_list = [] for name, field in form.fields.iteritems(): if name in form._errors: field_error_list = [] for message in form._errors[name]: field_error_list.append(force_text(message)) # use prefixed name so client side can find it error_list.append([ form.add_prefix(name), field.label, field_error_list ]) # now append the global errors name = '__all__' if name in form._errors: field_error_list = [] for message in form._errors[name]: field_error_list.append(force_text(message)) error_list.append([ None, None, field_error_list ]) # now that we have a formatted error list, return it results = { 'sculpt': 'ajax', 'form_error': error_list, } if is_partial: results['partial'] = { 'last_field': form.add_prefix(last_field), 'focus_field': form.add_prefix(focus_field), } if error != None: results['error'] = to_json(error, [ 'code', 'title', 'message' ]) # just these valid fields if 'size' in error: results['error']['size'] = error['size'] super(AjaxFormErrorResponse, self).__init__(results)