Mask and Tables display a collection of data that may belong to the database or not. Each of the data represented in the GUI that needs to partecipate to any updating/saving process should have it’s own handler that is a Field.
A Field is an entity that knows how to handle a piece of data, be it on the database (a field_name) or just in the GUI. It’s a layer that allows gui widget to be simpler and easier to interchange. As an example, both varchars and integers are normally displayed by a gtk.Entry: the entry.get_text() will retrieve in both cases a string, it’s the Field (IntegerField) that knows how to turn that string into an integer using the Field.clean_value() method. In more complex cases clean_value can return data computed from related records.
cthe field knows:
- if it belongs to the database (attribute persistent is True) and in case how it is defined ( i.e.: sqlalchemy property/column)
- if it is nullable/editable
- which widget must be used to represent it (see below, not requested)
- how to produce a formatted representation of the field.
It provides functions to
- set/get value
- get default value (but will not cope with server_side defaults)
- tell if it changed from the default
- clean value according to it’s logic: i.e. return a value of the correct type
- validate values (possibly according to other criteria)
The association between a database field and a Field is dome by FieldChooser, but you can force a particular Field when defining the model class setting the key field of the column’s info dictionary:
class MyClass(Base):
...
foo = Column(..., info={'field' : MyField})
A last method is to use on_pre_layout hook that allows to set sqlkit.Fields even on non persisted fields.
Currently there are a number of operation that require that the field know wich is the sqlwidget it is acting for. I’d like to loosen this connection in future but at present it’s used in the following situations:
In the meanwhile I add master to the Field via set_master() and add a widget to the Field via set_widget()
The costructor can be passed a dict of field_attributes
field_name: the name of the field
- nullable: True if field is nullable or False. The related widget will get a background color that
reflects the fact that it is required (currently yellow). This can be set at any time.
- editable: True if field is editable or False. The related widget will be set unsensitive. This can
be set at any time.
length: the desired length in chars
default: a possible default option
type: the python type
mapper: defined as None for field that are mapped
table: the SA Table object
column: the SA Column object
property: the SA Property - if any
fkey: the SA ForeignKey or None
pkey: True is field is a PRIMARY KEY or False
- widget: the widget used to represent it. May be sqlkit.widgets.mask.miniwidget or similar
- format: the format used to represent the field (numeric or date/time)
- locale: the locale to use to represent the field (numeric or date/time)
- DecimalFields also have precision/scale
- Varchar/TextFields also have blank=True/False (default: False). It determines if an empty string is a valid value. Empty strings are differerent from NULL values
This should provide a way to set the possible observers
validation based on the type should live here
possibly more validation may live here
see decimal to have an intro on formatting numbers
This class implements a way to determine which Field should be associated to each field_name in a mapper (used in setup_field_validation so that it can be easily overwritten). It’s important to understand that it already receives a gtkwidget from layoutgenerator; that widget has been set by introspection of the layout description and of the field in the database.
You can overwrite the decision of the field redefining the gui_field on a derived sqlwidget or passing it as argument (see code snippet 34):
class Movie(SqlMask):
gui_field_mapping = {'date_release' : VarcharField}
t = Movie(table='movie', dbproxy=db, layout=lay)
It’s up to the field defined in this way to be able to handle the type of data. This setting can be used to add field constraints (eg: mail address validation) or to completely change the widget that represent data.
A Field does not create a gtk widget to represent data. Layout definition is normally enought to create the correct GTK widget. If a gtk widget exists that represent a field, it is handled by a proxy called Miniwidget that offers a common interface to possbly different gtk widgets. If a MiniWidget exists the Field will instantiate it and set values thought it.
A notable exception to this rule is represented by any m2m/o2m relation, that in the layout is only present as a gtk.Alignment widget to which a children is added by mask.Widget.
Miniwidgets for all main types are provided.
Varchar fields will try to cast an empty value to None unless blank_ok is set in the field:
t.gui_field.field_name.blank_ok = True
or globally:
from sqlkit.widgets.common import fields fields.BLANK_OK = True
Default value for BLANK_OK is False.
This is only enforced for NEW records, for already persisted records the default behaviour is to let it as-is, to prevent a very annoying flood of dialog “do you want to save?” when you just need to browse some data.
Parameters: |
|
---|
Set the value
Parameters: |
|
---|
return a string representation of the value according to current locale value is a”cleaned” value
Parameter: | value – the value to be formatted (must already be casted to correct type) |
---|
return a value of the correct type, if needed parse it with locale parsers (numbers, date...)
Parameters: |
|
---|
This function is used while sorting a column
All other field inherit from Field
The field to represent Strings
The fields to handle interegers
The fields to handle floats
The fields to handle Numeric Fields
The fields to handle datets
A field to handle a set of allowed values. You set values in the info column dict or setting values. Setting info column’s key render to ‘enum’ triggers this field and a widget based on ComboBox. It doesn’t currently use Sqlalchemy Enum type as it’s not yet supported in sqlalchemy 0.5.
Imge field suitable for VarcharField that hold an image path and should be rendered as image (icon in tables). It’s never used when autoloading the database schema (no info on the database tells that a string represent an image path), it can be forced setting info values on the Column:
render: image
base_dir: a directory
thumbnail_size: tuple (width, height)
default_size: tuple (width height)
as in:
image = Column(String(100), info={'render' : 'image', 'base_dir' : '/path/to/images'}
Image field that can create a thumbnail and resize an image into jpeg/png format using gtk.gdk.pixbuf* functions
Return the path to the image
Parameters: |
|
---|
Set the value and -if needed- copy the image file inside base_dir possibly resizing it to default_size. When resizing the only possible format is jpeg and the name is changed accordingly.
Parameters: |
|
---|
Return a standard save path. You may want to customize it.
Parameters: |
|
---|
scale pixbuf image with the same ratio so that it fits into self.w/self.h
Parameters: |
|
---|
Create a thumbnail that will be used when rendering images in tables. Uses attribute thumbnail_size
Parameter: | filename – the filename to create a thumbnail for |
---|
Return a thumbnail path and create the thumbnail image, if it doesn’t already exists
Parameters: |
|
---|
Return the thumbnail name for filename using default size. Place the thumbnail in a subdir of image dir ‘.thumbnail’ used by get_thumbnail() and create_thumbnail(). The name contains the thumbail_size used to generate it.
Parameter: | filename – the complete filename of the image |
---|
A field to handle foreign keys
Add an object to fullfill the constraint on delete-orphan
This is not meant to be used directly, it is used by set_value() If you have a relation with a delete-orphan constraint that would complain that is not attached to anybody configure the Column adding in the info keyword the attach_instance key pointing to the property of the relation to be added.
In the demo you can find this example:
class Movie(Base):
__tablename__ = 'movie'
...
director_id = Column(Integer, ForeignKey('director.id'), nullable=False,
info={'attach_instance': 'director'})
class Director(Base):
__tablename__ = 'director'
...
movies = relation('Movie', backref='director', cascade='all, delete-orphan',)
Attaching a director_id via completion, requires that you attach a director instance as well.
A decorator that will handle standard cases: value is None, is a string or is already cleaned.
This is handy when building new Fields as it allows to keep the .clean_value method as simple as possible, i.e. no need to check for standard cases:
class CountMovies(fields.IntegerField):
'''
A field that counts the movies
'''
@fields.std_cleanup
def clean_value(self, value):
## missing a field_name attribute on obj the object itselt is passed
return len(value.movies)