Jul 4, 2013
Dec 18, 2012
Django Performance Tuning
Oct 19, 2011
A skeleton Django project
https://github.com/senko/dj-skeletor
DJ Skeletor is a skeleton Django project handy for bootstrapping new empty projects.
The repository contains an empty, relocatable Django project with South, Django Debug Toolbar and Sentry apps set, and with provisions for test and production settings.
Oct 11, 2011
500/404 templates if you only use the admin
urls.py:
from django.utils.functional import curry
from django.views.defaults import server_error, page_not_found
handler500 = curry(server_error, template_name='admin/500.html')
handler404 = curry(page_not_found, template_name='admin/404.html')
If you have other drop-in apps that need authentication (like rosetta or sentry) bare in mind that the admin doesn’t have a reusable login view so you must hook one. You should just reuse django admin’s login template.
url(r'^accounts/login/$', 'django.contrib.auth.views.login', {'template_name': 'admin/login.html'}),
Making Django's signals asynchronous with Celery
from celery.task import task
from django.db.models.signals import post_save
from myproject.models import MyModel
# Warning. Monkey patch.
from django.dispatch.dispatcher import Signal
def reducer(self):
return (Signal, (self.providing_args,))
Signal.__reduce__ = reducer
# With the patch done, we can now connect to celery tasks.
@task(ignore_result=True)
def async_post_save(sender, instance, **kwargs):
# do something with the instance.
pass
post_save.connect(async_post_save.delay, sender=MyModel)
Патч нужен только если требуется в декоратор task передавать аргумент(ы). В противном случае достаточно:
from celery.task import task
from django.db.models.signals import post_save
from myproject.models import MyModel
@task
def async_post_save(instance):
# do something with the instance.
pass
def post_save_reciever(sender, instance, **kwargs):
async_post_save.delay()
post_save.connect(post_save_reciever)
Оригинал в блоге Dougal Matthews
Oct 5, 2011
Signals registration
from importlib import import_module
from django.conf import settings
for app in settings.INSTALLED_APPS:
try:
import_module( 'signals', app)
except ImportError as e:
print 'Failed to import "%s", reason: %s' % (app, str(e)))
Original: http://djangosnippets.org/snippets/2561/
Aug 30, 2011
Django Admin Snippets
readonly_field
As of Django 1.2, a readonly_field has been available to models in the admin. This is very helpful for making data visible in the admin while preventing it from being edited.
readonly_fields=[’created’,’modified’,’preformed_by’,’ipaddress’,’featured’]
get_readonly_fields()
Using the get_readonly_fields() method of the ModelAdmin, one can change readonly fields dynamically. The method gives access both to the request and to the Admin Model instance.
def get_readonly_fields(self, request, obj = None):
if obj:
if not (request.user.is_staff or request.user.is_superuser):
return [‘featured’,] + self.readonly_fields
return self.readonly_fields
else:
return self.readonly_fields
Disable admin actions
By default, every Django Admin model has a delete_selected admin action available which allows admins to delete multiple objects in the change_list admin view. If you wish to remove this default option and disable all the admin actions for a given Django Model in the Admin, something like this may be appropriate. This will remove the “Actions” dropdown completely from the model’s change list.
admin_actions = None
Override get_actions
An alternative to disabling all the admin actions for a Model would be to override the get_actions() method on the ModelAdmin. This will allow you to customize the “Actions” list based on the request or other factors.
http://stackoverflow.com/questions/1565812/the-default-delete-selected-admin-action-in-django
def get_actions(self, request):
actions = super(PostAdmin, self).get_actions(request)
try:
del actions[‘delete_selected’]
except KeyError:
pass
return actions
Customize permissions
The has_delete_permission() ModelAdmin method allows you to customize how permissions are assigned for a given model in the admin. Instead of using Django’s default permission system, you can change the permissions programmatically. Note that this function does not change how permissions work on admin actions such as the delete_selected action discussed above.
def has_delete_permission(self, request, obj=None):
return_value = False
user = request.user
if user.is_authenticated() and user.is_staff:
return_value = True
return return_value
The has_add_permission() allows the same type of customization of permissions for adding objects.
def has_add_permission(self, request):
return_value = False
user = request.user
if user.is_authenticated() and user.is_superuser:
return_value = True
return return_value
Customize save_model
The save_model() method allows you to customize actions that take place on the model only when it’s saved in the admin. In this example, we override the save_model() so that we may save to the model of the current admin user and her IP address.
def save_model(self, request, obj, form, change):
obj.preformed_by = request.user
obj.ip_address = utils.get_client_ip(request)
obj.save()
Change multiple-select widget to filter_horizontal for ManyToMany fields
When dealing with ManyToMany fields, the default admin widget is a multiple-select box which allows a user to control-select a list of multiple items. This select box is kind of awkward; a better option may be to use the Filter Horizontal widget which provides a more advanced box.
filter_horizontal = ('category',)
For performance reasons use raw_id_fields instead filter_horizontal
For performance reasons, it may not be a good idea to use the Django default widget or the filter_horizontal widget for ManyToMany relations where a lot of related results. For example, a filter_horizontal Admin widget may take a long time to load if used to display a related tags field if there are thousands of possible related Tags. In that case, the raw_id_fields Admin option may be more appropriate, as it will only display the ID field and unicode representation of the related object. This option also provides a link to a popup dialog that allows an admin to populate the id field by browsing for an object interactively.
raw_id_fields = ("tags",)
Dynamically define fieldsets
The Django Admin offers some flexibility in how the fields on the detail pages are displayed. Fieldsets are used to group Admin fields into sections and even together on the same line. This can be done dynamically by overriding the __init__() on the ModelAdmin.
fieldsets = []
def __init__(self, model, admin_site):
# Define some field groupings
post_fields = ['title', 'type', 'featured']
meta_fields = ['created', 'modified',]
client_fields = ['preformed_by', 'ipaddress']
message_fields = ['message',]
# make a big list of all the fields that we are customizing
ex_fields = post_fields + meta_fields + client_fields + message_fields
all_fields = fields_for_model(model)
base_fields = [tuple(post_fields), tuple(meta_fields), tuple(message_fields)]
# all the rest of the fields that we don’t specifically customize
rest_fields = list(set(all_fields) - set(ex_fields))
# Group fields into Sections
self.fieldsets.append(('Post Info', { 'fields': tuple(base_fields), }))
self.fieldsets.append(('Client Info', { 'fields': tuple(client_fields), }))
# Display the rest of the non-customized fields at the bottom
if rest_fields:
self.fieldsets.append(('Other', { 'fields': tuple(rest_fields), }))
# set the fieldset - needs to be a tuple
self.fieldsets = tuple(self.fieldsets)
super(PostAdmin, self).__init__(model, admin_site)
admin.site.register(models.Post, PostAdmin)
Customize User model
Sometimes it’s nice to be able to customize the admin page for the Django user. This can be done by un-registering the default ModelAdmin class and re-registering your customized version. This code should be placed in any one of your Django App’s admins.py files. In this example, we add a custom Inline class to the User Admin, as well as modify the list_display and list_filter fields for the User Admin.
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
class PostInline(admin.TabularInline):
model = models.Post
extra = 0
readonly_fields = ['created', 'modified', 'preformed_by', 'ip_address']
exclude = ['tags','category',]
class CustomUserAdmin(UserAdmin):
list_display = UserAdmin.list_display + ('date_joined','last_login')
list_filter = UserAdmin.list_filter + ('is_active',)
inlines = [PostInline,]
admin.site.unregister(User)
admin.site.register(User, CustomUserAdmin)
Customize User form
The form that an Admin model uses can be customized as well. For example, you can place extra validation on the Admin form to ensure that the admin users enter data correctly.
class PostAdminForm(forms.ModelForm):
class Meta:
model = models.Post
def clean(self):
cleaned_data = self.cleaned_data
message = cleaned_data.get("message", False)
if len(message) < 20:
raise forms.ValidationError("Message must be 20+ chars long.")
return cleaned_data
Set the form by adding it to the PostAdmin ModelAdmin.
class PostAdmin(admin.ModelAdmin):
...
...
form = PostAdminForm
...
Override “Django Administration”
One convenient admin customization is to override the default “Django Administration” title that appears at the top of the admin interface. This can be done via an admin template override.
Let’s say our settings.py has our TEMPLATE_DIRS set as follows, where PROJECT_PATH is the UNIX filesystem path to the Django Project.
import os
PROJECT_PATH = os.path.realpath(os.path.dirname(__file__))
TEMPLATE_DIRS = (
os.path.join(PROJECT_PATH, 'templates'),
)
We could create a file called base_site.html located in PROJECT_PATH/templates/admin/ which contains the following Django template code. This overrides the default title for the Django admin.
{# Located in PROJECT_PATH/templates/admin/base_site.html #}
{% extends "admin/base.html" %}
{% load i18n %}
{% block title %}{{ title }} | {% trans 'ChicagoDjango Demo Project Admin' %}{% endblock %}
{% block branding %}
<h1 id="site-name">{% trans 'ChicagoDjango Demo Project Administration' %}</h1>{% endblock %}
{% block nav-global %}{% endblock %}
Add extra “sections” to the Django admin on a given Object Change page
Sometimes you may want to add extra “sections” to the Django admin on a given Object Change page (change_form.html). This can be done with an admin template override and template inheritance. In order to override the default admin template for the Object Change view, you need to place a file named change_form.html in the following directory within your Django module directory, where your_module_name and your_model_name refers to the lower-case names of your Django module and Django model respectively: templates/admin/<your_module_name>/<your_model_name>/.
Notice in the code below that this custom template overrides admin/change_form.html. Also, this custom template defines a block called {% block after_field_sets %} which adds a template block at the bottom of the page. You can reference the object being edited as a context variable called “original”.
</your_model_name>/<your_module_name>
{# Located in MODULE_PATH/templates/admin/a/post/change_form.html #}
{% extends "admin/change_form.html" %}
{% block extrahead %}{{ block.super }}
<style>
.item { padding: 10px; border-bottom:1px solid #EEEEEE; height: 25px }
.heading { font-weight: bold; font-size: 14px; color: #666666; }
</style>
{% endblock %}
{% block after_field_sets %}{{ block.super }}
<div class="module aligned">
<div class="item">Post: {{ original.title }}</div>
</div>
<div class="module aligned">
<div class="item heading">Post Categories</div>
{% for category in original.category.all %}
<div class="item">
<span class="item_name">{{ category.name }}</span>
<span class="item_edit"><a href="{% url admin:a_postcategory_change category.id %}" target="_blank">Edit</a></span>
</div>
{% empty %}
<div class="item">No Categories</div>{% endfor %}
</div>
{% endblock %}
When it comes to customizing the Django admin, this is just the tip of the iceberg. Please feel free to share any admin customizations that you find interesting via a comment. Also, feel free to fork the Github repository and suggest updates or additional techniques.
Original http://www.chicagodjango.com/blog/django-admin-snippets/
Jul 29, 2011
Memcached
Установка
apt-get install memcached
apt-get install python-memcache
pylibmc работает быстрее но из-за того что написан на С вызывает дополнительные эксепшены, поэтому использовать надо осторожно
apt-get install python-pylibmc
Затем прописываем в settings.py
DATABASES = {
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
}
}
или для pylibmc
DATABASES = {
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
'LOCATION': '127.0.0.1:11211',
}
}
Сброс кэша
/etc/init.d/memcached restart
Или через телнет команду flush_all
Изменение конфигурации
vi /etc/memcached.conf
Jul 21, 2011
Amazon ses + django
sudo apt-get install libio-socket-ssl-perl
sudo apt-get install libxml-libxml-perl
sudo pip install boto
sudo pip install django-ses
# in settings.py
AWS_ACCESS_KEY_ID = 'YOUR-ACCESS-KEY-ID'
AWS_SECRET_ACCESS_KEY = 'YOUR-SECRET-ACCESS-KEY'
EMAIL_BACKEND = 'django_ses.SESBackend'
Jul 18, 2011
Rename django admin app name and breadcrumbs
from django.db.models.base import ModelBase
from django.core.urlresolvers import resolve
class AppLabelRenamer(object):
''' Rename app label and app breadcrumbs in admin. '''
def __init__(self, native_app_label, app_label):
self.native_app_label = native_app_label
self.app_label = app_label
self.module = '.'.join([native_app_label, 'models'])
class string_with_realoaded_title(str):
''' tnx to Ionel Maries Cristian for http://ionelmc.wordpress.com/2011/06/24/custom-app-names-in-the-django-admin/'''
def __new__(cls, value, title):
instance = str.__new__(cls, value)
instance._title = title
return instance
def title(self):
return self._title
__copy__ = lambda self: self
__deepcopy__ = lambda self, memodict: self
def rename_app_label(self, f):
app_label = self.app_label
def rename_breadcrumbs(f):
def wrap(self, *args, **kwargs):
extra_context = kwargs.get('extra_context', {})
extra_context['app_label'] = app_label
kwargs['extra_context'] = extra_context
return f(self, *args, **kwargs)
return wrap
def wrap(model_or_iterable, admin_class=None, **option):
if isinstance(model_or_iterable, ModelBase):
model_or_iterable = [model_or_iterable]
for model in model_or_iterable:
if model.__module__ != self.module:
continue
if admin_class is None:
admin_class = type(model.__name__+'Admin', (admin.ModelAdmin,), {})
admin_class.add_view = rename_breadcrumbs(admin_class.add_view)
admin_class.change_view = rename_breadcrumbs(admin_class.change_view)
admin_class.changelist_view = rename_breadcrumbs(admin_class.changelist_view)
model._meta.app_label = self.string_with_realoaded_title(self.native_app_label, self.app_label)
return f(model, admin_class, **option)
return wrap
def rename_app_index(self, f):
def wrap(request, app_label, extra_context=None):
requested_app_label = resolve(request.path).kwargs.get('app_label', '')
if requested_app_label and requested_app_label == self.native_app_label:
app_label = self.string_with_realoaded_title(self.native_app_label, self.app_label)
else:
app_label = requested_app_label
return f(request, app_label, extra_context=None)
return wrap
def main(self):
admin.site.register = self.rename_app_label(admin.site.register)
admin.site.app_index = self.rename_app_index(admin.site.app_index)
# Example
AppLabelRenamer(native_app_label=u'exampleapp', app_label=u'your custom label').main()
Оригинал: http://djangosnippets.org/snippets/2488/
См. также: Изменение названия модуля в django admin
Jul 14, 2011
Decorators ideas
def get_article_from_id(view):
"""
Retrieves a specific article, passing it to the view directly
"""
def wrapper(request, id, *args, **kwargs):
article = get_object_or_404(Article, id=int(id))
return view(request, article=article, *args, **kwargs)
return wraps(view)(wrapper)
def content_type(c_type):
"""
Overrides the Content-Type provided by the view.
Accepts a single argument, the new Content-Type
value to be written to the outgoing response.
"""
def decorator(view):
def wrapper(request, *args, **kwargs):
response = view(request, *args, **kwargs)
response['Content-Type'] = c_type
return wraps(view)(wrapper)
return decorator
def dual_format(template_name):
def decorator(view):
def wrapper(request, *args, **kwargs):
data = view(request, *args, **kwargs)
if request.is_ajax():
json = simplejson.dumps(data, cls=DjangoJSONEncoder)
return HttpResponse(json)
else:
context = RequestContext(request)
return render_to_response(template_name, data, context)
return wraps(view)(wrapper)
return decorator
def logged(view):
"""
Logs any errors that occurred during the view
in a special model design for app-specific errors
"""
def wrapper(request, *args, **kwargs):
try:
return view(request, *args, **kwargs)
except Exception, e:
# Log the entry using the application’s Entry model
Entry.objects.create(path=request.path, type='View exception', description=str(e))
# Re-raise it so standard error handling still applies
raise
return wraps(view)(wrapper)
Jul 4, 2011
Currency template filter
from django import template
import locale
register = template.Library()
@register.filter(name='currency')
def currency(value):
try:
locale.setlocale(locale.LC_ALL,'en_US.UTF-8')
except:
locale.setlocale(locale.LC_ALL,'')
loc = locale.localeconv()
return locale.currency(value, loc['currency_symbol'], grouping=True)
Making Changes to a Database Schema
Adding Fields
- Add the field to your model.
- Run manage.py sqlall [yourapp] to see the new CREATE TABLE statement for the model. Note the column definition for the new field.
- Start your database’s interactive shell (e.g., psql or mysql, or you can use manage.py dbshell). Execute an ALTER TABLE statement that adds your new column.
Adding NOT NULL Columns
BEGIN;
ALTER TABLE books_book ADD COLUMN num_pages integer;
UPDATE books_book SET num_pages=0;
ALTER TABLE books_book ALTER COLUMN num_pages SET NOT NULL;
COMMIT;
Removing Fields
- Remove the field’s code from your model class and restart the Web server.
- Remove the column from your database, using a command like this:
ALTER TABLE books_book DROP COLUMN num_pages;
- Remove the ManyToManyField code from your model class and restart the Web server.
- Remove the many-to-many table from your database, using a command like this:
DROP TABLE books_book_authors;
Using South ;)
South brings migrations to Django applications. Its main objectives are to provide a simple, stable and database-independent migration layer to prevent all the hassle schema changes over time bring to your Django applications.
Jun 30, 2011
Request useful methods
request.path # the full path, not including the domain "/hello/" but including the leading slash
request.get_host() # the host (i.e., the “domain,” in common "127.0.0.1:8000" or parlance) "www.example.com"
request.get_full_path() # the path, plus a query string (if available) "/hello/?print=true"
request.is_secure() # True if the request was made via HTTPS; True or False otherwise, False
Jun 29, 2011
Find the real location of the exception
The problem with Django is that there are certain circumstances where it will hide the actual error message and traceback and replace it will a higher level exception, but with the traceback then being where that higher level exception was raised. This is one such case. To try and find the real location of the exception add the following to your WSGI script file.
import traceback
import sys
def dump_exception(callable):
def wrapper(*args, **kwargs):
try:
return callable(*args, **kwargs)
except:
traceback.print_exception(*sys.exc_info())
return wrapper
import django.core.urlresolvers
urlresolvers.get_callable = dump_exception(urlresolvers.get_callable)
This wraps the call which is doing the lookup and will dump out the error message it raises before the traceback gets thrown away.
Jun 25, 2011
Изменение названия модуля в django admin
class Stuff(models.Model):
class Meta:
verbose_name = u'The stuff'
verbose_name_plural = u'The bunch of stuff'
django admin использует app_label.title() поэтому мы можем использовать небольшой хак: подкласс str с переопределенным методом title:
class string_with_title(str):
def __new__(cls, value, title):
instance = str.__new__(cls, value)
instance._title = title
return instance
def title(self):
return self._title
и в итоге получаем:
class Stuff(models.Model):
class Meta:
app_label = string_with_title("stuffapp", "The stuff box")
# 'stuffapp' is the name of the django app
verbose_name = 'The stuff'
verbose_name_plural = 'The bunch of stuff'
См. также: Rename django admin app name and breadcrumbs
Jun 24, 2011
Полезные функции в Django
- django.utils.datastructures.SortedDict
- django.utils.datastructures.MultiValueDict
- По умолчанию в Python объект
dictне поддерживает сортировку ключей и несколько значений для одного ключа. Именно поддержку этих возможностей дают перечисленные выше классы. Например, поддержкаGET,POST,REQUESTмассивов в объектеrequestреализована в видеMultiValueDictобъектов. - django.utils.dates
- Этот модуль содержит разнообразные массивы, которые используются для печати SelectDateWidget'а.
- django.utils.encoding.force_unicode
- Переводит любой Python объект в
unicode. Так же переводит вunicodeлюбую модель Django у которой есть метод__unicode__. - django.utils.html.clean_html
- Очищает переданный в функцию HTML строку, а именно:
- Конвертирует
<b>и<i>в<strong>и<em>. - Правильно кодирует все амперсанды.
- Удаляет все
"target"аттрибуты с тегов<a>. - Конвертирует явно заданные баллетсы (bullets) в неупорядоченные HTML списки.
- Удаляет из текста фрагменты
"<p> </p>", но только если они находятся в конце текста.
- Конвертирует
- django.utils.html.urlize
- Переводит все ссылки в тексте в
<a>тэги. - django.utils.safestring.mark_safe
- Обозначает любой строковой объект, как безопасный для того, чтобы он мог был беспрепятственно распечатан в шаблоне без эскейпинга символов.
- django.utils.text.get_text_list
- Для описания работы этой функции и
doctest'а хватит: - >>> get_text_list(['a', 'b', 'c', 'd'])
- u'a, b, c or d'
- >>> get_text_list(['a', 'b', 'c'], 'and')
- u'a, b and c'
- >>> get_text_list(['a', 'b'], 'and')
- u'a and b'
- >>> get_text_list(['a'])
- u'a'
- >>> get_text_list([])
- u''
Jun 22, 2011
Dkim
pydkim
Python module that implements DKIM (DomainKeys Identified Mail) email signing and verification. It also provides helper scripts for command line signing and verification.Snippet
from django.core.mail.backends.smtp import EmailBackend
from django.conf import settings
import dkim # http://hewgill.com/pydkim
class DKIMBackend(EmailBackend):
def _send(self, email_message):
"""A helper method that does the actual sending + DKIM signing."""
if not email_message.recipients():
return False
try:
message_string = email_message.message().as_string()
signature = dkim.sign(message_string,
settings.DKIM_SELECTOR,
settings.DKIM_DOMAIN,
settings.DKIM_PRIVATE_KEY)
self.connection.sendmail(email_message.from_email,
email_message.recipients(),
signature+message_string)
except:
if not self.fail_silently:
raise
return False
return True
Jun 20, 2011
Class-based views
class SomeFormView(TemplateResponseMixin, View):
template_name = 'some_form.html'
def get(self, request):
form = SomeForm()
return self.render_to_response({
'form': form,
})
def post(self, request):
form = SomeForm(request.POST)
if form.is_valid():
form.save()
messages.success(request, 'Your form has been saved!')
return self.render_to_response({
'form': form,
})
class AjaxThingView(View):
# Note that I don't subclass the TemplateResponseMixin here!
def get(self, request):
return HttpResponse(status=404)
def post(self, request):
id = request.POST.get('id')
# Do something with the id
return HttpResponse('some data')
Выполняем тесты быстрее
import sys
if 'test' in sys.argv:
DATABASES['default'] = {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': 'test_database.sqlite'
}