Oct 28, 2011

Search applications

django-watson - Full-text multi-table search application for Django. Easy to install and use, with good performance.

django-solr - Solr Search Engine ORM for Django
http://yuji.wordpress.com/2011/08/18/installing-solr-and-django-haystack-on-ubuntu-with-openjdk/
pip install django-haystack

sudo apt-get install openjdk-6-jre jetty solr-jetty

./manage.py build_solr_schema > schema.xml
sudo mv schema.xml /etc/solr/conf/schema.xml

sudo vi /etc/jetty/jetty.xml
#set default HAYSTACK_SOLR_URL setting port
#<Set name="port"><SystemProperty name="jetty.port" default="8983"/></Set>

sudo vi /etc/solr/conf/solrconfig.xml
#<lockType>simple</lockType>
#<unlockOnStartup>true</unlockOnStartup>

sudo vi /etc/init.d/jetty
# change port to 8983
# change user to root

sudo vi /etc/default/jetty
# change NO_START to be 0
# JAVA_HOME=YOUR_JDK_HOME

sudo /etc/init.d/jetty restart

./manage.py rebuild_index

Testing applications and extensions

Python Testing Tools Taxonomy
Django Packages: Testing Tools

Open Source Testing
Link Checker

django-testtools - A helper for writting Django's tests.
  • assertRecipients
  • assertQuerySetEqual
  • assertErrorsInForm
django-test-extensions - A set of custom assertions and examples for use testing django applications.
  • login_as_admin
  • ...
  • assert_file_exists
  • assert_key_exists
  • assert_has_attr
  • ...
  • assert_mail
  • assert_latest
  • assert_model_changes
django-autofixture - Can create auto-generated test data
from autofixture import AutoFixture
fixture = AutoFixture(Entry)
entries = fixture.create(10)
django-test-utils
  • Django Testmaker 
  • Django Crawler 
  • Django Test Runner 
  • Twill Runner 
  • Persistent Database Test Runner
+
./manage.py makefixture proposals.Proposal[:10] --indent=4 > proposal_with_related_items.json
factory_boy - A test fixtures replacement for Python based on thoughtbot's factory_girl for Ruby
import factory
from models import User

class UserFactory(factory.Factory):
    FACTORY_FOR = User

    first_name = 'John'
    last_name = 'Doe'
    admin = False

# Returns a User instance that's not saved
user = UserFactory.build()

# Returns a saved User instance
user = UserFactory.create()

# Returns a dict of attributes that can be used to build a User instance
attributes = UserFactory.attributes()

# Returns an object with all defined attributes stubbed out:
stub = UserFactory.stub()
rebar - Rebar makes your Forms stronger
from rebar.testing import flatten_to_dict

form_data = flatten_to_dict(ContactForm())
form_data.update({
        'name': 'X' * 300,
    })
form = ContactForm(data=form_data)
assert(not form.is_valid())
The same for formsets
from rebar.testing import flatten_to_dict, empty_form_data

formset = ContactFormSet()
form_data = flatten_to_dict(formset)
form_data.update(
    empty_form_data(formset, len(formset))
)

django-uuslug

https://github.com/un33k/django-uuslug - Guarantee a unique unicode slug for use in Django projects

Oct 26, 2011

Программист-прагматик. Путь от подмастерья к мастеру - Э. Хант, Д. Томас

Прагматическая философия

  • Хаос в программе пораждает еще большую неразбириху. Если есть недоработки стоит сразу их устранить.

Прагматический подход

  • DRY
  • Ортогональность системы - объекты не должны пересекаться или пересекаться минимально. (сцепление - cohesion)
  • Стрельба трассирующими
  • Прототип
  • Язык должен отражать предметную область (именование переменных)
  • Определять для себя на сколько точной должна быть оценка. Часто не обязательно знать 2 дня 10 часов обычно достаточно около 3х дней

Походный набор инструментов

  • Генераторы текстов: пассивные и активные (каждый пересоздают на основе актуальных данных)

Прагматическая паранойя

  • Контракты
  • Утверждения
  • Исключения используется только в действительно исключительных ситуациях. В противном случае они становятся подобны оператору goto.
  • Участок кода использующий ресурс отвечает и за его освобождение. Освобождаютя ресурсы в обратной последовательности по отношению к распределению этих ресурсов.

Гибкость против хрупкости

  • Несвязанность и закон Деметера 
  • Если есть возможность распараллелить программу, то эту возможность надо использовать (потоки, асинхронность).
  • "Доски объявлений" для координации потоков работ.
  • События, паттерны Observer и MVC хорошо подходят для графических интерфейсов.

Пока вы пишите программу

  • Хороший код можно написать только четко понимая что и как происходит. Это и есть преднамеренное программирование.
  • Оценку скорости алгоритма можно сделать определив его порядок. Цикл Q(n), вложенный цикл Q(m x n). Для сортировки лучше использовать библиотечные методы, скорость их работы оптимизирована.
  • Перед рефакторингом лучше убедиться что все тесты прошли успешно. Лучше рефакторинг проводить отдельно от добавления новых возможностей. После реорганизации обязательно проводить регрессионные тесты.
  • Тестовый стенд. Отладочное окно по горячим клавишам.

Перед тем как начать проект

  • Список новых изменений и требований поможет остановит их последующий лавинообразный рост.
  • Глоссарий терминов проекта позволит использовать их согласованно и новым участникам проекта понять их значение.
  • Если документы хранятся в проекте, то больше шансов, что их будут читать.
  • Часто у сложной проблемы есть простое решение. Его надо увидеть за навязываемым сложным.

Прагматические проекты

  • Если ручное тестирование обнаружило баг, то следует обязательно написать тест который бы находил эту ошибку, чтобы в будущем автоматизированное тестирование вылавливало его.
  • Если слегка превысить ожидания пользователей это сделает их более дружелюбными к вашему приложению.

Рефакторинг. Улучшение существующего кода - Мартин Фаулер




Книга будет интересна тем кто не пользуется pycharm :) Ну действительно, кому интересно как делается "Introduce variable", если с этим отлично справляется IDEшка? )))

Если серьезно, то в книге много полезной информации для чего делаются разные виды рефакторинга и, соответственно, есть каталог типов рефакторинга. Пометим несколько моментов..
Перед тем как проводить рефакторинг проверяется работоспособность кода, пишутся тесты.
Рефакторинг проводится поэтапно шаг за шагом, небольшими кусками кода и, обязательно, отдельно от добавления новой функциональности.
Не надо пытаться покрыть тестами все возможные варианты выполнения кода, но обязательно надо проверить все узкие места.

Источники неприятных запахов

  • Дублирование кода
  • Длинный метод
  • Большой класс
  • Длинный список параметров
  • Расходящиеся модификации (когда один класс модифицируется различными способами по разным функциональным причинам)
  • Стрельба дробью (изменения разбросаны по коду)
  • Завистливые функции (метод класса больше интересуется другим классом а не собственным)
  • Группы данных
  • Одержимость элементарными типами (валюта, номера телефонов, почтовые индексы)
  • Операторы switch
  • Параллельные иерархии наследования
  • Ленивый класс (лишний)
  • Теоретическая общность (программированное наперед)
  • Временное поле (когда в объекте атрибут устанавливается только при определенных обстоятельствах)
  • Цепочки сообщений (o.getBla().getFoo().getBar()...)
  • Посредник (лишний делегат)
  • Неуместная близость
  • Альтернативные классы с разными интерфейсами
  • Неполнота библиотечного класса
  • Классы данных
  • Отказ от наследства (например, пустой переопределенный метод)
  • Комментарии

CMSs

django-fiber
ella - Ella is an opensource CMS based on the Django framework. It originated in CentrumHoldings as CMS for their lifestyle magazines (mainly Žena.cz) with an ambition to become the only CMS powering all CentrumHoldings content websites from lifestyle magazines with medium traffic to news sites with millions of pageviews per day.

Oct 22, 2011

django-helptext

http://pypi.python.org/pypi/django-helptext/0.3 - A django application for editing django model field help text in the django admin

Oct 21, 2011

The Python Standard Library

http://docs.python.org/library/index.html

References & Development Aides

Using Vim with Django

https://code.djangoproject.com/wiki/UsingVimWithDjango

Oct 20, 2011

Web App Security: Django and the OWASP Top 10


  1. Code Injection:  For most Django applications, the primary code injection risk is SQL injection.  Django protects against SQL injection through its ORM abstraction layer, which automatically escapes input.  Note that it's possible toperform raw sql queries with Django, any any such code should be manually audited for if it interacts with direct user input.  Though raw SQL is needed occasionally, especially for optimization, it's generally a code smell in a Django application.

    If your application interacts with any other backends, like LDAP, you'll want to investigate those third-party libraries separately.  Client-side javascript is also mitigated through its templating system; see #2 below.
  2. Cross-site scripting:  Generally, the most important way to mitigate XSS is to prevent unescaped user input from making it into your application's rendered HTML. Django’s templating system facilitates this by automatically excaping all variable values.  If you don't want to escape something on the front end, you have to explicitly tell Django not to escape it.  In your code reviews, you can concentrate more on the few areas of your app where you don't escape user input.
  3. Session hijacking:  With the default Django SessionMiddleware, the framework doesn't allow any session data in the url.  Session IDs are also stored as hashes, mitigating brute force attacks.

    While you'll still want to ensure your code doesn't expose direct session data to the user in any way, Django makes it difficult to expose that information.
  4. Insecure direct object references:  Django has several mechanisms in place to mitigate IDORs.  It provides a special "slug" field if you don't want to pass object IDs around as parameters.  Django 1.2 also lets you explicitly name read-only fields in the admin, so you can prevent users from hacking together forms that alter protected  data.

    Note that you'll still want to manually audit your code to expose areas where users can access arbitrary object data, especially outside of the admin.
  5. Cross-site request forgery:  Django has built-in CSRF protection middleware, so it would be extraordinarily difficult for an attacker to maliciously submit a form to your site using an authenticated user's credentials.
  6. Security misconfiguration:  This is one item that is largely outside the domain of the web framework itself; it's more about the application's deployment environment.  You need to keep up with Python security updates, Django security updates, and keep track of any third-party libraries you use for security updates.  You need to disable ports/services you don't use, and more.  With complex apps, this can be a huge job.

    Fortunately, there are great, frequently-updated blogs for both the Python andDjango core teams where you can keep track of security updates.  It's also easy to follow security announcement lists for your web server (e.g. apachenginx) or operating system to keep track of security updates.
  7. Insecure cryptographic storage:  If the only secure information you're encrypting is user password data, you're all set if you use Django's built-in user authentication.  Django encrypts password data using SHA1 by default, but also supports MD5 and crypt out-of-the-box.

    If your application directly stores or manipulates any sensitive user data, you'll need to audit that code manually.  Fortunately, OWASP maintains a great cryptographic storage cheat sheet to help you along the way.
  8. Failure to restrict URL access:  Django has great built-in support for restricting access to specific content.  Access is always controlled at the view level, before anything is rendered.  You're able to restrict access for specific actions or forentire views.  Note that you'll still want to audit each url/action in your app to ensure that you're restricting access the way you intended.  It's easy to miss a @login_required decorator or forget to lock down an AJAX action.
  9. Insufficient transport layer protection:  In many cases, strong transport layer protection means using SSL.  Though this falls outside the domain of Django itself, the framework does provide some help:  Django supports the secure cookie protocol (PDF link to research paper), and also allows developers to force the use of secure cookies over HTTPS.
  10. Unvalidated redirects and forwards:  Because of Django's robust, built-in URL access restriction (see #7), it would be very hard for an attacker to take advantage of unvalidated redirects.  Again, since access is handled at the view level, you can't [easily] redirect users to a different url on your site without access control.

    Additionally, Django's built-in user authentication system doesn't allow off-site redirect links as url parameters.  Note that you'll still want to audit your code for any manual use of redirect links in URL parameters.

Django caching

Полезная презентация: Cache rules everything around me
http://lanyrd.com/2011/djangocon-us/shbrr/

django-cacheops

A slick app that supports automatic or manual queryset caching and automatic granular event-driven invalidation. It can also cache results of user functions and invalidate them by time or the same way as querysets. It uses redis as backend for ORM cache and redis or filesystem for simple time-invalidated one.

django-newcache

Ничего особо полезного не нашел. Есть бэкенд для pylibmc, но такой уже имеется в джанге.

johnny-cache

Кэширует все запросы. есть серьезные ограничения
Avoiding the database at all costs was not a goal, so different ordering clauses on the same dataset are considered different queries. Since invalidation happens at the table level, any table having been modified makes the cached query inaccessible
# cached, depends on `publisher` table
p = Publisher.objects.get(id=5)
# cached, depends on `book` and `publisher` table
Book.objects.all().select_related('publisher')
p.name = "Doubleday"
# write on `publisher` table, modifies publisher generation
p.save()
# the following are cache misses
Publisher.objects.get(id=5)
Book.objects.all().select_related('publisher')

django-autocache

В объект добавляется поле cache.
Instance Caching
class Model(django.models.Model):
    cache = autocache.CacheController()
    field = django.models.TextField()

Model.objects.get(pk=27)    # hits the database
Model.cache.get(27)         # Tries cache first
Related Objects Caching
instance = Model.cache.get(pk=27)
related_things = instance.things_set.all()  # hits the database
related_things = instance.cache.things_set  # Tries cache first
 Тоже есть ограничения
Autocache relies on the post_save and post_delete signals to keep your cache up to date. Performing operations that alter the database state without sending these signals will result in your cache becoming out of sync with your database.

cache-machine

Еще одна библиотека для автоматического кэширования и инвалидации. Ограничение - CachingManager должен быть менеджером модели по умолчанию
from django.db import models

import caching.base

class Zomg(caching.base.CachingMixin, models.Model):
    val = models.IntegerField()

    objects = caching.base.CachingManager()

django-cache-utils2

Django caching decorator + invalidate function
from cache_utils2 import cached, invalidate

@cached(60)
def foo(x, y=0):
    print 'foo is called'
    return x+y

foo(1, 2) # foo is called
foo(1, y=2)
foo(5, 6) # foo is called
foo(5, 6)
invalidate(foo, {'x': 1, 'y': 2})
foo(1, 2) # foo is called
foo(5, 6)
foo(x=2) # foo is called
foo(x=2)

Caching parsed templates

django.template.loaders.cached.Loader
https://docs.djangoproject.com/en/dev/ref/templates/api/#loader-types

Expire page from cache

from django.core.cache import cache
from django.http import HttpRequest
from django.utils.cache import get_cache_key

def expire_page(path):
    request = HttpRequest()
    request.path = path
    key = get_cache_key(request)
    if cache.has_key(key):   
        cache.delete(key)
http://djangosnippets.org/snippets/936/

Oct 19, 2011

Django servers benchmarks

fcgi vs. gunicorn vs. uWSGI
Benchmark of Python WSGI Servers

A Django setup

Using Nginx and Gunicorn
http://senko.net/en/django-nginx-gunicorn/

Using Nginx and uWsgi
http://grokcode.com/784/how-to-setup-a-linux-nginx-uwsgi-python-django-server/
http://www.eshlox.net/en/2012/09/11/nginx-uwsgi-virtualenv-and-django-ubuntu-1204/

A skeleton Django project

http://senko.net/en/django-quickstart-skeleton-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.

HTML5 Boilerplate

http://html5boilerplate.com/ - A rock-solid default for HTML5 awesome.

Bootstrap, from Twitter

http://twitter.github.com/bootstrap/

Bootstrap is a toolkit from Twitter designed to kickstart development of webapps and sites.It includes base CSS and HTML for typography, forms, buttons, tables, grids, navigation, and more.

Модель акторов

http://jodal.github.com/pykka/
http://ru.wikipedia.org/wiki/%D0%9C%D0%BE%D0%B4%D0%B5%D0%BB%D1%8C_%D0%B0%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2


Модель акторов исходит из такой философии, что всё вокруг является акторами. Это похоже на философию объектно-ориентированного программирования, где всё вокруг является некоторыми объектами, но отличается тем, что в объектно-ориентированном программировании программы, как правило, выполняются последовательно, в то время как в модели акторов вычисления по своей сути совпадают по времени.

Актор является вычислительной сущностью, которая в ответ на полученное сообщение может одновременно:
  • отправить конечное число сообщений другим акторам;
  • создать конечное число новых акторов;
  • выбрать тип поведения, которое будет использоваться для следующего сообщения в свой адрес.

Может существовать произвольная последовательность вышеописанных действий, и все они могут выполняться параллельно.

Развязка отправителя и посланных сообщений стала фундаментальным достижением модели акторов, обеспечившая асинхронную связь и управление структурами как прототип передачи сообщений.

Получатели сообщений идентифицируются по адресу, который иногда называют «почтовым адресом». Таким образом, актор может взаимодействовать только с теми акторами, адреса которых он имеет. Он может извлечь адреса из полученных сообщений или знать их заранее, если актор создан им самим.

Модель акторов характеризуется внутренне присущим параллелизмом вычислений внутри одного актора и между ними, динамическое создание акторов, включение адресов акторов в сообщения, а также взаимодействие только через прямой асинхронный обмен сообщениями без каких-либо ограничений на порядок прибытия сообщений.

Oct 16, 2011

Virtualenv + pip

Install easy_install, pip, virtualen

sudo apt-get install python-setuptools python-virtualenv python-pip

Create virtual environment

$ virtualenv --no-site-packages env # from version 1.7 --no-site-packages default behavior
$ source env/bin/activate

(env)$ export PYTHONPATH=  # sometimes required
(env)$ pip install django
# ...
(env)$ pip freeze > requirements.txt
(env)$ deactivate

$ virtualenv --no-site-packages env2
$ source env2/bin/activate
(env2)$ pip install -r requirements.txt

Pip

# concrete package version
(env)$ pip install ipython==0.11

# archive link
(env)$ pip install -f http://downloads.sourceforge.net/project/matplotlib/matplotlib/matplotlib-1.0/matplotlib-1.0.0.tar.gz matplotlib

# install for concrete python interpreter version
sudo pip install ipython -E python2.5

Bonuses

List all packages with requirements:
pip list --local | awk '{print $1}' | xargs pip show | grep -v -e '^Location' -e '^Requires: $'
yolk - list installed packages
(env2)$ pip install yolk
(env2)$ yolk -l
vanity - list available versions
(env2)$ pip install vanity
(env2)$ vanity django -v

PyCharm

If you use PyCharm you’ll want to set up your virtualenv there for your project. Edit your project settings. Select Python Interpreter -> Add -> Specify Other… Add python from your virtual_env (env/bin/python)

Oct 11, 2011

500/404 templates if you only use the admin

If you have a project that only exposes the admin you should just use the 500/404 templates from 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

My Vim plugins and config for comfortable Python / Django scripting

Generate ctags:
ctags --languages=Python -R --exclude=IPython --exclude=test --exclude=tests

Plugins:
python-mode
ctrlp.vim
django_template_textobjects
nerdtree
patchreview-vim
tagbar
ultisnips
vim-commentary
vim-repeat
vim-sparkup
vim-surround
vim-textobj-user
vim-unimpaired
vim-visual-star-search


Config:
set nocompatible

" Command line history size 
set history=1000
set undolevels=1000

" Set to auto read when a file is changed from the outside
set autoread

" Turn backup off, since most stuff is in SVN, git et.c anyway...
set nobackup
set nowb
set noswapfile

" Return to last edit position when opening files (You want this!)
autocmd BufReadPost *
     \ if line("'\"") > 0 && line("'\"") <= line("$") |
     \   exe "normal! g`\"" |
     \ endif

syntax enable
set autoindent

set t_Co=256
let g:solarized_termcolors=16
colorscheme jellybeans


" Tab completion like bash
set wildmode=longest,list
" Tab completion like zch
"set wildmenu
"set wildmode=full

set shiftwidth=4 softtabstop=4 expandtab

" Jump between special words
filetype plugin on
runtime macros/matchit.vim

" Disable arrow keys
noremap  
noremap  
noremap  
noremap  

" Pathogen load
filetype off
call pathogen#infect()
call pathogen#helptags()

filetype plugin indent on
syntax on
let g:pymode_folding = 0
"let g:pymode_rope_vim_completion = 0
"let g:pymode_rope = 0
"let g:pymode_lint_write = 0
"let g:pymode_lint_onfly = 1
"let g:pymode_lint_cwindow = 0
let g:ropevim_extended_complete=1

nmap  :set number!
nmap  :PyLintAuto
set pastetoggle=

nnoremap  :!ctags -R

nmap  :NERDTreeToggle
nmap  :TagbarToggle

noremap   :cal VimCommanderToggle()

" SEARCH

" enable ack
set grepprg=ack\ --nogroup\ --column\ $*
set grepformat=%f:%l:%c:%m

" mutes search highlight and redraws screen
nnoremap   :nohlsearch

set hls

" show search matches as you type
set incsearch
set ignorecase
set smartcase

" NETRW

let s:split_width=24

"let g:netrw_menu=0
let g:netrw_liststyle='tree'

let NERDTreeIgnore = ['\.pyc$', '^tags$', 'nohup.out']
let NERDTreeChDirMode=2
let NERDTreeMinimalUI=1
let NERDTreeDirArrows=1

" EX MODE

" %% instead %:h
cnoremap  %% getcmdtype() == ':' ? expand('%:h').'/' : '%%'

" Fixing the & Command
nnoremap & :&&
xnoremap & :&&

" set path+=apps/
"set path+gtemplates/
"set path+=/usr/local/lib/python2.7/dist-packages/

" SPELL

" syn spell toplevel
set spell
" autocmd BufNewFile,BufRead * setlocal spell spelllang=en 
autocmd BufNewFile,BufRead * syn spell toplevel

set mouse=a

let g:clipbrdDefaultReg = '+'

" When I close a tab, remove the buffer
set nohidden


if filereadable(".vimrc")
    so .vimrc
endif

Oct 10, 2011

Проверка состояния сервера и перезапуск в случае необходимости

Можно воспользоваться Supervisor или чем-то подобным, но для небольших проектов достаточно crontab:
crontab -e
Например, для проверки memcached каждую минуту:
*/1     *       *       *       *       netstat -ln | grep ":11211 " | wc -l | awk '{if ($1 == 0) system("/etc/init.d/memcached start") }'

Oct 5, 2011

Signals registration

Best place for Django signals is app/signals.py file. This snippet imports signal modules from all installed apps.
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/