def __init__(self, *args, **kw): super(CompositeField, self).__init__(*args, **kw) if not self.fields: raise ValueError('Fields are required for composite field.') if not isinstance(self.fields, Fieldset): self.fields = Fieldset(*self.fields) self.fields.prefix = '%s.' % self.name
def __init__(self, *args, **kw): super(OptionsField, self).__init__(*args, **kw) voc = vocabulary.Vocabulary( *[vocabulary.Term(fname, fname, field.title) for fname, field in self.fields.items()]) if not self.key: self.key = self.name self.fields = Fieldset( RadioField( self.key, missing = voc[0].value, default = voc[0].value, required = False, vocabulary = voc)) + self.fields
def __init__(self, context, request, **kw): self.__dict__.update(kw) self.context = context self.request = request self.__parent__ = context if self.buttons is None: self.buttons = Buttons() # convert fields to Fieldset if not isinstance(self.fields, Fieldset): self.fields = Fieldset(*self.fields) # set tmpl_widget for fieldset in self.fields.fieldsets(): for field in fieldset.fields(): if field.cls.tmpl_widget is None: field.cls.tmpl_widget = self.tmpl_widget
def __init__(self, *args, **kw): super(CompositeField, self).__init__(*args, **kw) if not self.fields: raise ValueError('Fields are required for composite field.') if not isinstance(self.fields, Fieldset): self.fields = Fieldset(*self.fields) self.fields.prefix = '%s.'%self.name
class Form(object): """ A form ``id``: Form id ``name``: Form name ``label``: Form label ``description``: Form description ``prefix``: Form prefix, it used for html elements `id` generations. ``fields``: Form fields :py:class:`ptah.form.Fieldset` ``buttons``: Form buttons :py:class:`ptah.form.Buttons` ``actions``: Instance of :py:class:`ptah.form.Actions` class ``widgets``: Instance of :py:class:`FormWidgets` class ``content``: Form content, it should be `None` or dictionary with data for fields. ``params``: Form request parameters ``action``: Form action, by default ``request.url`` ``method``: HTML Form method (`post`, `get`) ``csrf``: Enable/disable form csrf protection ``csrf_name``: Form csrf field name ``csrf_token``: Form csrf token value """ label = None description = '' prefix = 'form.' actions = None widgets = None buttons = None fields = Fieldset() content = None method = 'post' enctype = 'multipart/form-data' accept = None accept_charset = 'utf-8' params = None context = None klass = 'form-horizontal' csrf = False csrf_name = 'csrf-token' csrf_token = '' tmpl_view = 'form:form' tmpl_actions = 'form:form-actions' tmpl_widget = 'form:widget' __name__ = '' __parent__ = None __view_mapper__ = FormViewMapper def __init__(self, context, request, **kw): self.__dict__.update(kw) self.context = context self.request = request self.__parent__ = context if self.buttons is None: self.buttons = Buttons() # convert fields to Fieldset if not isinstance(self.fields, Fieldset): self.fields = Fieldset(*self.fields) # set tmpl_widget for fieldset in self.fields.fieldsets(): for field in fieldset.fields(): if field.cls.tmpl_widget is None: field.cls.tmpl_widget = self.tmpl_widget @reify def id(self): return self.name.replace('.', '-') @reify def name(self): return self.prefix.strip('.') @reify def action(self): return self.request.url @reify def csrf_token(self): return self.request.session.get_csrf_token() def form_content(self): """ Return form content. By default it returns ``Form.content`` attribute. """ return self.content def form_params(self): """ get form request params """ if self.params is not None: if not isinstance(self.params, MultiDict): return MultiDict(self.params) return self.params if self.method == 'post': return self.request.POST elif self.method == 'get': return self.request.GET else: return self.params def update_widgets(self): """ prepare form widgets """ self.widgets = FormWidgets(self.fields, self, self.request) self.widgets.update() def update_actions(self): """ Prepare form actions, this method should be called directly. ``Form.update`` calls this method during initialization.""" self.actions = Actions(self, self.request) self.actions.update() def update_form(self, data=None): """ update form """ if not self.content and data: self.content = data self.update_widgets() self.update_actions() ac_result = self.actions.execute() if IResponse.providedBy(ac_result): raise HTTPResponseIsReady(ac_result) result = self.update() if IResponse.providedBy(result): raise HTTPResponseIsReady(result) if result is None: result = {} if ac_result is not None: result.update(ac_result) return result def update(self): """ Update form """ return {} def render(self): """ render form """ return render(self.request, self.tmpl_view, self, actions=self.actions, widgets=self.widgets) def validate(self, data, errors): """ Custom form validation """ def validate_form(self, data, errors): """ Form validation """ self.validate_csrf_token() try: self.validate(data, errors) except Invalid as err: errors.append(err) def validate_csrf_token(self): """ csrf token validation """ if self.csrf: token = self.form_params().get(self.csrf_name, None) if token is not None: if self.csrf_token == token: return raise HTTPForbidden("Form authenticator is not found.") def extract(self): """ extract form values """ return self.widgets.extract() def add_error_message(self, msg): """ add form error message """ add_message(self.request, msg, 'form:error') def __call__(self): """ update form and render form to response """ try: result = self.update_form() except HTTPResponseIsReady as result: return result.args[0] except HTTPException as result: return result response = self.request.registry.queryAdapterOrSelf(result, IResponse) if response is not None: return response body = self.render() response = self.request.response if isinstance(body, bytes): response.body = body else: response.text = body return response
class CompositeField(Field): """ Composit field """ fields = None tmpl_input = 'form:composite' tmpl_widget = 'form:widget-composite' inline = False consolidate_errors = False def __init__(self, *args, **kw): super(CompositeField, self).__init__(*args, **kw) if not self.fields: raise ValueError('Fields are required for composite field.') if not isinstance(self.fields, Fieldset): self.fields = Fieldset(*self.fields) self.fields.prefix = '%s.'%self.name @reify def default(self): return dict( [(name, field.default if field.default is not null else field.missing) for name, field in self.fields.items()]) def bind(self, request, prefix, value, params, context=None): """ Bind field to value and request params """ if value in (null, None): value = {} clone = super(CompositeField, self).bind( request, prefix, value, params, context) clone.fields = self.fields.bind(request, value, params, '', context) return clone def set_id_prefix(self, prefix): self.id = ('%s%s'%(prefix, self.name)).replace('.', '-') prefix = '%s%s.'%(prefix, self.name) for name, field in self.fields.items(): field.set_id_prefix(prefix) def update(self): """ Update field, prepare field for rendering """ super(CompositeField, self).update() for field in self.fields.values(): field.update() def to_field(self, value): """ convert form value to field value """ result = {} errors = [] for name, val in value.items(): field = self.fields[name] try: result[name] = field.to_field(val) except Invalid as error: error.name = name errors.append(error) if field.error is None: field.error = error if errors: if self.consolidate_errors: raise CompositeError(errors[0].msg, field=self) else: raise CompositeError(field=self, errors=errors) return result def validate(self, value): """ validate value """ errors = [] for name, val in value.items(): field = self.fields[name] try: field.validate(val) except Invalid as error: error.name = name errors.append(error) if field.error is None: field.error = error if errors: if self.consolidate_errors: raise CompositeError(errors[0].msg, field=self) else: raise CompositeError(field=self, errors=errors) if self.validator is not None: self.validator(self, value) def extract(self): value = {} for name, field in self.fields.items(): val = field.extract() if val is null and field.missing is not null: val = copy.copy(field.missing) value[name] = val return value def flatten(self, value): for name, field in self.fields.items(): if field.flat and name in value: value.update(field.flatten(value.pop(name))) return value
class Form(object): """ A form ``id``: Form id ``name``: Form name ``label``: Form label ``description``: Form description ``prefix``: Form prefix, it used for html elements `id` generations. ``fields``: Form fields :py:class:`ptah.form.Fieldset` ``buttons``: Form buttons :py:class:`ptah.form.Buttons` ``actions``: Instance of :py:class:`ptah.form.Actions` class ``widgets``: Instance of :py:class:`FormWidgets` class ``content``: Form content, it should be `None` or dictionary with data for fields. ``params``: Form request parameters ``action``: Form action, by default ``request.url`` ``method``: HTML Form method (`post`, `get`) ``csrf``: Enable/disable form csrf protection ``csrf_name``: Form csrf field name ``csrf_token``: Form csrf token value """ label = None description = '' prefix = 'form.' actions = None widgets = None buttons = None fields = Fieldset() content = None method = 'post' enctype = 'multipart/form-data' accept = None accept_charset = 'utf-8' params = None context = None klass = 'form-horizontal' csrf = False csrf_name = 'csrf-token' csrf_token = '' tmpl_view = 'form:form' tmpl_actions = 'form:form-actions' tmpl_widget = 'form:widget' __name__ = '' __parent__ = None __view_mapper__ = FormViewMapper def __init__(self, context, request, **kw): self.__dict__.update(kw) self.context = context self.request = request self.__parent__ = context if self.buttons is None: self.buttons = Buttons() # convert fields to Fieldset if not isinstance(self.fields, Fieldset): self.fields = Fieldset(*self.fields) # set tmpl_widget for fieldset in self.fields.fieldsets(): for field in fieldset.fields(): if field.cls.tmpl_widget is None: field.cls.tmpl_widget = self.tmpl_widget @reify def id(self): return self.name.replace('.', '-') @reify def name(self): return self.prefix.strip('.') @reify def action(self): return self.request.url @reify def csrf_token(self): return self.request.session.get_csrf_token() def form_content(self): """ Return form content. By default it returns ``Form.content`` attribute. """ return self.content def form_params(self): """ get form request params """ if self.params is not None: if not isinstance(self.params, MultiDict): return MultiDict(self.params) return self.params if self.method == 'post': return self.request.POST elif self.method == 'get': return self.request.GET else: return self.params def update_widgets(self): """ prepare form widgets """ self.widgets = FormWidgets(self.fields, self, self.request) self.widgets.update() def update_actions(self): """ Prepare form actions, this method should be called directly. ``Form.update`` calls this method during initialization.""" self.actions = Actions(self, self.request) self.actions.update() def update_form(self, data=None): """ update form """ if not self.content and data: self.content = data self.update_widgets() self.update_actions() ac_result = self.actions.execute() if IResponse.providedBy(ac_result): raise HTTPResponseIsReady(ac_result) result = self.update() if IResponse.providedBy(result): raise HTTPResponseIsReady(result) if result is None: result = {} if ac_result is not None: result.update(ac_result) return result def update(self): """ Update form """ return {} def render(self): """ render form """ return render(self.request, self.tmpl_view, self, actions = self.actions, widgets = self.widgets) def validate(self, data, errors): """ Custom form validation """ def validate_form(self, data, errors): """ Form validation """ self.validate_csrf_token() try: self.validate(data, errors) except Invalid as err: errors.append(err) def validate_csrf_token(self): """ csrf token validation """ if self.csrf: token = self.form_params().get(self.csrf_name, None) if token is not None: if self.csrf_token == token: return raise HTTPForbidden("Form authenticator is not found.") def extract(self): """ extract form values """ return self.widgets.extract() def add_error_message(self, msg): """ add form error message """ add_message(self.request, msg, 'form:error') def __call__(self): """ update form and render form to response """ try: result = self.update_form() except HTTPResponseIsReady as result: return result.args[0] except HTTPException as result: return result response = self.request.registry.queryAdapterOrSelf(result, IResponse) if response is not None: return response body = self.render() response = self.request.response if isinstance(body, bytes): response.body = body else: response.text = body return response
class OptionsField(CompositeField): """ Options field ``key``: Name of group key name ``defaults``: Build defaults for unselected groups ``extract_all``: Extract values for all groups """ key = '' defaults = False extract_all = False tmpl_input = 'form:options' def __init__(self, *args, **kw): super(OptionsField, self).__init__(*args, **kw) voc = vocabulary.Vocabulary( *[vocabulary.Term(fname, fname, field.title) for fname, field in self.fields.items()]) if not self.key: self.key = self.name self.fields = Fieldset( RadioField( self.key, missing = voc[0].value, default = voc[0].value, required = False, vocabulary = voc)) + self.fields def to_field(self, value): value = super(OptionsField, self).to_field(value) if self.defaults: for name, f in self.fields.items(): if name not in value: value[name] = (f.default if f.default is not null else f.missing) return value def validate(self, value): key = value.get(self.key) if key not in self.fields: key = self.fields[self.key].default super(OptionsField, self).validate( {key: value.get(key, self.fields[key].missing)}) def extract(self): value = super(OptionsField, self).extract() if not self.extract_all: opotion = value[self.key] if opotion in value: return {self.key: opotion, opotion: value[opotion]} else: return {} return value
class CompositeField(Field): """ Composit field """ fields = None tmpl_input = 'form:composite' tmpl_widget = 'form:widget-composite' inline = False consolidate_errors = False def __init__(self, *args, **kw): super(CompositeField, self).__init__(*args, **kw) if not self.fields: raise ValueError('Fields are required for composite field.') if not isinstance(self.fields, Fieldset): self.fields = Fieldset(*self.fields) self.fields.prefix = '%s.' % self.name @reify def default(self): return dict([ (name, field.default if field.default is not null else field.missing) for name, field in self.fields.items() ]) def bind(self, request, prefix, value, params, context=None): """ Bind field to value and request params """ if value in (null, None): value = {} clone = super(CompositeField, self).bind(request, prefix, value, params, context) clone.fields = self.fields.bind(request, value, params, '', context) return clone def set_id_prefix(self, prefix): self.id = ('%s%s' % (prefix, self.name)).replace('.', '-') prefix = '%s%s.' % (prefix, self.name) for name, field in self.fields.items(): field.set_id_prefix(prefix) def update(self): """ Update field, prepare field for rendering """ super(CompositeField, self).update() for field in self.fields.values(): field.update() def to_field(self, value): """ convert form value to field value """ result = {} errors = [] for name, val in value.items(): field = self.fields[name] try: result[name] = field.to_field(val) except Invalid as error: error.name = name errors.append(error) if field.error is None: field.error = error if errors: if self.consolidate_errors: raise CompositeError(errors[0].msg, field=self) else: raise CompositeError(field=self, errors=errors) return result def validate(self, value): """ validate value """ errors = [] for name, val in value.items(): field = self.fields[name] try: field.validate(val) except Invalid as error: error.name = name errors.append(error) if field.error is None: field.error = error if errors: if self.consolidate_errors: raise CompositeError(errors[0].msg, field=self) else: raise CompositeError(field=self, errors=errors) if self.validator is not None: self.validator(self, value) def extract(self): value = {} for name, field in self.fields.items(): val = field.extract() if val is null and field.missing is not null: val = copy.copy(field.missing) value[name] = val return value def flatten(self, value): for name, field in self.fields.items(): if field.flat and name in value: value.update(field.flatten(value.pop(name))) return value