def network_choice_node(): """Create a colander.SchemaNode() with a drop down to choose one of AssetNetworks.""" return colander.SchemaNode( # Convert selection widget UUIDs back to Customer objects UUIDForeignKeyValue(model=AssetNetwork, match_column="id"), title="Chain", # A SelectWidget with values lazily populated widget=network_choice_widget)
def map_standard_relationship(self, mode, request, node, model, name, rel) -> colander.SchemaNode: """Build a widget for choosing a relationship with target. The relationship must be foreign_key and the remote must offer ``uuid`` attribute which we use as a vocabulary key.. """ if isinstance(rel.argument, Mapper): # TODO: How to handle this kind of relationships return TypeOverridesHandling.drop if isinstance(rel.argument, _class_resolver): # Case from tutorialapp: # <RelationshipProperty at 0x1095a4438; question> # <class 'sqlalchemy.ext.declarative.clsregistry._class_resolver'> remote_model = rel.argument() else: remote_model = rel.argument # Get first column of the set for column in rel.local_columns: break # For now, we automatically deal with this only if the model provides uuid if hasattr(remote_model, "uuid"): dbsession = request.dbsession # TODO: We probably need a mechanism for system wide empty default label required = not column.nullable if mode in (EditMode.add, EditMode.edit): default_choice = "--- Choose one ---" else: default_choice = "(not set)" if required: missing = colander.required else: missing = None vocabulary = get_uuid_vocabulary_for_model(dbsession, remote_model, default_choice=default_choice) if rel.uselist: # Show out all relationships if mode == EditMode.show: return colander.SchemaNode(UUIDModelSet(remote_model), name=name, missing=missing, widget=deform.widget.CheckboxChoiceWidget(values=vocabulary)) else: # Select from a single relationship return colander.SchemaNode(UUIDForeignKeyValue(remote_model), name=name, missing=missing, widget=deform.widget.SelectWidget(values=vocabulary)) return TypeOverridesHandling.drop
class AssetSchema(colander.Schema): #: Human readable name name = colander.SchemaNode(colander.String()) #: The network this asset is in network = colander.SchemaNode( UUIDForeignKeyValue(model=AssetNetwork, match_column="id"), widget=defer_widget_values(deform.widget.SelectWidget, available_networks), ) #: Symbol how this asset is presented in tickers symbol = colander.SchemaNode(colander.String()) description = colander.SchemaNode(colander.String(), missing="") #: Markdown page telling about this asset long_description = colander.SchemaNode(colander.String(), description="Markdown formatted", missing="", widget=deform.widget.TextAreaWidget( rows=20, cols=80)) #: Ethereum address external_id = colander.SchemaNode(colander.String(), title="Address", validator=validate_ethereum_address, missing=None, description="0x hex string format") #: Number of units avaialble supply = colander.SchemaNode(colander.Decimal(), missing=None) #: What kind of asset is this asset_class = colander.SchemaNode( EnumValue(AssetClass), widget=deform.widget.SelectWidget(values=enum_values(AssetClass))) #: Workflow state of this asset state = colander.SchemaNode( EnumValue(AssetState), widget=deform.widget.SelectWidget(values=enum_values(AssetState))) other_data = colander.SchemaNode( JSONValue(), widget=JSONWidget(), description="JSON bag of attributes of the object", missing=dict) def dictify(self, obj: Asset) -> dict: """Serialize SQLAlchemy model instance to nested dictionary appstruct presentation.""" appstruct = dictify(self, obj, excludes=("long_description", "external_id")) # Convert between binary storage and human readable hex presentation appstruct["long_description"] = obj.other_data.pop( "long_description", "") if obj.external_id: appstruct["external_id"] = bin_to_eth_address(obj.external_id) else: appstruct["external_id"] = "" return appstruct def objectify(self, appstruct: dict, obj: Asset): """Store the dictionary data from the form submission on the object.""" objectify(self, appstruct, obj, excludes=("long_description", "external_id")) if not obj.other_data: # When creating the object JSON value may be None # instead of empty dict obj.other_data = {} # Special case of field stored inside JSON bag obj.other_data["long_description"] = appstruct["long_description"] # Convert between binary storage and human readable hex presentation if appstruct["external_id"]: obj.external_id = eth_address_to_bin(appstruct["external_id"])