def render(self, **kwargs): if fields._pk(self.model) != self._bound_pk and self.data is not None: msg = ("Primary key of model has changed since binding, " "probably due to sync()ing a new instance (from %r to %r). " "You can solve this by either binding to a model " "with the original primary key again, or by binding data to None.") raise exceptions.PkError(msg % (self._bound_pk, fields._pk(self.model))) engine = self.engine or config.engine if 'request' not in kwargs: kwargs['request'] = self._request if self.readonly: template = 'fieldset_readonly' else: template = 'fieldset' return engine(template, fieldset=self, **kwargs)
def update(self): request = self.request id = request.model_id fs = self.get_fieldset(suffix="Edit", id=id) event = events.BeforeRenderEvent(self.request.model_instance, self.request, fs=fs) alsoProvides(event, events.IBeforeEditRenderEvent) zope.component.event.objectEventNotify(event) if request.format == "json" and request.method == "PUT": data = json.load(request.body_file) elif request.content_type == "application/json": data = json.load(request.body_file) else: data = request.POST with_prefix = True if request.format == "json": with_prefix = bool(request.params.get("with_prefix")) fs = fs.bind(request=request, with_prefix=with_prefix) if self.validate(fs): fs.sync() self.sync(fs, id) self.session.flush() if request.format in ("html", "xhr"): if request.is_xhr or request.format == "xhr": return Response(content_type="text/plain") return exc.HTTPFound(location=request.fa_url(request.model_name, _pk(fs.model))) else: return self.render(fs=fs, status=0) if request.format == "html": return self.render(fs=fs, id=id) else: return self.render(fs=fs, status=1)
def list(self, modelname, format='html'): """List instances of a model type""" S = self.Session() grid = self._model_grids[modelname] query = S.query(grid.model.__class__) page = Page(query, page=int(request.GET.get('page', '1')), **self._paginate) if format == 'json': values = [] for item in page: pk = _pk(item) values.append((pk, url('view_model', pk))) return self.render_json(records=dict(values), page_count=page.page_count, page=page.page) grid = grid.bind(instances=page, session=None) clsnames = [ f.relation_type().__name__ for f in grid._fields.itervalues() if f.is_relation ] return self._engine('admin_list', c=c, grid=grid, page=page, clsnames=clsnames, modelname=modelname, custom_css=self._custom_css, custom_js=self._custom_js)
def listing(self, *args, **kwargs): request = self.request if request.format != 'json': return Base.listing(self, *args, **kwargs) page = self.get_page(**kwargs) fs = self.get_grid() fs = fs.bind(instances=page, request=self.request) columns = [] fields = [] total = 0 for field in fs.render_fields.values(): type = field.type.__class__.__name__.lower() columns.append(dict( dataIndex=field.name, header=field.label(), editor=dict(xtype=self.xtypes.get(type, '%sfield' % type)), width=160, fixed=False )) fields.append(dict(name=field.name, type=self.types.get(type, type))) values = [] for item in page: total = total+1 pk = _pk(item) fs._set_active(item) value = dict(id=pk, absolute_url=request.fa_url(request.model_name, request.format, pk)) value.update(fs.to_dict(with_prefix=bool(request.params.get('with_prefix')))) values.append(value) data = dict(columns=columns, metaData=dict(fields=fields, root='records', id='id'), records=values, success=True, total=total) return Response(self.encoder.encode(data), content_type='application/json')
def edit_link(): return lambda item: ''' <form action="%(url)s" method="GET" class="ui-grid-icon ui-widget-header ui-corner-all"> <input type="submit" class="ui-grid-icon ui-icon ui-icon-pencil" title="%(label)s" value="%(label)s" /> </form> ''' % dict(url=model_url('edit_%s' % self.member_name, id=_pk(item)), label=get_translator()('edit'))
def listing(self, **kwargs): """listing page""" page = self.get_page() fs = self.get_grid() fs = fs.bind(instances=page) fs.readonly = True if self.request.format == 'json': values = [] request = self.request for item in page: pk = _pk(item) fs._set_active(item) value = dict(id=pk, item_url=self.route_url(request.model_name, pk)) if 'jqgrid' in request.GET: fields = [_stringify(field.render_readonly()) for field in fs.render_fields.values()] value['cell'] = [pk] + fields else: value.update(dict([(field.key, field.model_value) for field in fs.render_fields.values()])) values.append(value) return self.render_json_format(rows=values, records=len(values), total=page.page_count, page=page.page) if 'pager' not in kwargs: pager = page.pager(**self.pager_args) else: pager = kwargs.pop('pager') return self.render_grid(fs=fs, id=None, pager=pager)
def bind(self, model=None, session=None, data=None, request=None): """Bind to an instance""" self._request = request if not (model or session or data): raise Exception( 'must specify at least one of {model, session, data}') if not model: if not self.model: raise Exception( 'model must be specified when none is already set') model = fields._pk( self.model) is None and self._original_cls or self.model # copy.copy causes a stacktrace on python 2.5.2/OSX + pylons. unable to reproduce w/ simpler sample. mr = object.__new__(self.__class__) mr.__dict__ = dict(self.__dict__) # two steps so bind's error checking can work mr.rebind(model, session, data) mr._fields = OrderedDict([ (key, renderer.bind(mr)) for key, renderer in self._fields.iteritems() ]) if self._render_fields: mr._render_fields = OrderedDict([ (field.key, field) for field in [field.bind(mr) for field in self._render_fields.itervalues()] ]) return mr
def __init__(self, model, **kwargs): BaseFieldSet.__init__(self, model, **kwargs) if model is not None and isinstance(model, schema.Document): BaseFieldSet.rebind(self, model.__class__, data=kwargs.get('data', None)) self.doc = model.__class__ self.model = model self._bound_pk = fields._pk(model) else: BaseFieldSet.rebind(self, model, data=kwargs.get('data', None)) self.doc = model values = self.doc._properties.values() values.sort(lambda a, b: cmp(a.creation_counter, b.creation_counter)) for v in values: if getattr(v, 'name'): k = v.name sch = None if isinstance(v, schema.SchemaListProperty): t = fatypes.List sch = v._schema elif isinstance(v, schema.SchemaProperty): t = fatypes.String sch = v._schema else: try: t = getattr(fatypes, v.__class__.__name__.replace('Property','')) except AttributeError: raise NotImplementedError('%s is not mapped to a type for field %s (%s)' % (v.__class__, k, v.__class__.__name__)) self.append(Field(name=k, type=t, schema=sch)) if v.required: self._fields[k].validators.append(validators.required)
def update(self, **kwargs): """REST api""" request = self.request S = self.Session() id = request.model_id fs = self.get_fieldset(id) if not request.POST: raise ValueError(request.POST) fs = fs.bind(data=request.POST) if fs.validate(): fs.sync() self.sync(fs, id) S.flush() if request.format == 'html': if request.is_xhr: response.content_type = 'text/plain' return '' return exc.HTTPFound( location=self.route_url(request.model_name, _pk(fs.model))) else: return self.render(fs=fs, status=0) if request.format == 'html': return self.render(fs=fs, action='edit', id=id) else: return self.render(fs=fs, status=1)
def edit_link(): return lambda item: ''' <form action="%(url)s" method="GET" class="ui-grid-icon ui-widget-header ui-corner-all"> <input type="submit" class="ui-grid-icon ui-icon ui-icon-pencil" title="%(label)s" value="%(label)s" /> </form> ''' % dict(url=self.request.fa_url(self.request.model_name, _pk(item), 'edit'), label=get_translator(request=self.request)('edit'))
def update(self): request = self.request id = request.model_id fs = self.get_fieldset(suffix='Edit', id=id) event = events.BeforeRenderEvent(self.request.model_instance, self.request, fs=fs) alsoProvides(event, events.IBeforeEditRenderEvent) zope.component.event.objectEventNotify(event) fs = fs.bind(request=request) if self.validate(fs): fs.sync() self.sync(fs, id) self.session.flush() if request.format in ('html', 'xhr'): if request.is_xhr or request.format == 'xhr': return Response(content_type='text/plain') return exc.HTTPFound( location=request.fa_url(request.model_name, _pk(fs.model))) else: return self.render(fs=fs, status=0) if request.format == 'html': return self.render(fs=fs, id=id) else: return self.render(fs=fs, status=1)
def delete_link(): return lambda item: ''' <form action="%(url)s" method="POST" class="ui-grid-icon ui-state-error ui-corner-all"> <input type="submit" class="ui-icon ui-icon-circle-close" title="%(label)s" value="%(label)s" /> </form> ''' % dict(url=self.request.fa_url(self.request.model_name, _pk(item), 'delete'), label=get_translator(request=self.request)('delete'))
def bind(self, model=None, session=None, data=None): """ Return a copy of this FieldSet or Grid, bound to the given `model`, `session`, and `data`. The parameters to this method are the same as in the constructor. Often you will create and `configure` a FieldSet or Grid at application startup, then `bind` specific instances to it for actual editing or display. """ if not (model or session or data): raise Exception('must specify at least one of {model, session, data}') if not model: if not self.model: raise Exception('model must be specified when none is already set') model = fields._pk(self.model) is None and type(self.model) or self.model # copy.copy causes a stacktrace on python 2.5.2/OSX + pylons. unable to reproduce w/ simpler sample. mr = object.__new__(self.__class__) mr.__dict__ = dict(self.__dict__) # two steps so bind's error checking can work ModelRenderer.rebind(mr, model, session, data) mr._fields = OrderedDict([(key, renderer.bind(mr)) for key, renderer in self._fields.iteritems()]) if self._render_fields: mr._render_fields = OrderedDict([(field.key, field) for field in [field.bind(mr) for field in self._render_fields.itervalues()]]) return mr
def index(self, format='html', **kwargs): """REST api""" page = self.get_page() fs = self.get_grid() fs = fs.bind(instances=page) fs.readonly = True if format == 'json': values = [] for item in page: pk = _pk(item) fs._set_active(item) value = dict(id=pk, item_url=model_url(self.member_name, id=pk)) if 'jqgrid' in request.GET: fields = [_stringify(field.render_readonly()) for field in fs.render_fields.values()] value['cell'] = [pk] + fields else: value.update(dict([(field.key, field.model_value) for field in fs.render_fields.values()])) values.append(value) return self.render_json_format(rows=values, records=len(values), total=page.page_count, page=page.page) if 'pager' not in kwargs: pager = page.pager(**self.pager_args) else: pager = kwargs.pop('pager') return self.render_grid(format=format, fs=fs, id=None, pager=pager)
def listing(self, **kwargs): """listing page""" page = self.get_page(**kwargs) fs = self.get_grid() fs = fs.bind(instances=page, request=self.request) fs.readonly = True event = events.BeforeRenderEvent(self.request.model_class(), self.request, fs=fs, page=page) alsoProvides(event, events.IBeforeListingRenderEvent) zope.component.event.objectEventNotify(event) if self.request.format == 'json': values = [] request = self.request for item in page: pk = _pk(item) fs._set_active(item) value = dict(id=pk, absolute_url=request.fa_url(request.model_name, pk)) if 'jqgrid' in request.GET: fields = [_stringify(field.render_readonly()) for field in fs.render_fields.values()] value['cell'] = [pk] + fields else: value.update(fs.to_dict(with_prefix=bool(request.params.get('with_prefix')))) values.append(value) return self.render_json_format(rows=values, records=len(values), total=page.page_count, page=page.page) if 'pager' not in kwargs: pager = page.pager(**self.pager_args) else: pager = kwargs.pop('pager') return self.render_grid(fs=fs, id=None, pager=pager)
def delete_link(): return lambda item: ''' <form action="%(url)s" method="POST" class="ui-grid-icon ui-state-error ui-corner-all"> <input type="submit" class="ui-icon ui-icon-circle-close" title="%(label)s" value="%(label)s" /> <input type="hidden" name="_method" value="DELETE" /> </form> ''' % dict(url=model_url(self.member_name, id=_pk(item)), label=get_translator()('delete'))
def delete_link(): return lambda item: '''<form action="%(url)sdelete/%(id)s" method="POST"> <input type="submit" class="icon delete" title="%(label)s" value="" /> <input type="hidden" name="_method" value="DELETE" /> </form> ''' % dict( url=model_URL, id=_pk(item), label=get_translator().gettext('delete'))
def delete_link(): return lambda item: ''' <form action="%(url)s" method="POST" class="ui-grid-icon ui-state-error ui-corner-all"> <input type="submit" class="ui-icon ui-icon-circle-close" title="%(label)s" value="%(label)s" /> </form> ''' % dict(url=self.request.fa_url(self.request.model_name, _pk(item), 'delete'), label=get_translator(request=self.request) ('delete'))
def render(self, **kwargs): if fields._pk(self.model) != self._bound_pk and self.data is not None: msg = ( "Primary key of model has changed since binding, " "probably due to sync()ing a new instance (from %r to %r). " "You can solve this by either binding to a model " "with the original primary key again, or by binding data to None." ) raise exceptions.PkError(msg % (self._bound_pk, fields._pk(self.model))) engine = self.engine or config.engine if 'request' not in kwargs: kwargs['request'] = self._request if self.readonly: template = 'fieldset_readonly' else: template = 'fieldset' return engine(template, fieldset=self, **kwargs)
def delete_link(): model_url = url('models', modelname=modelname) return lambda item: '''<form action="%(url)s/%(id)s" method="POST"> <input type="submit" class="icon delete" title="%(label)s" value="" /> <input type="hidden" name="_method" value="DELETE" /> </form> ''' % dict(url=model_url, id=_pk(item), label=get_translator().gettext( 'delete'))
def delete(self, modelname, id): """Delete an instance of the given model type""" F_ = get_translator().gettext fs = self._model_fieldsets[modelname] S = self.Session() instance = S.query(fs.model.__class__).get(id) key = _pk(instance) S.delete(instance) S.commit() message = F_(_("Deleted %s %s")) % (modelname.encode("utf-8", "ignore"), key) flash(message) redirect_to(controller=self._name, modelname=modelname, action="list", id=None)
def render(self, *args, **kwargs): html = super(Renderer, self).render(*args, **kwargs) fk_class = self.field.relation_type() model_name = fk_class.__name__ try: field_url = '%s.xhr?field=%s' % (model_url('model', id=fields._pk(self.field.model)), self.field.key) except GenerationException: field_url = '%s.xhr?field=%s' % (model_url('new_model'), self.field.key) new_url = '%s.xhr' % model_url('new_model', model_name=model_name) html += literal('<button class="new_relation_item" alt="%s" href="%s">New %s</button>' % ( field_url, new_url, model_name)) return html
def render_json(self, fs=None, **kwargs): response.content_type = 'text/javascript' if fs: fields = dict([(field.key, field.model_value) for field in fs.render_fields.values()]) data = dict(fields=fields) pk = _pk(fs.model) if pk: data['url'] = url('view_model', modelname=fs.model.__class__.__name__, id=pk) else: data = {} data.update(kwargs) return json.dumps(data)
def render_readonly(self, options=None, **kwargs): value = self.raw_value if value is None: return '' if not isinstance(value, list): if self.request.has_permission('view', value): return h.content_tag('a', self.stringify_value(value, as_html=True), href=self.request.fa_url(value.__class__.__name__, fields._pk(value))) else: return h.content_tag('span', self.stringify_value(value, as_html=True)) else: html = [] for item in value: if self.request.has_permission('view', item): html.append(h.content_tag('a', self.stringify_value(item, as_html=True), href=self.request.fa_url(item.__class__.__name__, fields._pk(item)))) else: html.append(h.content_tag('span', self.stringify_value(item, as_html=True))) return h.literal(', ').join(html)
def render(self, *args, **kwargs): html = super(Renderer, self).render(*args, **kwargs) pk = fields._pk(self.field.model) model_name = self.field.parent.model.__class__.__name__ if pk: field_url = '#root_url/%s/xhr/%s?field=%s' % (model_name, pk, self.field.key) else: field_url = '#root_url/%s/xhr?field=%s' % (model_name, self.field.key) fk_class = self.field.relation_type() model_name = fk_class.__name__ new_url = '#root_url/%s/xhr/new' % model_name html += literal('<button class="new_relation_item" alt="%s" href="%s">New %s</button>' % ( field_url, new_url, model_name)) return html
def render_json_format(self, fs=None, **kwargs): request = self.request request.override_renderer = "json" if fs is not None: data = fs.to_dict(with_prefix=request.params.get("with_prefix", False)) pk = _pk(fs.model) if pk: if "id" not in data: data["id"] = pk data["absolute_url"] = request.fa_url(request.model_name, "json", pk) else: data = {} data.update(kwargs) return data
def render_json_format(self, fs=None, **kwargs): request = self.request request.override_renderer = 'json' if fs is not None: data = fs.to_dict(with_prefix=request.params.get('with_prefix', False)) pk = _pk(fs.model) if pk: if 'id' not in data: data['id'] = pk data['absolute_url'] = request.fa_url(request.model_name, 'json', pk) else: data = {} data.update(kwargs) return data
def render(self, *args, **kwargs): html = super(Renderer, self).render(*args, **kwargs) pk = fields._pk(self.field.model) model_name = self.field.parent.model.__class__.__name__ request = self.request if pk: field_url = request.fa_url(model_name, 'xhr', pk, field=self.field.key) else: field_url = request.fa_url(model_name, 'xhr', field=self.field.key) fk_class = self.field.relation_type() model_name = fk_class.__name__ new_url = request.fa_url(model_name, 'xhr', 'new') html += literal('<button class="new_relation_item" alt="%s" href="%s">New %s</button>' % ( field_url, new_url, model_name)) return html
def render_json_format(self, fs=None, **kwargs): response.content_type = "text/javascript" if fs: try: fields = fs.jsonify() except AttributeError: fields = dict([(field.renderer.name, field.model_value) for field in fs.render_fields.values()]) data = dict(fields=fields) pk = _pk(fs.model) if pk: data["item_url"] = model_url(self.member_name, id=pk) else: data = {} data.update(kwargs) return json.dumps(data)
def render(self, *args, **kwargs): html = super(Renderer, self).render(*args, **kwargs) fk_class = self.field.relation_type() model_name = fk_class.__name__ try: field_url = '%s.xhr?field=%s' % (model_url( 'model', id=fields._pk(self.field.model)), self.field.key) except GenerationException: field_url = '%s.xhr?field=%s' % (model_url('new_model'), self.field.key) new_url = '%s.xhr' % model_url('new_model', model_name=model_name) html += literal( '<button class="new_relation_item" alt="%s" href="%s">New %s</button>' % (field_url, new_url, model_name)) return html
def render_json_format(self, fs=None, **kwargs): response.content_type = 'text/javascript' if fs: try: fields = fs.jsonify() except AttributeError: fields = dict([(field.renderer.name, field.model_value) for field in fs.render_fields.values()]) data = dict(fields=fields) pk = _pk(fs.model) if pk: data['item_url'] = model_url(self.member_name, id=pk) else: data = {} data.update(kwargs) return json.dumps(data)
def render_json_format(self, fs=None, **kwargs): request = self.request request.override_renderer = 'json' if fs: try: fields = fs.jsonify() except AttributeError: fields = dict([(field.renderer.name, field.model_value) for field in fs.render_fields.values()]) data = dict(fields=fields) pk = _pk(fs.model) if pk: data['item_url'] = request.route_url('fa_admin', traverse='%s/json/%s' % (self.model_name, pk)) else: data = {} data.update(kwargs) return data
def render_json_format(self, fs=None, **kwargs): request = self.request request.override_renderer = 'json' if fs is not None: data = fs.to_dict( with_prefix=request.params.get('with_prefix', False)) pk = _pk(fs.model) if pk: if 'id' not in data: data['id'] = pk data['absolute_url'] = request.fa_url(request.model_name, 'json', pk) else: data = {} data.update(kwargs) return data
def delete(self, modelname, id, format='html'): """Delete an instance of the given model type""" F_ = get_translator().gettext fs = self._model_fieldsets[modelname] S = self.Session() instance = S.query(fs.model.__class__).get(id) key = _pk(instance) S.delete(instance) S.commit() if format == 'html': message = F_(_('Deleted %s %s')) % (modelname.encode( 'utf-8', 'ignore'), key) flash(message) redirect(url('models', modelname=modelname)) else: return self.render_json(status=0)
def delete(self, modelname, id, format='html'): """Delete an instance of the given model type""" F_ = get_translator().gettext fs = self._model_fieldsets[modelname] S = self.Session() instance = S.query(fs.model.__class__).get(id) key = _pk(instance) S.delete(instance) S.commit() if format == 'html': message = F_(_('Deleted %s %s')) % (modelname.encode('utf-8', 'ignore'), key) flash(message) redirect(url('models', modelname=modelname)) else: return self.render_json(status=0)
def rebind(self, model, session=None, data=None): if model is not self.iface: if model and not self.iface.providedBy(model): if getattr(model, '__implemented__', None) is not None: raise ValueError('%r does not provide %r' % (model, self.iface)) model = self.gen_model(model) self.model = model self._bound_pk = fields._pk(model) if data is None: self.data = None elif hasattr(data, 'getall') and hasattr(data, 'getone'): self.data = data else: try: self.data = SimpleMultiDict(data) except: raise Exception('unsupported data object %s. currently only dicts and Paste multidicts are supported' % self.data)
def render(self, *args, **kwargs): html = super(Renderer, self).render(*args, **kwargs) pk = fields._pk(self.field.model) model_name = self.field.parent.model.__class__.__name__ if pk: field_url = '#root_url/%s/xhr/%s?field=%s' % (model_name, pk, self.field.key) else: field_url = '#root_url/%s/xhr?field=%s' % (model_name, self.field.key) fk_class = self.field.relation_type() model_name = fk_class.__name__ new_url = '#root_url/%s/xhr/new' % model_name html += literal( '<button class="new_relation_item" alt="%s" href="%s">New %s</button>' % (field_url, new_url, model_name)) return html
def bind(self, model, session=None, data=None): """Bind to an instance""" if not (model or session or data): raise Exception('must specify at least one of {model, session, data}') if not model: if not self.model: raise Exception('model must be specified when none is already set') model = fields._pk(self.model) is None and type(self.model) or self.model # copy.copy causes a stacktrace on python 2.5.2/OSX + pylons. unable to reproduce w/ simpler sample. mr = object.__new__(self.__class__) mr.__dict__ = dict(self.__dict__) # two steps so bind's error checking can work mr.rebind(model, session, data) mr._fields = OrderedDict([(key, renderer.bind(mr)) for key, renderer in self._fields.iteritems()]) if self._render_fields: mr._render_fields = OrderedDict([(field.key, field) for field in [field.bind(mr) for field in self._render_fields.itervalues()]]) return mr
def bind(self, model=None, session=None, data=None, request=None, with_prefix=True): """ Return a copy of this FieldSet or Grid, bound to the given `model`, `session`, and `data`. The parameters to this method are the same as in the constructor. Often you will create and `configure` a FieldSet or Grid at application startup, then `bind` specific instances to it for actual editing or display. """ if not (model is not None or session or data or request): raise Exception( 'must specify at least one of {model, session, data, request}') if not model: if not self.model: raise Exception( 'model must be specified when none is already set') model = fields._pk(self.model) is None and type( self.model) or self.model # copy.copy causes a stacktrace on python 2.5.2/OSX + pylons. unable to reproduce w/ simpler sample. mr = object.__new__(self.__class__) mr.__dict__ = dict(self.__dict__) # two steps so bind's error checking can work FieldSet.rebind(mr, model, session, data, request, with_prefix=with_prefix) mr._fields = OrderedDict([(key, renderer.bind(mr)) for key, renderer in self._fields.items()]) if self._render_fields: mr._render_fields = OrderedDict([ (field.key, field) for field in [field.bind(mr) for field in self._render_fields.values()] ]) mr._request = request return mr
def listing(self, **kwargs): """listing page""" page = self.get_page(**kwargs) fs = self.get_grid() fs = fs.bind(instances=page, request=self.request) fs.readonly = True event = events.BeforeRenderEvent(self.request.model_class(), self.request, fs=fs, page=page) alsoProvides(event, events.IBeforeListingRenderEvent) zope.component.event.objectEventNotify(event) if self.request.format == 'json': values = [] request = self.request for item in page: pk = _pk(item) fs._set_active(item) value = dict(id=pk, absolute_url=request.fa_url( request.model_name, pk)) if 'jqgrid' in request.GET: fields = [ _stringify(field.render_readonly()) for field in fs.render_fields.values() ] value['cell'] = [pk] + fields else: value.update( fs.to_dict(with_prefix=bool( request.params.get('with_prefix')))) values.append(value) return self.render_json_format(rows=values, records=len(values), total=page.page_count, page=page.page) if 'pager' not in kwargs: pager = page.pager(**self.pager_args) else: pager = kwargs.pop('pager') return self.render_grid(fs=fs, id=None, pager=pager)
def rebind(self, model, session=None, data=None): if model is not self.iface: if model and not self.iface.providedBy(model): if getattr(model, '__implemented__', None) is not None: raise ValueError('%r does not provide %r' % (model, self.iface)) model = self.gen_model(model) self.model = model self._bound_pk = fields._pk(model) if data is None: self.data = None elif hasattr(data, 'getall') and hasattr(data, 'getone'): self.data = data else: try: self.data = SimpleMultiDict(data) except: raise Exception( 'unsupported data object %s. currently only dicts and Paste multidicts are supported' % self.data)
def list(self, modelname, format='html'): """List instances of a model type""" S = self.Session() grid = self._model_grids[modelname] query = S.query(grid.model.__class__) page = Page(query, page=int(request.GET.get('page', '1')), **self._paginate) if format == 'json': values = [] for item in page: pk = _pk(item) values.append((pk, url('view_model', pk))) return self.render_json(records=dict(values), page_count=page.page_count, page=page.page) grid = grid.bind(instances=page, session=None) clsnames = [f.relation_type().__name__ for f in grid._fields.itervalues() if f.is_relation] return self._engine('admin_list', c=c, grid=grid, page=page, clsnames=clsnames, modelname=modelname, custom_css = self._custom_css, custom_js = self._custom_js)
def edit(self, modelname, id=None): """Edit (or create, if `id` is None) an instance of the given model type""" F_ = get_translator().gettext fs = self._model_fieldsets[modelname] S = self.Session() if id: instance = S.query(fs.model.__class__).get(id) c.fs = fs.bind(instance) title = "Edit" else: c.fs = fs.bind(fs.model.__class__, session=S) title = "New object" if request.method == "POST": c.fs = c.fs.bind(data=request.params) log.debug("saving %s w/ %s" % (c.fs.model.id, request.POST)) if c.fs.validate(): c.fs.sync() S.flush() if not id: # needed if the object does not exist in db if not object_session(c.fs.model): S.save(c.fs.model) message = _("Created %s %s") else: S.refresh(c.fs.model) message = _("Modified %s %s") S.commit() message = F_(message) % (modelname.encode("utf-8", "ignore"), _pk(c.fs.model)) flash(message) redirect_to(modelname=modelname, action="list", id=None) return self._engine( "admin_edit", c=c, action=title, id=id, controller=self._name, modelname=modelname, custom_css=self._custom_css, custom_js=self._custom_js, )
def update(self): request = self.request id = request.model_id fs = self.get_fieldset(suffix='Edit', id=id) event = events.BeforeRenderEvent(self.request.model_instance, self.request, fs=fs) alsoProvides(event, events.IBeforeEditRenderEvent) zope.component.event.objectEventNotify(event) if request.format == 'json' and request.method == 'PUT': data = json.load(request.body_file) elif request.content_type == 'application/json': data = json.load(request.body_file) else: data = request.POST with_prefix = True if request.format == 'json': with_prefix = bool(request.params.get('with_prefix')) fs = fs.bind(request=request, with_prefix=with_prefix) if self.validate(fs): fs.sync() self.sync(fs, id) self.session.flush() if request.format in ('html', 'xhr'): if request.is_xhr or request.format == 'xhr': return Response(content_type='text/plain') return exc.HTTPFound( location=request.fa_url(request.model_name, _pk(fs.model))) else: return self.render(fs=fs, status=0) if request.format == 'html': return self.render(fs=fs, id=id) else: return self.render(fs=fs, status=1)
def rebind(self, model=None, session=None, data=None): if model is not None and model is not self.doc: if not isinstance(model, self.doc): try: model = model() except Exception as e: raise Exception('''%s appears to be a class, not an instance, but FormAlchemy cannot instantiate it. (Make sure all constructor parameters are optional!) %r - %s''' % ( model, self.doc, e)) else: model = self.doc() self.model = model self._bound_pk = fields._pk(model) if data is None: self.data = None elif hasattr(data, 'getall') and hasattr(data, 'getone'): self.data = data else: try: self.data = SimpleMultiDict(data) except: raise Exception('unsupported data object %s. currently only dicts and Paste multidicts are supported' % self.data)
def edit(self, modelname, id=None, format='html'): """Edit (or create, if `id` is None) an instance of the given model type""" saved = 1 if id and id.endswith('.json'): id = id[:-5] format = 'json' if request.method == 'POST' or format == 'json': if id: prefix = '%s-%s' % (modelname, id) else: prefix = '%s-' % modelname if request.method == 'PUT': items = json.load(request.body_file).items() request.method = 'POST' elif '_method' not in request.POST: items = request.POST.items() format = 'json' else: items = None if items: for k, v in items: if not k.startswith(prefix): if isinstance(v, list): for val in v: request.POST.add('%s-%s' % (prefix, k), val) else: request.POST.add('%s-%s' % (prefix, k), v) fs = self._model_fieldsets[modelname] S = self.Session() if id: instance = S.query(fs.model.__class__).get(id) assert instance, id title = 'Edit' else: instance = fs.model.__class__ title = 'New object' if request.method == 'POST': F_ = get_translator().gettext c.fs = fs.bind(instance, data=request.POST, session=not id and S or None) if c.fs.validate(): c.fs.sync() S.flush() if not id: # needed if the object does not exist in db if not object_session(c.fs.model): S.add(c.fs.model) message = _('Created %s %s') else: S.refresh(c.fs.model) message = _('Modified %s %s') S.commit() saved = 0 if format == 'html': message = F_(message) % (modelname.encode( 'utf-8', 'ignore'), _pk(c.fs.model)) flash(message) redirect(url('models', modelname=modelname)) else: c.fs = fs.bind(instance, session=not id and S or None) if format == 'html': return self._engine('admin_edit', c=c, action=title, id=id, modelname=modelname, custom_css=self._custom_css, custom_js=self._custom_js) else: return self.render_json(fs=c.fs, status=saved, model=modelname)
def edit_link(): model_url = url('models', modelname=modelname) return lambda item: '<a href="%(url)s/%(id)s" title="%(label)s" class="icon edit">%(label)s</a>' % dict( url=model_url, id=_pk(item), label=get_translator().gettext('edit'))
def rebind(self, model=None, session=None, data=None, request=None, with_prefix=True): """ Like `bind`, but acts on this instance. No return value. Not all parameters are treated the same; specifically, what happens if they are NOT specified is different: * if `model` is not specified, the old model is used * if `session` is not specified, FA tries to re-guess session from the model * if `data` is not specified, it is rebound to None * if `request` is specified and not `data` request.POST is used as data. `request` is also saved to be access by renderers (as `fs.FIELD.renderer.request`). * if `with_prefix` is False then a prefix ``{Model}-{pk}`` is added to each data keys """ if data is None and request is not None: if hasattr(request, 'environ') and hasattr(request, 'POST'): if request.environ.get('REQUEST_METHOD', '').upper() == 'POST': data = request.POST or None original_model = model if model: if isinstance(model, type): try: model = model() except Exception as e: model_error = str(e) msg = ("%s appears to be a class, not an instance, but " "FormAlchemy cannot instantiate it. " "(Make sure all constructor parameters are " "optional!). The error was:\n%s") raise Exception(msg % (model, model_error)) # take object out of session, if present try: _obj_session = object_session(model) except (AttributeError, UnmappedInstanceError): pass # non-SA object; doesn't need session else: if _obj_session: _obj_session.expunge(model) else: try: session_ = object_session(model) except: # non SA class if fields._pk( model) is None and model is not self._original_cls: error = ( 'Mapped instances to be bound must either have ' 'a primary key set or not be in a Session. When ' 'creating a new object, bind the class instead ' '[i.e., bind(User), not bind(User())].') raise Exception(error) else: if session_: # for instances of mapped classes, require that the instance # have a PK already try: class_mapper(type(model)) except: pass else: if fields._pk(model) is None: error = ( 'Mapped instances to be bound must either have ' 'a primary key set or not be in a Session. When ' 'creating a new object, bind the class instead ' '[i.e., bind(User), not bind(User())]') raise Exception(error) if (self.model and type(self.model) != type(model) and not issubclass(model.__class__, self._original_cls)): raise ValueError( 'You can only bind to another object of the same type or subclass you originally bound to (%s), not %s' % (type(self.model), type(model))) self.model = model self._bound_pk = fields._pk(model) if data is not None and not with_prefix: if isinstance(data, multidict.UnicodeMultiDict): encoding = data.encoding else: encoding = config.encoding pk = fields._pk(self.model) or '' prefix = '%s-%s' % (self._original_cls.__name__, pk) if self._prefix: prefix = '%s-%s' % (self._prefix, prefix) data = SimpleMultiDict([('%s-%s' % (prefix, k), v) for k, v in data.items()], encoding=encoding) if data is None: self.data = None elif isinstance(data, multidict.UnicodeMultiDict): self.data = data elif isinstance(data, multidict.MultiDict): self.data = multidict.UnicodeMultiDict(multi=data, encoding=config.encoding) elif hasattr(data, 'getall') and hasattr(data, 'getone'): self.data = data elif isinstance(data, (dict, list)): self.data = SimpleMultiDict(data, encoding=config.encoding) else: raise Exception( 'unsupported data object %s. currently only dicts and Paste multidicts are supported' % self.data) if not self.__sa__: return if session: self.session = session elif model: if '_obj_session' in locals(): # model may be a temporary object, expunged from its session -- grab the existing reference self.session = _obj_session else: try: o_session = object_session(model) except (AttributeError, UnmappedInstanceError): pass # non-SA object else: if o_session: self.session = o_session # if we didn't just instantiate (in which case object_session will be None), # the session should be the same as the object_session if self.session and model == original_model: try: o_session = object_session(self.model) except (AttributeError, UnmappedInstanceError): pass # non-SA object else: if o_session and self.session is not o_session: raise Exception( 'You may not explicitly bind to a session when your model already belongs to a different one' )