Getting started

About

Dirty Model is a Python library to define transactional models. It means a model itself has no functionality. It just defines a structure in order to store data. It is almost true, but it doesn’t. A Dirty Model has some functionality: it could be modified storing changes. This is the main propose of this library.

How to define a model

To define a model is a simple task. You may create a new model class which inherit from dirty_models.models.BaseModel and use our field descriptors to define your fields.

class MyModel(BaseModel):

    my_int_field = IntegerField()
    my_string_field = StringField()

It is all! You has a new model.

Dirty Models defines an useful set of field descriptors to store any type of data: integer, string, non-empty string, float, date, time, datetime, timedelta, model, list of anything, hashmap, dynamic data, etc. You see all of them in Fields types.

All of them defines some common parameters on constructor:

  • default defines default value when a new model is instanced.
class MyModel(BaseModel):

    my_int_field = IntegerField(default=3)
    my_string_field = StringField()

model = MyModel()

assert model.my_int_field == 3 # True
  • alias defines a list of alias for field. Alias could be used like regular field there is no differences. It is not a good practice to define alias for same data, but it useful in some scenarios.
class MyModel(BaseModel):

    my_int_field = IntegerField(default=3, alias=['integer_field'])
    my_string_field = StringField()

model = MyModel()

assert model.my_int_field == 3 # True
assert model.integer_field == 3 # True
  • name defines real field name. It will be used on export data for example. Some time you need to define a field with weird characters to fit to a third party API. So, you could define a real name with this parameter. If it is not defined, name used on model definition is assumed as real name. Otherwise if it is defined, name defined on model become an alias for field.
class MyModel(BaseModel):

    my_int_field = IntegerField(default=3, name='real_integer_field')
    my_string_field = StringField()

model = MyModel()

assert model.my_int_field == 3 # True
assert model.real_integer_field == 3 # True

print(model.export_data())
# Prints
# {'real_integer_field': 3}
  • read_only defines whether field could be modified (easily). Of course, there are ways to modify it, but they must be used explicitly. See Unlocker.
class MyModel(BaseModel):

    my_int_field = IntegerField(default=3, read_only=True)
    my_string_field = StringField()

model = MyModel()

assert model.my_int_field == 3 # True

# Non read only field
model.my_string_field = 'string'
assert model.my_string_field == 'string' # True

# Read only field
model.my_int_field = 4
assert model.my_int_field == 4 # False
assert model.my_int_field == 3 # True
  • doc allows to define field docstring programmatically. But, don’t worry, you could use docstrings on regular way.
  • getter allows to define a function to get value.
  • setter allows to define a function to set value.

How to set data

There are some ways to set data in models.

Assign value to a field

Probably the most easy is just assigning value to field:

class MyModel(BaseModel):

    my_int_field = IntegerField(default=3, read_only=True)
    my_string_field = StringField()

model = MyModel()

model.my_int_field = 3
assert model.my_int_field == 3 # True

Be aware, Dirty Model will try to cast value to field type. It means that you could assign string value '3' to a integer field and it will be cast to 3. If value could not be cast it will be ignored. None is a particular value, it removes data from field.

class MyModel(BaseModel):

    my_int_field = IntegerField()
    my_string_field = StringField()

model = MyModel()

# Automatic cast
model.my_int_field = '3'
assert model.my_int_field == 3 # True
assert model.my_int_field == '3' # False

# Using None to remove data
model.my_int_field = None
assert model.my_int_field is None # True

Set data for whole model on contructor

Dictionary could be cast to model on contructor:

class MyModel(BaseModel):

    my_int_field = IntegerField()
    my_string_field = StringField()

model = MyModel(data={'my_int_field': 3, 'my_string_field': 'string'})

assert model.my_int_field == 3 # True
assert model.my_string_field == 'string' # True

On the other hand you could use keyword arguments to set some fields:

class MyModel(BaseModel):

    my_int_field = IntegerField()
    my_string_field = StringField()

model = MyModel(my_int_field=3, my_string_field='string')

assert model.my_int_field == 3 # True
assert model.my_string_field == 'string' # True

Import data

Some time you want to set data to whole model, but model already exists, so you could import data:

class MyModel(BaseModel):

    my_int_field = IntegerField()
    my_string_field = StringField()

model = MyModel()

model.import_data({'my_int_field': 3, 'my_string_field': 'string'})

assert model.my_int_field == 3 # True
assert model.my_string_field == 'string' # True

How to get data

In the same way, there are several methods to get data from model.

Use data from field

It is the simplest way to get data. Just use field.

class MyModel(BaseModel):

    my_int_field = IntegerField()
    my_string_field = StringField()

model = MyModel()

model.my_int_field = 3

assert model.my_int_field == 3 # True

Export data

It is possible to export data to a dict.

class MyModel(BaseModel):

    my_int_field = IntegerField()
    my_string_field = StringField()

model = MyModel()

model.my_int_field = 3

print(model.export_data())
# {'my_int_field': 3}

How to remove data

Once more, there are two way to remove data.

Using del keyword

Simplest way to remove data from field is to use del python keyword.

class MyModel(BaseModel):

    my_int_field = IntegerField()
    my_string_field = StringField()

model = MyModel()

model.my_int_field = 3
del model.my_int_field

assert model.my_int_field is None # True

Use None as value

Other way is to set None to field.

class MyModel(BaseModel):

    my_int_field = IntegerField()
    my_string_field = StringField()

model = MyModel()

model.my_int_field = 3
model.my_int_field = None

assert model.my_int_field is None # True