/usr/share/pyshared/elixir/fields.py is in python-elixir 0.7.1-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 | '''
This module provides support for defining the fields (columns) of your
entities. Elixir currently supports two syntaxes to do so: the default
`Attribute-based syntax`_ as well as the has_field_ DSL statement.
Attribute-based syntax
----------------------
Here is a quick example of how to use the object-oriented syntax.
.. sourcecode:: python
class Person(Entity):
id = Field(Integer, primary_key=True)
name = Field(String(50), required=True)
ssn = Field(String(50), unique=True)
biography = Field(Text)
join_date = Field(DateTime, default=datetime.datetime.now)
photo = Field(Binary, deferred=True)
_email = Field(String(20), colname='email', synonym='email')
def _set_email(self, email):
self._email = email
def _get_email(self):
return self._email
email = property(_get_email, _set_email)
The Field class takes one mandatory argument, which is its type. Please refer
to SQLAlchemy documentation for a list of `types supported by SQLAlchemy
<http://www.sqlalchemy.org/docs/05/reference/sqlalchemy/types.html>`_.
Following that first mandatory argument, fields can take any number of
optional keyword arguments. Please note that all the **arguments** that are
**not specifically processed by Elixir**, as mentioned in the documentation
below **are passed on to the SQLAlchemy ``Column`` object**. Please refer to
the `SQLAlchemy Column object's documentation
<http://www.sqlalchemy.org/docs/05/reference/sqlalchemy/schema.html
#sqlalchemy.schema.Column>`_ for more details about other
supported keyword arguments.
The following Elixir-specific arguments are supported:
+-------------------+---------------------------------------------------------+
| Argument Name | Description |
+===================+=========================================================+
| ``required`` | Specify whether or not this field can be set to None |
| | (left without a value). Defaults to ``False``, unless |
| | the field is a primary key. |
+-------------------+---------------------------------------------------------+
| ``colname`` | Specify a custom name for the column of this field. By |
| | default the column will have the same name as the |
| | attribute. |
+-------------------+---------------------------------------------------------+
| ``deferred`` | Specify whether this particular column should be |
| | fetched by default (along with the other columns) when |
| | an instance of the entity is fetched from the database |
| | or rather only later on when this particular column is |
| | first referenced. This can be useful when one wants to |
| | avoid loading a large text or binary field into memory |
| | when its not needed. Individual columns can be lazy |
| | loaded by themselves (by using ``deferred=True``) |
| | or placed into groups that lazy-load together (by using |
| | ``deferred`` = `"group_name"`). |
+-------------------+---------------------------------------------------------+
| ``synonym`` | Specify a synonym name for this field. The field will |
| | also be usable under that name in keyword-based Query |
| | functions such as filter_by. The Synonym class (see the |
| | `properties` module) provides a similar functionality |
| | with an (arguably) nicer syntax, but a limited scope. |
+-------------------+---------------------------------------------------------+
has_field
---------
The `has_field` statement allows you to define fields one at a time.
The first argument is the name of the field, the second is its type. Following
these, any number of keyword arguments can be specified for additional
behavior. The following arguments are supported:
+-------------------+---------------------------------------------------------+
| Argument Name | Description |
+===================+=========================================================+
| ``through`` | Specify a relation name to go through. This field will |
| | not exist as a column on the database but will be a |
| | property which automatically proxy values to the |
| | ``attribute`` attribute of the object pointed to by the |
| | relation. If the ``attribute`` argument is not present, |
| | the name of the current field will be used. In an |
| | has_field statement, you can only proxy through a |
| | belongs_to or an has_one relationship. |
+-------------------+---------------------------------------------------------+
| ``attribute`` | Name of the "endpoint" attribute to proxy to. This |
| | should only be used in combination with the ``through`` |
| | argument. |
+-------------------+---------------------------------------------------------+
Here is a quick example of how to use ``has_field``.
.. sourcecode:: python
class Person(Entity):
has_field('id', Integer, primary_key=True)
has_field('name', String(50))
'''
from sqlalchemy import Column
from sqlalchemy.orm import deferred, synonym
from sqlalchemy.ext.associationproxy import association_proxy
from elixir.statements import ClassMutator
from elixir.properties import Property
__doc_all__ = ['Field']
class Field(Property):
'''
Represents the definition of a 'field' on an entity.
This class represents a column on the table where the entity is stored.
'''
def __init__(self, type, *args, **kwargs):
super(Field, self).__init__()
self.colname = kwargs.pop('colname', None)
self.synonym = kwargs.pop('synonym', None)
self.deferred = kwargs.pop('deferred', False)
if 'required' in kwargs:
kwargs['nullable'] = not kwargs.pop('required')
self.type = type
self.primary_key = kwargs.get('primary_key', False)
self.column = None
self.property = None
self.args = args
self.kwargs = kwargs
def attach(self, entity, name):
# If no colname was defined (through the 'colname' kwarg), set
# it to the name of the attr.
if self.colname is None:
self.colname = name
super(Field, self).attach(entity, name)
def create_pk_cols(self):
if self.primary_key:
self.create_col()
def create_non_pk_cols(self):
if not self.primary_key:
self.create_col()
def create_col(self):
self.column = Column(self.colname, self.type,
*self.args, **self.kwargs)
self.add_table_column(self.column)
def create_properties(self):
if self.deferred:
group = None
if isinstance(self.deferred, basestring):
group = self.deferred
self.property = deferred(self.column, group=group)
elif self.name != self.colname:
# if the property name is different from the column name, we need
# to add an explicit property (otherwise nothing is needed as it's
# done automatically by SA)
self.property = self.column
if self.property is not None:
self.add_mapper_property(self.name, self.property)
if self.synonym:
self.add_mapper_property(self.synonym, synonym(self.name))
def has_field_handler(entity, name, *args, **kwargs):
if 'through' in kwargs:
setattr(entity, name,
association_proxy(kwargs.pop('through'),
kwargs.pop('attribute', name),
**kwargs))
return
field = Field(*args, **kwargs)
field.attach(entity, name)
has_field = ClassMutator(has_field_handler)
|