На facotory-boy я набрел случайно, увидел название в комментариях на хабре. Погуглил и нашел factory-boy а гитхабе.
Facrtory-boy - это такая замена fixtures в django, которая позволяет более гибко и удобно генерировать данные для тестов с использование различных стратегий. Можно возвращать либо сохраненные модели, либо просто модели, пока еще не сохраненные, либо просто словарь атрибутов модели. Раздолье для творчества. Идея была позаимствована из аналогичной библиотеки factory-girl для руби. А написана она была Mark Sandstrom и сейчас активно занимается разработкой Raphaël Barrois.
Либо ставим с помощью easy_install factory_boy либо устанавливаем из исходников: python setup.py
Каждая фабрика представляет из себя класс, унаследованный от factory.Factory. Рекомендуется размещать фабрики в файле factories.py в директории с вашими тестами.
Создадим фабрики для пользователей (django.contrib.auth.User):
import factory
from models import User
# Фабрика для создания обычного пользователя
class UserFactory(factory.Factory):
FACTORY_FOR = User
first_name = 'John'
last_name = 'Doe'
admin = False
# Фабрика для создания привилегированного пользователя
class AdminFactory(factory.Factory):
FACTORY_FOR = User
first_name = 'Admin'
last_name = 'User'
admin = True
factory_boy поддерживает несколько различных стратегий создания экземпляров: build, create, attributes и stub.
# Возвращает не сохраненный экземпляр User
user = UserFactory.build()
# Возвращает сохраненный экземпляр User
user = UserFactory.create()
# Возвращает словарь аттрибутов, которые могут использоваться
# при создании экземпляра User
attributes = UserFactory.attributes()
# Возвращает объект со всеми определенными аттрибутами
stub = UserFactory.stub()
user = UserFactory()
# аналогично вызову
user = UserFactory.create()
Можно изменить это поведение переопределив свойство default_strategy. Это можно сделать как для конкретной фабрики, так и для всех дочерних фабрик factory.Factory
UserFactory.default_strategy = factory.BUILD_STRATEGY
user = UserFactory()
# переписываем стратегию для всех фабрик
factory.Factory.default_strategy = factory.BUILD_STRATEGY
На мой взгляд — это одна из самых убойных фич factory-boy. Она позволяет присваивать значения одних полей на основе значений других полей.
class UserFactory(factory.Factory):
first_name = 'Joe'
last_name = 'Blow'
email = factory.LazyAttribute(lambda a: '{0}.{1}@example.com'.format(a.first_name, a.last_name).lower())
UserFactory().email
# => 'joe.blow@example.com'
Если для ленивого аттрибута требуются какие-то значительные преобразования, которые не помещаются в лямбда функцию, то можно использовать декоратор для методов:
# Stub фабрики не могут быть ассоциированы с классом
class SumFactory(factory.StubFactory):
lhs = 1
rhs = 1
@lazy_attribute
def sum(a):
result = a.lhs + a.rhs # Or some other fancy calculation
return result
Это еще одна из убойных фич. Они нужны для того, чтобы создать связи ForeignKey моделей.
Associated instances can also be generated using LazyAttribute:
from models import Post
class PostFactory(factory.Factory):
author = factory.LazyAttribute(lambda a: UserFactory())
# Создаем и сохраняем наш экземпляр
post = PostFactory()
post.id == None # => False
post.author.id == None # => False
# Создаем экземпляр Post с сохраненным свойством author
post = PostFactory.build()
post.id == None # => True
post.author.id == None # => False
Фабрики можно наследовать и переписывать свойства.
class PostFactory(factory.Factory):
title = 'A title'
class ApprovedPost(PostFactory):
approved = True
approver = factory.LazyAttribute(lambda a: UserFactory())
factory.Sequence позволяет генерировать последовательности чисел. Этот прие может понадобиться для создания уникальных значений имён, email адресов и т.д.
class UserFactory(factory.Factory):
email = factory.Sequence(lambda n: 'person{0}@example.com'.format(n))
UserFactory().email # => 'person0@example.com'
UserFactory().email # => 'person1@example.com'
Последовательности можно комбинировать с ленивыми аттрибутами:
class UserFactory(factory.Factory):
name = 'Mark'
email = factory.LazyAttributeSequence(lambda a, n: '{0}+{1}@example.com'.format(a.name, n).lower())
UserFactory().email # => mark+0@example.com
или можно определить свой собственные алгоритм генерации последовательностей путем переопределения метода _setup_next_sequence:
class MyFactory(factory.Factory):
@classmethod
def _setup_next_sequence(cls):
return cls._associated_class.objects.values_list('id').order_by('-id')[0] + 1
Иногда не достаточно переопределить стратегию создания экземпляра и нужно вмешать в этот процесс. Здесь нам поможет переопределение метода _prepare:
class UserFactory(factory.Factory):
FACTORY_FOR = User
username = factory.LazyAttributeSequence(lambda a, n: 'username_{0}'.format(n))
first_name = factory.LazyAttributeSequence(lambda a, n: 'first_name_{0}'.format(n))
last_name = factory.LazyAttributeSequence(lambda a, n: 'last_name_{0}'.format(n))
email = factory.LazyAttributeSequence(lambda a, n: 'person{0}@example.com'.format(n))
password = "password"
is_staff = False
is_active = True
is_superuser = False
@classmethod
def _prepare(cls, create, **kwargs):
password = kwargs.pop('password', None)
user = super(UserFactory, cls)._prepare(create, **kwargs)
if password:
user.set_password(password)
if create:
user.save()
return user
Если одна из ваших фабрик имеет поле, которое тоже является фабрикой, то вы можете определить его с помощью SubFactory. Лучше посмотреть пример работы:
class InnerFactory(factory.Factory):
foo = 'foo'
bar = factory.LazyAttribute(lambda o: foo * 2)
class ExternalFactory(factory.Factory):
inner = factory.SubFactory(InnerFactory, foo='bar')
>>> e = ExternalFactory()
>>> e.foo
'bar'
>>> e.bar
'barbar'
>>> e2 : ExternalFactory(inner__bar='baz')
>>> e2.foo
'bar'
>>> e2.bar
'baz'
Уверен, что использование этой библиотеки спасет кучу времени и облегчит работу, связанную с поддержание fixtures в актуальном состоянии.
Еще более подробно можно ознакомиться с исходниками на странице: factory-boy
Меня тоже можно фоловить на гитхабе, всякие клевые штуки рано или поздно я там нахожу.
Увидел интересную разработку. Называется css-terminal. Это простой букмарклет, который добавляет на страницу поле для ввода css правил. При каждом нажатии enter эти правила применяются на страницу. Очень удобная штука для правки страниц.
Поддерживаются браузеры с DOM2:
Более подробное описание можно посмотреть на странице http://barberboy.github.com/css-terminal/ Там же можно и установить букмарклет.
Исходники можно посмотреть на гитхабе github.com/barberboy/css-terminal
Перед тем как обновить проект на сервере я предпочитаю сжимать статический файлы (js и css).
Компрессоров на данный момент существует множество. Я использую yui compressor. Он дает лучшие результаты по сжатию css и js файлов. Статических файлы я храню в директории static проекта. Файлов может быть много, поэтому я это дело автоматизировал, написав скрипт на bash. Он рекурсивно проходится по директориям static и media и ищет файлы в которых встречается комбинация dev, которая заменяется на min.
#!/bin/bash
echo "Static compressor"
COMPRESSOR_PATH="/usr/bin/yui-compressor"
STATIC_PATH="./static"
MEDIA_PATH="./media"
for f in `find "$STATIC_PATH" "$MEDIA_PATH" \( -name '*.dev.js' -or -name '*.dev.css' \)`; do
command="$COMPRESSOR_PATH --type ${f##*.} -o ${f%.*.*}.min.${0##*.} $f"
echo $command
$command
done
Соответственно в шаблонах проекта у меня статические файлы определяются следующим образом: {% static "css/layout.dev.css" %}.
Соответственно на сервере для разработки используется layout.dev.css, а на production сервере layout.min.css.
Это всего лишь малая часть того, что можно оптимизировать. По оптимизации могу посоветовать лучший в Рунете ресурс по клиентской оптимизации.
Периодически я посматриваю как выглядели раньше некоторые сайты, еще во времена своего зарождения. Как выглядела design.ru или яндекс. Отправиться в прошлое мне помогает машина времени под названием web.archive.org.
Это наверное один из старейших и консервативных сайтов, аналогов у которого нет.
В очередной раз зашел на него и был приятно удивлен. Ребята запустили в бета-тестирования новую версию интерфейса.
На главной странице нас встречает форма ввода адреса сайта для отправки в прошлое.
Теперь навигация по сохраненным страницам стала более удобной. Сверху страницы показывается меню с помощью которого можно перемещаться во-времени.
Вот так например выглядел хабрахабр в самой первой его редакции. Интересно почему я тогда не зарегистрировался на нем?

Загорелся очередным проектом. Идея меня посещала неоднократно, но не мог найти в себе силы за нее взяться. В данной нише уже существую сайты, которые создавались более 5 лет назад, чего достаточно для укрепления позиция. Но ни один из них не смог полностью удовлетворить мои потребности.
Идей у меня много. Но я решил пойти совсем другим путем, нежели раньше. Разработка ведется небольшими итерациями и обновления выкладываются постоянно.
За основу пока взят движок throwcatch.me, но раздел q&a будет не основным. Сейчас уже разработан второй модуль - блоги. Они представлены в несколько урезанном виде, потому как я считаю, что из-за низкой посещаемости его можно отложить.
Сейчас разрабатывается один из основных модулей, и на мой взгляд самый нужный. В скором времени он будет запущен.
А пока приглашаю на сайт всех тех, кто интересуется предпринимательством на сайт о бизнесе, предпринимательстве