This library contains useful functions and classes mainly for a web development with Django (form and model fields, shortcuts, advanced datastructure, decoraters etc.). For more details see examples below.
django.forms.DecimalField
with step
parameter and validated min
and max
parameters.
Widget for safe rendering of readonly form values.
Mixin for automatic South migration of custom model fields.
django.db.models.DecimalField
with step
, min
and max
parameters. Uses chamber.forms.fields.DecimalField
as default form field.
Same as FileField, but you can specify:
content_types
- list containing allowed content_types. Example: ['application/pdf', 'image/jpeg']max_upload_size
- a number indicating the maximum file size allowed for upload in MB. Maximum upload size can be specified in project settings underMAX_FILE_UPLOAD_SIZE
constant
django.db.models.FileField
with RestrictedFileFieldMixin
options.
sorl.thumbnail.ImageField
(fallback to django.db.models.ImageField
) with RestrictedFileFieldMixin
options.
django.db.models.CharField
that stores NULL
but returns ''.
SmartModel introduced to Chamber uses by default a modified QuerySet with some convenience filters.
If you are overriding model manager of a SmartModel, you should incorporate SmartQuerySet
in order not to lose its benefits and to follow the Rule of the Least Surprise (everyone using your SmartModel will assume the custom filters to be there).
- If the manager is created using the
QuerySet.as_manager()
method, your custom queryset should subclassSmartQuerySet
instead the one from Django. - If you have a new manager created by subclassing
models.Manager
from Django, you should override theget_queryset
method as shown in Django docs here.
List of the added filters follows.
Returns same result as regular distinct()
but is much faster especially in PostgreSQL which performs distinct on all DB columns. The optimization is achieved by doing a second query and the __in
operator. If you have queryset qs
of MyModel
then fast_distinct()
equals to calling
MyModel.objects.filter(pk__in=qs.values_list('pk', flat=True))
Model dispatchers are a way to reduce complexity of _pre_save
and _post_save
methods of the SmartModel. A common use-case of these methods is to perform some action based on the change of the model, e.g. send a notification e-mail when the state of the invoice changes.
Better alternative is to define a handler function encapsulating the action that should happen when the model changes in a certain way. This handler is registered on the model using a proper dispatcher.
So far, there are two types of dispatchers but you are free to subclass the BaseDispatcher
class to create your own, see the code as reference. During save of the model, the __call__
method of all dispatchers is invoked with following parameters:
obj
... instance of the model that is being savedchanged_fields
... list of field names that was changed since the last save*args
... custom arguments passed to the save method (can be used to pass additional arguments to your custom dispatchers)**kwargs
... custom keyword arguments passed to the save method
The moment when the handler should be fired may be important. Therefore, you can register the dispatcher either in the pre_save_dispatchers
group or post_save_dispatchers
group. Both groups are dispatched immediately after the _pre_save
or _post_save
method respectively.
When the handler is fired, it is passed a single argument -- the instance of the SmartModel that is being saved. Here is an example of a handler that is registered on a User
model:
def send_email(user):
# Code that actually sends the e-mail
send_html_email(recipient=user.email, subject='Your profile was updated')
chamber.models.dispatchers.PropertyDispatcher
is a versatile dispatcher that fires the given handler when a specified property of the model evaluates to True
.
The example shows how to to register the aforementioned send_email
handler to be dispatched after saving the object if the property should_send_email
returns True
.
class MySmartModel(chamber_models.SmartModel):
email_sent = models.BooleanField()
post_save_dispatchers = (
PropertyDispatcher(send_email, 'should_send_email'),
)
@property
def should_send_email(self):
return not self.email_sent
In the following example, where we register my_handler
function to be dispatched during _pre_save
method when the state changes to SECOND
. This is done using chamber.models.dispatchers.StateDispatcher
.
def my_handler(my_smart_model):
# Do that useful stuff
pass
class MySmartModel(chamber_models.SmartModel):
STATE = ChoicesNumEnum(
('FIRST', _('first'), 1),
('SECOND', _('second'), 2),
)
state = models.IntegerField(choices=STATE.choices, default=STATE.FIRST)
pre_save_dispatchers = (
StateDispatcher(my_handler, STATE, state, STATE.SECOND),
)
A common use-case is to perform an action whenever an instance of a particular model is created. chamber.models.dispatchers.CreatedDispatcher
is provided to accommodate this need. An update of the instance will not trigger the handler.
def my_handler(my_smart_model):
# Do that useful stuff when a new instance of MySmartModel is created
pass
class MySmartModel(chamber_models.SmartModel):
post_save_dispatchers = (
CreatedDispatcher(my_handler),
)
remove_accent('ěščřžýáíé') # 'escrzyaie'
It returns a method of a given class or instance.
Base enumeration class with controlled __getattr__
.
Python's set
with AbstractEnum
behaviour.
Python's dict
with AbstractEnum
behaviour.
>>> NumEnum('a', 'b')
{'a': 1, 'b': 2}
Base choices class (as used in Model field's choices
argument).
django.utils.datastructures.SortedDict
with AbstractEnum
and AbstractChoicesEnum
behaviour. Useful for string based choices.
>>> enum = ChoicesEnum(('OK', 'ok'), ('KO', 'ko'))
>>> enum
{'OK': 'ok', 'KO': 'ko'}
>>> enum.OK
'ok'
>>> enum.choices
[('OK', 'ok'), ('KO', 'ko')]
django.utils.datastructures.SortedDict
with AbstractEnum
and AbstractChoicesEnum
behaviour. Useful for integer based choices.
>>> enum = ChoicesNumEnum(('OK', 'ok', 1), ('KO', 'ko', 2))
>>> enum.KO
2
>>> enum.choices
[(1, 'ok'), (2, 'ko')]
>>> enum.get_label(2)
'ko'
Ties property to class, usefull for usage in class methods.
class RestResource(BaseResource):
@classproperty
def csrf_exempt(cls):
return not cls.login_required
@classmethod
def as_view(cls, allowed_methods=None, **initkwargs):
view.csrf_exempt = cls.csrf_exempt
Class decorator, which allows for only one instance of class to exist.
Sets short_description
attribute (this attribute is used by list_display and formulars).
@short_description('amount')
def absolute_amount(self):
return abs(self.amount)
is equivalent of
def absolute_amount(self):
return abs(self.amount)
absolute_amount.short_description = 'amount'
Returns True if passed formset contains FileField (or ImageField).
Assemble query string from dict
of parameters.
>>> query_string_from_dict({'q': 'query1', 'user': 'test'})
u'q=query1&user=test'
Takes Model or QuerySet and arguments and returns instance of Model if exists, None
otherwise.
>>> get_object_or_none(User, pk=1)
<User: Gaul Asterix>
>>> get_object_or_none(User.objects.exclude(pk=1), pk=1) or ''
''
Takes Model or QuerySet and arguments and returns instance of Model if exists, raises django.http.response.Http404
otherwise.
>>> get_object_or_404(User, pk=1)
<User: Gaul Asterix>
>>> get_object_or_404(User.objects.exclude(pk=1), pk=1)
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/var/ve/lib/python2.7/site-packages/chamber/shortcuts.py", line 21, in get_object_or_404
raise Http404
Http404
Takes Model or QuerySet and distinction parameters and returns list of unique values.
>>> User.objects.filter(last_name='Gaul')
[<User: Gaul Obelix>, <User: Gaul Asterix>]
>>> distinct_field(User.objects.filter(last_name='Gaul'), 'last_name')
[(u'Gaul',)]
Takes negate bool
(True for exclude, False for filter), Model or QuerySet and date parameters and return queryset filtered or excluded by date parameters.
>>> Order.objects.values_list('created_at', flat=True)
[datetime.datetime(2014, 4, 6, 15, 56, 16, 727000, tzinfo=<UTC>),
datetime.datetime(2014, 2, 6, 15, 56, 16, 727000, tzinfo=<UTC>),
datetime.datetime(2014, 1, 11, 23, 15, 43, 727000, tzinfo=<UTC>)]
>>> filter_or_exclude_by_date(False, Order, created_at=date(2014, 2, 6))
[<Order: MI-1234567>]
>>> filter_or_exclude_by_date(False, Order, created_at=date(2014, 2, 6))[0].created_at
datetime.datetime(2014, 2, 6, 15, 56, 16, 727000, tzinfo=<UTC>)
Shortcut for chamber.shortcuts.filter_or_exclude_by_date
with first parameter False.
Shortcut for chamber.shortcuts.filter_or_exclude_by_date
with first parameter True.
For contribution go to example
directory and call make install
to install an example project.
To run tests go to example
directory and call make test
.
See LICENSE file.