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 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 self._render or self._render_readonly: warnings.warn(DeprecationWarning('_render and _render_readonly are deprecated and will be removed in 1.5. Use a TemplateEngine instead')) if self.readonly: if self._render_readonly is not None: engine._update_args(kwargs) return self._render_readonly(fieldset=self, **kwargs) return engine('fieldset_readonly', fieldset=self, **kwargs) if self._render is not None: engine._update_args(kwargs) return self._render(fieldset=self, **kwargs) return engine('fieldset', fieldset=self, **kwargs)
def rebind(self, model=None, session=None, data=None): """ 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. """ original_model = model if model: if isinstance(model, type): try: model = model() except Exception, 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: 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: 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)