mirror of
https://github.com/Infinidat/infi.clickhouse_orm.git
synced 2024-11-22 00:56:34 +03:00
documentation
This commit is contained in:
parent
27ee24843a
commit
64f8cde1c0
60
README.rst
60
README.rst
|
@ -32,9 +32,9 @@ Models are defined in a way reminiscent of Django's ORM:
|
|||
|
||||
engine = engines.MergeTree('birthday', ('first_name', 'last_name', 'birthday'))
|
||||
|
||||
It is possible to provide a default value for a field, instead of it's "natural" default (empty string for string fields, zero for numeric fields etc.).
|
||||
It is possible to provide a default value for a field, instead of its "natural" default (empty string for string fields, zero for numeric fields etc.).
|
||||
|
||||
See below for the supported model field types.
|
||||
See below for the supported field types and table engines.
|
||||
|
||||
Using Models
|
||||
------------
|
||||
|
@ -48,8 +48,8 @@ Once you have a model, you can create model instances:
|
|||
>>> dan.first_name
|
||||
u'Dan'
|
||||
|
||||
When values are assigned to a model fields, they are immediately converted to their Pythonic data type.
|
||||
In case the value is invalid, a ValueError is raised:
|
||||
When values are assigned to model fields, they are immediately converted to their Pythonic data type.
|
||||
In case the value is invalid, a ``ValueError`` is raised:
|
||||
|
||||
.. code:: python
|
||||
|
||||
|
@ -61,7 +61,10 @@ In case the value is invalid, a ValueError is raised:
|
|||
>>> suzy.birthday = '1922-05-31'
|
||||
ValueError: DateField out of range - 1922-05-31 is not between 1970-01-01 and 2038-01-19
|
||||
|
||||
To write your instances to ClickHouse, you need a Database instance:
|
||||
Inserting to the Database
|
||||
-------------------------
|
||||
|
||||
To write your instances to ClickHouse, you need a ``Database`` instance:
|
||||
|
||||
.. code:: python
|
||||
|
||||
|
@ -76,16 +79,53 @@ If necessary, you can specify a different database URL and optional credentials:
|
|||
|
||||
db = Database('my_test_db', db_url='http://192.168.1.1:8050', username='scott', password='tiger')
|
||||
|
||||
Using the Database instance you can create a table for your model, and insert instances to it:
|
||||
Using the ``Database`` instance you can create a table for your model, and insert instances to it:
|
||||
|
||||
.. code:: python
|
||||
|
||||
db.create_table(Person)
|
||||
db.insert([dan, suzy])
|
||||
|
||||
The insert method can take any iterable of model instances, but they all must belong to the same model class.
|
||||
The ``insert`` method can take any iterable of model instances, but they all must belong to the same model class.
|
||||
|
||||
Reading from the Database
|
||||
-------------------------
|
||||
|
||||
Loading model instances from the database is simple:
|
||||
|
||||
.. code:: python
|
||||
|
||||
for person in db.select("SELECT * FROM my_test_db.person", model_class=Person):
|
||||
print person.first_name, person.last_name
|
||||
|
||||
Do not include a ``FORMAT`` clause in the query, since the ORM automatically sets the format to ``TabSeparatedWithNamesAndTypes``.
|
||||
|
||||
It is possible to select only a subset of the columns, and the rest will receive their default values:
|
||||
|
||||
.. code:: python
|
||||
|
||||
for person in db.select("SELECT first_name FROM my_test_db.person WHERE last_name='Smith'", model_class=Person):
|
||||
print person.first_name
|
||||
|
||||
Specifying a model class is not required. In case you do not provide a model class, an ad-hoc class will
|
||||
be defined based on the column names and types returned by the query:
|
||||
|
||||
.. code:: python
|
||||
|
||||
for row in db.select("SELECT max(height) as max_height FROM my_test_db.person"):
|
||||
print row.max_height
|
||||
|
||||
Counting
|
||||
--------
|
||||
|
||||
The ``Database`` class also supports counting records easily:
|
||||
|
||||
.. code:: python
|
||||
|
||||
>>> db.count(Person)
|
||||
117
|
||||
>>> db.count(Person, conditions="height > 1.90")
|
||||
6
|
||||
|
||||
Field Types
|
||||
-----------
|
||||
|
@ -106,6 +146,10 @@ Currently the following field types are supported:
|
|||
- DateField
|
||||
- DateTimeField
|
||||
|
||||
Table Engines
|
||||
-------------
|
||||
|
||||
TBD
|
||||
|
||||
|
||||
Development
|
||||
|
@ -119,4 +163,4 @@ After cloning the project, run the following commands::
|
|||
|
||||
To run the tests, ensure that the ClickHouse server is running on http://localhost:8123/ (this is the default), and run::
|
||||
|
||||
bin/nosetests
|
||||
bin/nosetests
|
|
@ -17,6 +17,7 @@ class Database(object):
|
|||
self._send('CREATE DATABASE IF NOT EXISTS ' + db_name)
|
||||
|
||||
def create_table(self, model_class):
|
||||
# TODO check that model has an engine
|
||||
self._send(model_class.create_table_sql(self.db_name))
|
||||
|
||||
def drop_table(self, model_class):
|
||||
|
|
|
@ -15,23 +15,30 @@ class Field(object):
|
|||
self.default = default or self.class_default
|
||||
|
||||
def to_python(self, value):
|
||||
"""
|
||||
'''
|
||||
Converts the input value into the expected Python data type, raising ValueError if the
|
||||
data can't be converted. Returns the converted value. Subclasses should override this.
|
||||
"""
|
||||
'''
|
||||
return value
|
||||
|
||||
def validate(self, value):
|
||||
'''
|
||||
Called after to_python to validate that the value is suitable for the field's database type.
|
||||
Subclasses should override this.
|
||||
'''
|
||||
pass
|
||||
|
||||
def _range_check(self, value, min_value, max_value):
|
||||
'''
|
||||
Utility method to check that the given value is between min_value and max_value.
|
||||
'''
|
||||
if value < min_value or value > max_value:
|
||||
raise ValueError('%s out of range - %s is not between %s and %s' % (self.__class__.__name__, value, min_value, max_value))
|
||||
|
||||
def get_db_prep_value(self, value):
|
||||
"""
|
||||
'''
|
||||
Returns the field's value prepared for interacting with the database.
|
||||
"""
|
||||
'''
|
||||
return value
|
||||
|
||||
|
||||
|
|
|
@ -58,6 +58,10 @@ class Model(object):
|
|||
setattr(self, name, field.default)
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
'''
|
||||
When setting a field value, converts the value to its Pythonic type and validates it.
|
||||
This may raise a ValueError.
|
||||
'''
|
||||
field = self.get_field(name)
|
||||
if field:
|
||||
value = field.to_python(value)
|
||||
|
@ -65,15 +69,24 @@ class Model(object):
|
|||
super(Model, self).__setattr__(name, value)
|
||||
|
||||
def get_field(self, name):
|
||||
'''
|
||||
Get a Field instance given its name, or None if not found.
|
||||
'''
|
||||
field = getattr(self.__class__, name, None)
|
||||
return field if isinstance(field, Field) else None
|
||||
|
||||
@classmethod
|
||||
def table_name(cls):
|
||||
'''
|
||||
Returns the model's database table name.
|
||||
'''
|
||||
return cls.__name__.lower()
|
||||
|
||||
@classmethod
|
||||
def create_table_sql(cls, db_name):
|
||||
'''
|
||||
Returns the SQL command for creating a table for this model.
|
||||
'''
|
||||
parts = ['CREATE TABLE IF NOT EXISTS %s.%s (' % (db_name, cls.table_name())]
|
||||
cols = []
|
||||
for name, field in cls._fields:
|
||||
|
@ -86,6 +99,9 @@ class Model(object):
|
|||
|
||||
@classmethod
|
||||
def drop_table_sql(cls, db_name):
|
||||
'''
|
||||
Returns the SQL command for deleting this model's table.
|
||||
'''
|
||||
return 'DROP TABLE IF EXISTS %s.%s' % (db_name, cls.table_name())
|
||||
|
||||
@classmethod
|
||||
|
|
Loading…
Reference in New Issue
Block a user