Welcome to django-fusionbox’s documentation!¶
Contents:
Introduction¶
Django app of useful, reusable tools for use in Django projects. Primarily used by the development team at Fusionbox, however contains many tools that any Django developer would find useful.
Auth¶
Authentication backend to allow you to insert your own user model into the built in django authentication backend.
Installation and Usage¶
- Add
'fusionbox.auth.backends.CustomModelBackend'
to yourAUTHENTICATION_BACKENDS
setting insettings.py
- Set
CUSTOM_USER_MODEL
in yoursettings.py
file to a fully qualified path to your custom user model.
The Middlewares¶
-
class
fusionbox.middleware.
GenericTemplateFinderMiddleware
[source]¶ Response middleware that uses
generic_template_finder_view()
to attempt to autolocate a template for otherwise 404 responses.-
process_response
(request, response)[source]¶ Ensures that 404 raised from view functions are not caught by
GenericTemplateFinderMiddleware
.
-
process_view
(request, view_func, view_args, view_kwargs)[source]¶ Informs
process_response()
that there was a view for this url and that it threw a real 404.
-
-
class
fusionbox.middleware.
Redirect
(source, target, status_code, filename, line_number)[source]¶ Encapulates all of the information about a redirect.
-
class
fusionbox.middleware.
RedirectFallbackMiddleware
(*args, **kwargs)[source]¶ This middleware handles 3xx redirects and 410s.
Only 404 responses will be redirected, so if something else is returning a non 404 error, this middleware will not produce a redirect
Redirects should be formatted in CSV files located in either
<project_path>/redirects/
or an absolute path declared insettings.REDIRECTS_DIRECTORY
.CSV files should not contain any headers, and be in the format
source_url, target_url, status_code
wherestatus_code
is optional and defaults to 301. To issue a 410, leave off target url and status code.
Template Tags¶
The fusionbox_tags
library contains several useful template tags. Use
{% load fusionbox_tags %}
to use these.
highlight_here
¶
Filter the subnode’s output to add a class to every anchor where
appropriate, based on startswith matching. By default the class is here
,
but you can override by passing an argument to the tag.
Note
This requires BeautifulSoup to do the HTML parsing
Examples¶
Given:
{% highlight_here %}
<a href="/" class="home">/</a>
<a href="/blog/">blog</a>
{% endhighlight %}
If request.url is /
, the output is:
<a href="/" class="home here">/</a>
<a href="/blog/">blog</a>
On /blog/
, it is:
<a href="/" class="home">/</a>
<a href="/blog/" class="here">blog</a>
Code¶
Behaviors¶
Usage Notes¶
Because behaviors are ultimately implemented using a special metaclass, any model inheritance involving behaviors must come before any other parent class which inherits from Django’s built in metaclass.
Example Correct and Incorrect Usage:
class MyBaseModel(models.Model):
pass
# Incorrect Usage
class MyChildModel(MyBaseModel, Timestampable):
pass
# Correct Usage
class MyChildModel(Timestampable, MyBaseModel):
pass
Built in Behaviors¶
-
class
fusionbox.behaviors.
Behavior
(*args, **kwargs)[source]¶ Base class for all Behaviors
Behaviors are implemented through model inheritance, and support multi-inheritance as well. Each behavior adds a set of default fields and/or methods to the model. Field names can be customized like example B.
EXAMPLE A:
class MyModel(FooBehavior): pass
MyModel
will have whatever fieldsFooBehavior
adds with default field names.EXAMPLE B:
class MyModel(FooBehavior): class FooBehavior: bar = 'qux' baz = 'quux'
MyModel
will have the fields fromFooBehavior
added, but the field names will be ‘qux’ and ‘quux’ respectively.EXAMPLE C:
class MyModel(FooBehavior, BarBehavior): pass
MyModel
will have the fields from bothFooBehavior
andBarBehavior
, each with default field names. To customizing field names can be done just like it was in example B.
-
fusionbox.behaviors.
ManagedQuerySet
¶ alias of
QuerySetManagerModel
-
class
fusionbox.behaviors.
Publishable
(*args, **kwargs)[source]¶ Base class for adding publishable behavior to a model.
- Added Fields:
- Field 1:
- field: DateTimeField(default=datetime.datetime.now, help_text=’Selecting a future date will automatically publish to the live site on that date.’) description: The date that the model instance will be made available to the PublishableManager’s query set default_name: publish_at
- Field 2:
- field: DateTimeField(default=datetime.datetime.now, help_text=’Selecting a future date will automatically publish to the live site on that date.’) description: setting to False will automatically draft the instance, making it unavailable to the PublishableManager’s query set default_name: is_published
- Added Managers:
- PublishableManager:
description: overwritten get_queryset() function to only fetch published instances. name: published usage:
class Blog(Publishable): ...
all_blogs = Blog.objects.all() published_blogs = Blog.published.all()
-
class
fusionbox.behaviors.
QuerySetManagerModel
(*args, **kwargs)[source]¶ This behavior is meant to be used in conjunction with
fusionbox.db.models.QuerySetManager
A class which inherits from this class will any inner QuerySet classes found in the mro merged into a single class.
Given the following Parent class:
class Parent(models.Model): class QuerySet(QuerySet): def get_active(self): ...
The following two Child classes are equivalent:
class Child(Parent): class QuerySet(Parent.QuerySet): def get_inactive(self): ... class Child(QuerySetManagerModel, Parent): class QuerySet(QuerySet): def get_inactive(self): ...
-
class
fusionbox.behaviors.
SEO
(*args, **kwargs)[source]¶ Base class for adding seo behavior to a model.
- Added Fields:
- Field 1:
- field: CharField(max_length = 255) description: Char field intended for use in html <title> tag. validation: Max Length 255 Characters default_name: seo_title
- Field 2:
- field: TextField() description: Text field intended for use in html <meta name=’description’> tag. default_name: seo_description
- Field 3:
- field: TextField() description: Text field intended for use in html <meta name=’keywords’> tag. validation: comma separated text strings default_name: seo_keywords
-
class
fusionbox.behaviors.
Timestampable
(*args, **kwargs)[source]¶ Base class for adding timestamping behavior to a model.
- Added Fields:
- Field 1:
- field: DateTimeField(default=now) description: Timestamps set at the creation of the instance default_name: created_at
- Field 2:
- field: DateTimeField(auto_now=True) description: Timestamps set each time the save method is called on the instance default_name: updated_at
-
class
fusionbox.behaviors.
Validation
(*args, **kwargs)[source]¶ Base class for adding complex validation behavior to a model.
By inheriting from Validation, your model can have
validate
andvalidate_<field>
methods.validate()
is for generic validations, and forNON_FIELD_ERRORS
, errors that do not belong to any one field. In this method you can raise a ValidationError that contains a single error message, a list of errors, or - if the messages are associated with a field - a dictionary of field-names to message-list.You can also write
validate_<field>
methods for any columns that need custom validation. This is for convience, since it is easier and more intuitive to raise an ‘invalid value’ from within one of these methods, and have it automatically associated with the correct field.Even if you don’t implement custom validation methods, Validation changes the normal behavior of
save
so that validation always occurs. This makes it easy to write APIs without having to understand theclean
,full_clean
, andclean_fields()
methods that must called in django. If a validation error occurs, the exception will not be caught, it is up to you to catch it in your view or API.
-
fusionbox.behaviors.
now
()¶ [tz] -> new datetime with tz’s local day and time.
-
class
fusionbox.behaviors.
MetaBehavior
[source] Base Metaclass for Behaviors
Panels¶
Intro¶
Django Debug Toolbar allows hooking in extra panels.
User Panel¶
The user panel is derived from https://github.com/playfire/django-debug-toolbar-user-panel. The user panel allows for quick swapping between users. This version has been modified to disable the panel unless the user logs in initially with a superuser.
Installation¶
Add
'fusionbox.panels.user_panel'
to yourINSTALLED_APPS
:INSTALLED_APPS = ( ... 'fusionbox.panels.user_panel', ... )
Add
fusionbox.panels.user_panel.panels.UserPanel
to theDEBUG_TOOLBAR_PANELS
setting:DEBUG_TOOLBAR_PANELS = ( ... 'fusionbox.panels.user_panel.panels.UserPanel', ... )
Include
fusionbox.panels.user_panel.urls
somewhere in your url conf:urlpatterns = patterns('', ... url(r'', include('fusionbox.panels.user_panel.urls')), ... )
Email¶
Markdown-templated email.
An email template looks like this:
---
subject: Hello, {{user.first_name}}
---
Welcome to the site.
When using send_markdown_mail()
, its output is placed in a layout to
produce a full html document::
<!DOCTYPE html>
<html>
<body>
{{content}}
</body>
</html>
The default layout is specified in settings.EMAIL_LAYOUT
, but can be
overridden on a per-email basis.
-
fusionbox.mail.
create_markdown_mail
(template, context, to=None, subject=None, from_address='settings.SERVER_EMAIL', layout='settings.EMAIL_LAYOUT')[source]¶ Creates a message from a markdown template and returns it as an
EmailMultiAlternatives
object.
-
fusionbox.mail.
send_markdown_mail
(*args, **kwargs)[source]¶ Wrapper around
create_markdown_mail()
that creates and sends the message in one step.
Forms Module¶
Forms¶
-
class
fusionbox.forms.
BaseChangeListForm
(*args, **kwargs)[source]¶ Base class for all
ChangeListForms
.
-
class
fusionbox.forms.
SearchForm
(*args, **kwargs)[source]¶ Base form class for implementing searching on a model.
# Example Usage
class UserSearchForm(SearchForm): SEARCH_FIELDS = ('username', 'email', 'profile__role') model = User
>>> form = UserSearchForm(request.GET, queryset=User.objects.filter(is_active=True)) >>> form <accounts.forms.UserSearchForm object at 0x102ea18d0> >>> form.get_queryset() [<User: admin>, <User: test@test.com>, <User: test2@test.com>]
SEARCH_FIELDS
should be an iterable of valid django queryset field lookups. Lookups can span foreign key relationships.By default, searches will be case insensitive. Set
CASE_SENSITIVE
toTrue
to make searches case sensitive.-
get_queryset
()[source]¶ Constructs an ‘__contains’ or ‘__icontains’ filter across all of the fields listed in
SEARCH_FIELDS
.
-
-
class
fusionbox.forms.
FilterForm
(*args, **kwargs)[source]¶ Base class for implementing filtering on a model.
# Example Usage
class UserFilterForm(FilterForm): FILTERS = { 'active': 'is_active', 'date_joined': 'date_joined__gte', 'published': None, # Custom filtering } model = User PUBLISHED_CHOICES = ( ('', 'All'), ('before', 'Before Today'), ('after', 'After Today'), ) active = forms.BooleanField(required=False) date_joined = forms.DateTimeField(required=False) published = forms.ChoiceField(choices=PUBLISHED_CHOICES, widget=forms.HiddenInput()) def pre_filter(self, queryset): published = self.cleaned_data.get('published') if published == '': return queryset elif published == 'before': return queryset.filter(published_at__lte=datetime.datetime.now()) elif published == 'after': return queryset.filter(published_at__gte=datetime.datetime.now())
FILTERS
defines a mapping of form fields to queryset filters.When displaying in the template, this form also provides you with url querystrings for all of your filters.
form.filters
is a dictionary of all of the filters defined on your form.In the example above, you could do the following in the template for display links for the published filter
{% for choice in form.filters.published %} {% if choice.active %} {{ choice.display }} (<a href='?{{ choice.remove }}'>remove</a>) {% else %} <a href='?{{ choice.querystring }}'>{{ choice.display }}</a> {% endif %} {% endfor %}
-
filters
¶ Generates a dictionary of filters with proper queryset links to maintian multiple filters.
-
get_queryset
()[source]¶ - Performs the following steps:
- Returns the queryset if the form is invalid.
- Otherwise, filters the queryset based on the filters defined on the form.
- Returns the filtered queryset.
-
-
class
fusionbox.forms.
SortForm
(*args, **kwargs)[source]¶ Base class for implementing sorting on a model.
# Example Usage
class UserSortForm(SortForm): HEADERS = ( {'column': 'username', 'title': 'Username', 'sortable': True}, {'column': 'email', 'title': 'Email Address', 'sortable': True}, {'column': 'is_active', 'title': 'Active', 'sortable': False}, model = User
The sort field for this form defaults to a HiddenInput widget which should be output within your form to preserve sorting accross any form submissions.
-
get_queryset
()[source]¶ Returns an ordered queryset, sorted based on the values submitted in the sort parameter.
-
headers
()[source]¶ Returns an object with the following template variables:
{{ form.headers }}
- access to the header
{{ header.title }}
- title declared for this header
{{ header.sortable }}
- boolean for whether this header is sortable
{{ header.active }}
- boolean for whether the queryset is currently being sorted by this header
{{ header.classes }}
- list of css classes for this header. (active, ascending|descending)
{{ header.priority }}
- numeric index for which place this header is being used for ordering.
{{ header.querystring }}
- querystring for use with progressive sorting (sorting by multiple fields)
{{ header.remove }}
- querystring which can be used to remove this header from sorting
{{ header.singular }}
- querystring which can be used to sort only by this header
Example:
{% for header in form.headers %} {% if header.priority %} <th scope="col" class="active {{ form.prefix }}-{{ header.column }}"> <div class="sortoptions {{ header.classes|join:' ' }}"> <a class="sortremove" href="?{{ header.remove }}" title="Remove from sorting">X</a> <span class="sortpriority" title="Sorting priority: {{ header.priority }}">{{ header.priority }}</span> <a href="?{{ header.querystring }}" class="toggle" title="Toggle sorting"></a> </div> {% else %} <th scope="col" class="{{ form.prefix }}-{{ header.column }}"> {% endif %} {% if header.sortable %} <div class="text"><a href="?{{ header.querystring }}">{{ header.title }}</a></div> {% else %} <div class="text">{{ header.title|safe }}</div> {% endif %} </th> {% endfor %}
-
-
class
fusionbox.forms.
CsvForm
(*args, **kwargs)[source]¶ Base class for implementing csv generation on a model.
Example:
# Given this class...
class UserFilterForm(FilterForm): model = User CSV_COLUMNS = ( {'column': 'id', 'title': 'Id'}, {'column': 'username', 'title': 'Username'}, {'column': 'email__domain_name', 'title': 'Email Domain'}, ) FILTERS = { 'active': 'is_active', 'date_joined': 'date_joined__gte', 'published': None, # Custom filtering } PUBLISHED_CHOICES = ( ('', 'All'), ('before', 'Before Today'), ('after', 'After Today'), ) active = forms.BooleanField(required=False) date_joined = forms.DateTimeField(required=False) published = forms.ChoiceField(choices=PUBLISHED_CHOICES, widget=forms.HiddenInput()) def pre_filter(self, queryset): published = self.cleaned_data.get('published') if published == '': return queryset elif published == 'before': return queryset.filter(published_at__lte=datetime.datetime.now()) elif published == 'after': return queryset.filter(published_at__gte=datetime.datetime.now())
>>> # This code in a repl will produce a string buffer with csv output for >>> # the form's queryset >>> form = UserFilterForm(request.GET, queryset=User.objects.all()) >>> form.csv_content() <StringIO.StringO object at 0x102fd2f48> >>>
CSV_COLUMNS
defines a list of properties to fetch from each obj in the queryset which will be output in the csv content. Thecolumn
key defines the lookup path for the property. This can lookup a field, property method, or method on the model which may span relationships. Thetitle
key defines the column header to use for that property in the csv content.The
csv_content()
method returns a string buffer with csv content for the form’s queryset.
-
class
fusionbox.forms.
UncaptchaForm
(data=None, files=None, auto_id='id_%s', prefix=None, initial=None, error_class=<class 'django.forms.util.ErrorList'>, label_suffix=':', empty_permitted=False)[source]¶ Extension of
django.forms.Form
which adds an UncaptchaField to the form.
-
class
fusionbox.forms.
UncaptchaModelForm
(data=None, files=None, auto_id='id_%s', prefix=None, initial=None, error_class=<class 'django.forms.util.ErrorList'>, label_suffix=':', empty_permitted=False, instance=None)[source]¶ Extension of
django.forms.ModelForm
which adds an UncaptchaField to the form.
Fields¶
-
class
fusionbox.forms.
MonthField
(*args, **kwargs)[source]¶ MonthField
is aTypedChoiceField
that selects a month. Its python value is a 1-indexed month number.
-
class
fusionbox.forms.
MultiFileField
(*args, **kwargs)[source]¶ Implements a multifile field for multiple file uploads.
This class’ clean method is implented by currying super.clean and running map over data which is a list of file upload objects received from the
MultiFileWidget
.Using this field requires a little work on the programmer’s part in order to use correctly. Like other Forms with fields that inherit from
FileField
, the programmer must pass in the kwarg files when creating the form instance. For example:` form = MyFormWithFileField(data=request.POST, files=request.FILES) `
After validation, the cleaned data will be a list of files. You might want to iterate over in a manner similar to this:
-
widget
¶ alias of
MultiFileWidget
-
-
class
fusionbox.forms.
NoAutocompleteCharField
(max_length=None, min_length=None, *args, **kwargs)[source]¶ NoAutocompleteCharField
is a subclass ofCharField
that sets theautocomplete
attribute tooff
. This is suitable for credit card numbers and other such sensitive information.This should be used in conjunction with the sensitive_post_parameters <https://docs.djangoproject.com/en/dev/howto/error-reporting/#sensitive_post_parameters> decorator.
Newsletter¶
Fabric helpers¶
Usage¶
A typical fabfile.py
using fusionbox.fabric_helpers
looks like:
from fusionbox.fabric_helpers import *
env.roledefs = {
'dev': ['dev.fusionbox.com'],
}
env.project_name = 'foobar'
env.short_name = 'fb'
stage = roles('dev')(stage)
Class based Views¶
REST Views¶
Fusionbox generic views.
-
class
fusionbox.views.
RestView
(**kwargs)[source]¶ Inherit this base class to implement a REST view.
- This view will handle:
- authentication (throuh the
auth
method) - dispatching to the proper HTTP method function
- returning a proper error status code.
- authentication (throuh the
It also implements a default response for the OPTIONS HTTP request method.
-
auth
(*args, **kwargs)[source]¶ Hook for implementing custom authentication.
Raises
NotImplementedError
by default. Subclasses must overwrite this.
REST View Mixins¶
View classes to help facilitate the creation of REST APIs
-
class
fusionbox.views.rest.
JsonRequestMixin
[source]¶ Adds a
data
method on the view instance. It returns the GET parameters if it is a GET request. It will return the python representation of the JSON sent with the request body.
-
class
fusionbox.views.rest.
JsonResponseMixin
[source]¶ Sets the response MIME type to
application/json
and serializes the context obj as a JSON string.-
http_method_not_allowed
(*args, **kwargs)[source]¶ Returns super after setting the Content-Type header to
application/json
-
Managers¶
-
class
fusionbox.db.models.
QuerySetManager
[source]¶ http://djangosnippets.org/snippets/734/
Easy extending of the base manager without needing to define multiple managers and queryset classes.
Example Usage
from django.db.models.query import QuerySet from fusionbox.db.models import QuerySetManager class Foo(models.Model): objects = QuerySetManager() class QuerySet(QuerySet): def published(self): return self.filter(is_published=True)