None
This library consists of various Django-related routines that extend or modify the behaviour of the framework:
- lots of composable abstract models to use
- a user activity log app storing users’ IP addresses and user agents (useful for hunting down multi-accounts)
- a
score
app enabling users on websites to vote on objects- a
tags
app which supports tagging by users and localized tags- a
badges
app which enables users to receive badges for actions on the website- extensions for
settings.py
(current directory resolution, namespace package support, settings profile support)- typical filters, template tags, form fields, etc.
Complete documentation for the package can be found here:
The latest version can be installed via PyPI:
$ pip install lck.django
or:
$ easy_install lck.django
The source code repository and issue tracker are maintained on GitHub.
This package bundles some royalty free static images that are useful in almost every Django project:
Silk icons 1.3 by FamFamFam - requires attributing the author
Silk Companion 1 by Damien Guard - requires attributing the author
Country Flags by SenojFlags.com - requires using the following HTML:
<a href="http://www.senojflags.com">Country flag</a> image from <a href="http://www.senojflags.com">Flags of all Countries</a>
For the curious, lck
stands for LangaCore Kit. LangaCore is a one man
software development shop of mine.
Note: lck.common
requires Python 2.7 because all of its code is using
the so-called four futures (absolute_imports
, division
, print_function
and unicode_literals
). One of the virtues in the creation of this library
is to make the code beautiful. These switches give a useful transitional
state between the old Python 2.x and the new Python 3.x. You should use them as
well.
Note: Since 0.5.0 lck.django
requires Django 1.3 because
it makes my monkey-patching efforts much easier. Moreover, 1.3 nicely deprecates
behaviour which I consider ugly.
The easiest way would be to run:
$ DJANGO_SETTINGS_MODULE="lck.dummy.settings" DJANGO_SETTINGS_PROFILE="test" django-admin.py test
This command runs the internal Django tests as well and that’s fine because there are monkey patches and other subtleties that should better be tested for potential breakage.
The dummy project is also used as an example of setting up a Django project.
However, it seems Django tests are not happy with some changes to the settings
so we’re using the test
profile (which loads overrides from
settings-test.py
) to avoid that.
profile
now properly rolls back a failed transaction in
create_a_user_profile_ignoring_dberrors()
(fixes initial syncdb’s
superuser creation on PostgreSQL)activitylog
, badges
, score
or tags
, unless you’re
using the plain auth.User
, their initial migrations depend on your
profile module being ready. Migrations currently depend on the initial
migration of your respective ACTIVITYLOG_PROFILE_MODEL
,
EDITOR_TRACKABLE_MODEL
, SCORE_VOTER_MODEL
or TAG_AUTHOR_MODEL
. If
those migrations should depend on a different migration or none, new settings
have been added.activitylog
modelsdj.choices
requirement bumped to 0.9.2 (support for Python 2.6 - 3.3)dj.chain
requirement bumped to 0.9.2 (support for Python 2.7 - 3.3)activitylog
now properly encloses database updates in transactionsactivitylog
on RQ and Celery now properly handles non-null constraints on
modelsSessionAwareLanguageMiddleware
simplified, now simply sets the language
argument in the session. This requires changing middleware order: this
middleware should come after SessionMiddleware
and before
LocaleMiddleware
.INSTRUMENTATION_RULE
is now simply lambda request: False
which makes TimingMiddleware
behave better with front-end caches (if
session is not accessed, Vary: Cookie
is not set).activitylog
now sports new async modes with built-in support for RQ or
Celery workerstags
modelsactivitylog
middleware. Now behaves better
in low-memory + slow I/O environments.whois
management command introduced to help find users by session IDUser
attributes proxied from a Profile
instance no longer
causes a query for each callTimeTrackable
models can now force marking fields as dirty with
mark_dirty()
and mark_clean()
methodsconcurrent_get_or_create
will now raise AssertionErrors if given either
too many fields (e.g. not all of which are unique or compose
a unique-together constraint) or too few (e.g. fields do not form a whole
unique-together constraint). Non-unique fields should be passed in the
defaults
keyword argument if needed at object creation time.profile
now implements automatic profile account synchronization by
registering a post-save signal on User and creating an AUTH_PROFILE_MODEL
instance. A management command for existing applications called
sync_profiles
has been created.concurrent_get_or_create
fails miserably on MySQL due to dogdy savepoint
support in MySQL-pythonconcurrent_get_or_create
based on get_or_create
from Django 1.4.2namespace_package_support
extended to cover django.utils.translation
as well (previously namespace-packaged projects only worked with I18N if
setup.py develop
or pip install -e .
was used to install them)dj.chain
requirement bumped to 0.9.1 (supports more collective methods)lazy_chain
moved to a separate dj.chain package. The old interface is thus
deprecated and will be removed in a future version.activitylog
updates: removed redundant user fields so it works again with
ACTIVITYLOG_PROFILE_MODEL
set to auth.User
EditorTrackable
doesn’t require overriding get_editor_from_request
anymore if EDITOR_TRACKABLE_MODEL
is set to a profile model instead of
auth.User
ProfileInlineFormSet
for
inclusion of profile-tied models to the UserAdmin
as inlineslazy_chain
: the fix from 0.7.13 introduced a different kind of bug,
reverted and fixed properly now. More tests included.flatpages
now serve content in the default language if the language
requested by the browser is unavailable.lazy_chain
: when iterating over a slice, the iterator fetched one item too
many. It didn’t yield it back so the result was correct but if using
xfilter()
that caused unnecessary iteration.dj.choices
requirement bumped to 0.9.0 (choices are int
subclasses,
unicode(choice)
is now equivalent to choice.desc
)dj.choices
requirement bumped to 0.8.6 (fully compatible with
0.8.5 and significantly improves ChoiceFields
)BACKLINKS_LOCAL_SITES
setting to control if all configured sites should be
considered local upon backlink discoveryactivitylog
activitylog
accepts UTF-8 characters in User-Agent
headersactivitylog
South migration #0002 now also works on backends with DDL
transactions (e.g. Postgres)DefaultTags
and
MACAddressField
).South migrations supported across the board. For existing installations you should run:
$ python manage.py migrate APP_NAME 0001 --fake
$ python manage.py migrate APP_NAME
where APP_NAME
is activitylog
, badges
, common
, flatpages
,
profile
, score
or tags
.
uniqueness constraints in activitylog.models.Backlink
and
activitylog.models.UserAgent
moved to separate hash
fields to make
MySQL happy. South migrations should handle schema evolution regardless of the
backend you’re using.
USE_TZ = True
compatibilityUser
attribute proxying in Profile
models rewritten to support all
built-in and custom attributes on the User
modelactivitylog.middleware
now records IPs and user agents for unauthenticated
requests as well. Possibly a performance hit.lck.django.score
after cleaning up helperslck.django.badges
introducedlck.django.common
cleaned up, lazy_chain
significantly upgraded (now
properly supports multiple iterables with filtering, slicing and sorting)lck.django.score
: send a signal on total score change (allows for caching
strategies on the app side)maxid
management command introduced: for every registered model returns
the current maximum value for primary keysMACAddressField
MAC address normalization ignores empty values, supports
Cisco 0000.0000.0000
notation and fixes a minor regression from 0.6.5SessionAwareLanguageMiddleware
introducedEditorTrackable
MACAddressField
ImageModel
introducedNamed
models name field extended to 75 characters of lengthtimediff
filterMACAddressField
normalization bug fixedModelAdmin
ModelAdmin
PyLibMCCache
backend in lck.django.cache_backends
activitylog
Oh boy, lots of changes!
TimeTrackable
just got a lot smarter. Includes cache_version
attribute automatically updated on significant changes to the object.
modified
gets updated only when there are actual changes to the object.
dirty_fields
property shows changed attributes from last save (works also
for objects composed from multiple models, including abstract ones).
Inspired by David Cramer and Simon Willison at EuroPython 2011.
The dogpile-safe lck.django.cache
now supports custom invalidators which
enables invalidation not only by time but also by e.g. model changes (think
TimeTrackable.cache_version
).
Settings profile support now requires a modified manage.py
script in the
Django project. This is forced by the unfortunate design of how Django loads
settings.
Activity logging moved to its own app, lck.activitylog
, which now also
tracks IPs and user agents of logged-in visitors (useful in hunting
multi-accounts).
Introduced a SavePrioritized
abstract model which adds priorities to
saves on models. Various parts of the application can specify which priority
they use. If they update an attribute which was first saved by something with
higher priority, the update is silently ignored.
Introduced a concurrency-aware variant of the popular
Model.objects.get_or_create
(unsurprisingly called
concurrent_get_or_create
)
Introduced a commit_on_success
variant that supports nesting
(unsurprisingly called nested_commit_on_success
)
Introduced BasicAuthMiddleware
for simplistic private URL protecting.
EditorTrackable
is now safe in terms of foreign key cascading (content
authored or modified by a user won’t get deleted after this user is removed
from the DB). Plus some nice admin refinements.
Now TimingMiddleware
doesn’t break other middlewares using
process_view()
and is generally smarter.
Added X-Slo
header in responses for TimingMiddleware
.
render()
now calculates and emits ETags based on the rendering output.
typical_handler()
can now redirect_on_success
.
Links from the BBCode filter now open in a new window and have
rel="nofollow"
set.
Introduced a {%settings KEY%}
templatetag.
Introduced a {%git_version%}
templatetag which returns a short string
useful to present as an app version. This is based on the latest commit in
the Git repository where the Django project lies in.
The cycle_filter
template filter now supports explicit counter settings
and incrementation.
Introduced template filters converting to and from Base64.
Introduced JQuery UI and JQueryMobile integrated radio widgets.
Improved documentation.
More complete translations.
TimingMiddleware
introduced.BaseProfile
now return self
for get_profile()
.Choices.ToNames
decorator introduced.manage.py shell
works also for models with
a custom``app_model``.EditorTrackable
introduced'--keyword=Group:2 '
to xgettext invocations in
django/core/managemenet/commands/makemessages.py. Cleaning that up is planned
for 0.6.0.typical_handler
works now with forms w/o a save()
methodupperfirst
filter introduced: ups only the first characterPolishDateWidget
AvatarSupport
abstract model for custom avatars. GravatarSupport
can
be used as fallback or independently.typical_handler
now properly supports file uploadsname_urlencoded
and
title_urlencoded
properties were introduced. Useful as arguments in
template tags.<<
operator overloadlck
namespace from langacore.kit
This library consists of a number of reusable Django apps and a set of common functionality that enables them to work.
For more detailed view on the modules, see the documentation below.
cache |
|
choices |
|
filters |
|
common |
|
common.forms |
|
common.middleware |
|
common.models |
|
common.templatetags.bbcode |
|
common.templatetags.converters |
|
common.templatetags.cycle_filter |
|
common.templatetags.strings |
|
common.templatetags.thumbnail |
|
activitylog.middleware |
|
activitylog.models |
|
badges.models |
|
profile.models |
|
score.models |
|
score.templatetags.lckd_score |
|
tags.helpers |
|
tags.models |
settings.py
¶One of the most often customized parts of a Django project is settings.py
.
To ease the process and protect against possible mistakes when doing the same
exact modification for the n-th time, a set of extensions for settings.py
was developed. The extensions are activated by importing them and executing:
from lck.django import current_dir_support
execfile(current_dir_support)
This is done so to enable the extensions access to the current local namespace
of settings.py
. If anyone knows a more elegant way to do that, let me know.
For now this seems a good approach though.
current_dir_support
¶This extension injects a CURRENT_DIR
variable into settings.py
so it is
available from the moment of definitions onwards. CURRENT_DIR
in this
context means the root of the project (“current” because most of the time this
is the same dir where settings.py
resides). An additional feature is that it
is always ending with os.sep
so it’s perfectly safe to do something like:
from lck.django import current_dir_support
execfile(current_dir_support)
(...)
MEDIA_ROOT = CURRENT_DIR + 'media/'
Moreover, CURRENT_DIR
gets set properly also for the projects that use
a package for specifying settings, e.g. a structure like that:
project_dir
├── __init__.py
├── an_app
│ ├── __init__.py
│ └── ...
├── an_app
│ ├── __init__.py
│ └── ...
├── other_app
│ ├── __init__.py
│ └── ...
├── settings
│ ├── __init__.py
│ └── local.py
└── yet_other_app
├── __init__.py
└── ...
To enable this extension, import and execute it in the settings.py
context
(at the very beginning of the config file is recommended since
CURRENT_DIR
is available only after the extension’s initialization).
namespace_package_support
¶This extension monkey-patches [1] Django so that is supports namespace packages. Not all places are covered though so if you spot some feature where namespace packages still don’t work, file an issue using our issue tracker.
To enable this extension, import and execute it in the settings.py
context
(anywhere within the config file is fine):
from lck.django import namespace_package_support
execfile(namespace_package_support)
Features supported:
profile_support
¶Splitting global settings from instance-specific ones is also a very frequent task that most Django projects implement in one way or another. There are many reasons why such separation is desirable but the most important ones are:
So, how do you get to split your settings.py
file? The simplest approach is
to create a file with the local settings as a module and just import it at the
end of the global one. This approach has two significant drawbacks: you cannot
use/edit variables specified in the global settings and the name of the local
module is now hard-coded within the global file.
Enter profile_support
! With this extension you can have several
local-specific settings modules which are executed in the global settings
context. This means you can within your local settings do things like:
INSTALLED_APPS += (
'debug_toolbar',
)
MEDIA_ROOT = CURRENT_DIR + 'static'
where you add the debug toolbar to the active apps (notice the +=
operator)
and CURRENT_DIR
is the one calculated by enabling current_dir_support
.
To enable profiles, just add these lines at the very end of your
settings.py
file:
from lck.django import profile_support
execfile(profile_support)
By default, this enables loading settings found in settings-local.py
. There
are times when you need more than one config profile though, for instance:
manage.py
syncdb
and manage.py migrate
Without profile_support
you would create some “toggle” variables like
SYNC_DB
or VERBOSE_DEBUG
and use if
/else
within the settings.
Thanks to profile_support
you can treat settings.py
files like regular
configuration files without any logic and just use different local profiles. To
change to a profile different from “local” when running a command, just
specify the DJANGO_SETTINGS_PROFILE
environment variable:
DJANGO_SETTINGS_PROFILE=syncdb python manage.py migrate
In that case, the local settings will be loaded from settings-syncdb.py
and
not from settings-local.py
.
If you use profiles heavily, the root project folder gets quite cluttered with
settings-*.py
files. In that case you might switch to package based
configuration. Just make a directory called settings
, move your existing
settings.py
to settings/__init__.py
and your settings-*.py
files to
settings/*.py
. Then your project tree will look something like the one on
the diagram in the current_dir_support
description above.
manage.py
commands¶By adding lck.django.common
to your INSTALLED_APPS
you get
some additional second-level commands for manage.py
:
shell
: a version of the original manage.py shell command for
lazy people: is using bpython if
installed and imports all models automaticallyNote
These commands require namespace_package_support.
Copyright (C) 2010, 2011 by Łukasz Langa
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the Software), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Convert unit tests to base on unittest2. Create introductory material for common models, activitylog, score and tags: tutorials, examples and FAQ.
Drop support for Django 1.3.
Separate some of the more useful things as their own packages. Currently these are already separated:
These would be great to separate:
Make all separated packages compatible with Python 3.x.
Unit test the rest, remove what’s supported out of the box in Django 1.4.
Clean up forms.
py.test
is used for the existing tests which makes proper
unit testing for Django-specific bits harder. Struggling with
django-pytest
did not produce any results as of yet.