Допустим, у вас есть модель, которая хранит состояние в базе данных, данная модель связана с пользователями. Но как быть в случае неавторизованного пользователя? Хранить состояние в кукисах браузера. Для этого пришлось бы пробежаться по модулю и ставить проверки, добавлять новые методы, переменные. В итоге код превратится в сплошной if… else, а оно нам надо? «А что делать?» — спросите вы. (Надеюсь что не спросите =) Без паники! Я, как-а-вот, ваш спаситель, расскажу и покажу на выход.
Выход — сделать фейковую модель и орудовать ею, как и с обычной джанговской моделью.
Пример
class UserBasket(models.Model):
user = models.ForeignKey(User)
shakedtimes = models.IntegerField(default = 0)
Тогда нашей фейковой моделью будет
class AnonymousBasket(object):
def __init__(self, request, response):
self.shakedtimes = request.COOKIES.get('sk_times', '0')
self.response = response
Теперь в классе можно просто в одном месте добавить проверку на авторизованного пользователя. Но помимо получения значений, рабочий модуль может выполнить операцию сохранения. С моделью то ясно, жанга все сделает за нас, а вот фейковое сохранение надо прописать ручками.
def save(self):
self.response.set_cookie('sk_times', self.shakedtimes)
Красяво? Думаю да. Минусом выступает то что в фейковую модель необходимо передать объект запроса и ответа, но как вы собрались считывать и сохранять куки, а? А? То-то же.
Разместил: Виталий Волков в 20:12 Декабрь 12, 2009. Комментарии выключены
Рубрики: Без рубрики. Теги: code refactoring, cookies, django, python.
Предлагаю вашему вниманию небольшой снипет, который мы написали, когда понадобилось сделать вывод объектов по колонкам.
-
from django import template
-
-
-
register = template.Library()
-
-
-
class SplitObjectsNode(template.Node):
-
def __init__(self, objects, list):
-
self._objects = template.Variable(objects)
-
self._list = list
-
-
def render(self, context):
-
import math
-
columns_count = len(self._list)
-
objects = self._objects.resolve(context)
-
-
for item in self._list:
-
context[item] = []
-
-
if len(objects) == 0:
-
return ”
-
-
dec = float(len(list(objects))) / columns_count
-
mid = int(math.ceil(dec))
-
pass_part = len(list(objects)) % columns_count
-
count_full_cols = columns_count – pass_part
-
-
idx = 0
-
index = 0
-
for item in self._list:
-
step = mid
-
if idx >= pass_part and pass_part != 0:
-
step = mid – 1
-
context[item] = objects[index: step + index]
-
index += step
-
idx += 1
-
return ”
-
-
-
@register.tag
-
def split_objects(parser, token):
-
"""
-
Split content of the objects to equal parts. Number of parts is a count of passed arguments to tag.
-
-
Example:
-
{% split_objects objects col1 col2 col3 %}
-
<table><tr><td>
-
{% for item in col1 %} {{ item.title }} {% endfor %}
-
</td><td>
-
{% for item in col2 %} {{ item.title }} {% endfor %}
-
</td><td>
-
{% for item in col3 %} {{ item.title }} {% endfor %}
-
</td></tr></table>
-
"""
-
parts = token.contents.split()
-
if len(parts) < 3:
-
raise template.TemplateSyntaxError, "Tag should get at the least 3 arguments. Example usage is {% split_objects objects col1 col2 %}"
-
-
tagname = parts.pop(0)
-
objects = parts.pop(0)
-
return SplitObjectsNode(objects, parts)
Разместил: Виталий Волков в 11:06 Июнь 25, 2009. Комментарии выключены
Рубрики: Без рубрики. Теги: django, python.
После поисков редактора питоновских скриптов я прошустил довольно много, спрашивал, читал, изучал. Мне не нужен был ни Eclipse ни IDEA. Для моего домашнего ноута честно признатся таких монстров вообще не нужно.
В итоге остановился на emacs. Сейчас читаю классную статью, которую, если вы так же как и я решили перейти на emacs, можете прочитать вот
Кстати под Mac OS X есть отличная обертка над emacs Aquamacs
Разместил: Виталий Волков в 12:04 Апрель 19, 2009. Комментарии выключены
Рубрики: Познание нового, Полезное. Теги: emacs, python.
Христос Воскрес!
Воистину все постигается в чтении умных книг. Буквально недавно сообразил, какую возможно грубейшую ошибку мы совершили в создании одного приложения на Python. Мы использовали для вызова методов родительского класса super.
Пример:
-
class B:
-
-
def __init__(x, y):
-
self.x = x
-
self.y = y
-
-
def setX(x):
-
self.x = x
-
-
-
class A(B):
-
def __init__(x, y, r):
-
super(A, self).__init__(x, y)
-
self.r = r
-
-
def setX(x):
-
super(A, self).setX(x + self.r)
А теперь посмотрим как было бы правильнее
-
class B:
-
-
def __init__(self, x, y):
-
self.x = x
-
self.y = y
-
-
def setX(self, x):
-
self.x = x
-
-
-
class A(B):
-
def __init__(self, x, y, r):
-
B.__init__(self, x, y)
-
self.r = r
-
-
def setX(self, x):
-
B.setX(self, x + self.r)
Разместил: Виталий Волков в 10:04 Апрель 19, 2009. Комментарии выключены
Рубрики: Познание нового. Теги: python, наследование.
Решили перевести наш сервер на версию Python 2.6. Замечу что до этого использовали 2.5, что как оказалось является довольно устаревшей. Ну решили – начал переводить.
Казалось бы что сложного, но Gentoo всячески отказывалась принимать версию из-за того что она была замаскирована. Что это означает я даже не подозреваю, поэтому раз через emerge не хотела, то решил просто собрать исходники.
Скачал необходимую версию питона, скомпилил – все отлично, осталось перевести ссылку python и python-config на новую версию.
# rm /usr/bin/python /usr/bin/python-config
# ln -s /usr/local/bin/python2.6 /usr/bin/python
# ln -s /usr/local/bin/python2.6-config /usr/bin/python-config
Все отличненько и
# python --version
вернула 2.6.2, осталось пересобрать mod_python, чтобы он использовал обновленный питон. Сделал через обычный emerge.
В итоге все довольны, и осталось только переустановить все необходимые пакеты (дада, именно переустановить, обычное линкование не очень хороший метод), чтобы все проекты поднялись.
Разместил: Виталий Волков в 12:04 Апрель 16, 2009. Комментарии выключены
Рубрики: Без рубрики. Теги: apache, gentoo, mod_python, python.
Заметил что hasattr в коей мере некорректно работает на определение наличия аттрибута в классе, пришлось отказаться от него и использовать такую проверку
-
if "value" not in MyClass.__dict__:
-
pass
Какие минусы этого подхода полностью не знаю, но знаю что может привести в определенных ситуациях к зацикливанию, это в случае если использовать __setattr__ в паре с ним. Может у кого-то другие подходы? Или просвятит на предмет использования __dict__ :-)
Разместил: Виталий Волков в 15:02 Февраль 4, 2009. Комментарии выключены
Рубрики: Познание нового. Теги: python.
Простой трюк если вам необходимо создать объект из его названия.
Для себя я нашел простой набор функций
-
def _get_mod(modulePath):
-
return __import__(modulePath, globals(), locals(), [‘*’])
-
-
-
def _get_func(fullFuncName):
-
"""Retrieve a function object from a full dotted-package name."""
-
-
# Parse out the path, module, and function
-
lastDot = fullFuncName.rfind(u".")
-
funcName = fullFuncName[lastDot + 1:]
-
modPath = fullFuncName[:lastDot]
-
-
aMod = _get_mod(modPath)
-
aFunc = getattr(aMod, funcName)
-
-
# Assert that the function is a *callable* attribute.
-
assert callable(aFunc), u"%s is not callable." % fullFuncName
-
-
# Return a reference to the function itself,
-
# not the results of the function.
-
return aFunc
-
-
-
def _get_class(fullClassName, parentClass=None):
-
"""Load a module and retrieve a class (NOT an instance).
-
-
If the parentClass is supplied, className must be of parentClass
-
or a subclass of parentClass (or None is returned).
-
"""
-
aClass = _get_func(fullClassName)
-
-
# Assert that the class is a subclass of parentClass.
-
if parentClass is not None:
-
if not issubclass(aClass, parentClass):
-
raise TypeError(u"%s is not a subclass of %s" %
-
(fullClassName, parentClass))
-
-
# Return a reference to the class itself, not an instantiated object.
-
return aClass
После можно это использовать таким образом
-
model_type = _get_class("example.MyView")
Далее просто создаем экземпляр нашего класса
-
model_object = model_type()
Если надо вызвать определенный метод то достаточно воспользоваться getattr
-
getattr(model_object, ‘mymethod’)()
Разместил: Виталий Волков в 07:12 Декабрь 3, 2008. Комментарии выключены
Рубрики: Без рубрики. Теги: python, динамический вызов методов, объекты, создание объектов.
Иногда приходится выполнять запросы по нескольким условиям из одной таблицы. Как пример выборка какой нибудь статьи сначала по названию, потом по дате. В принципе такое будет выглядеть таким образом
-
try:
-
if not objects:
-
objects = search_for(h_date__day = param)
-
except:
-
objects = []
-
-
try:
-
if not objects:
-
objects = search_for(h_date__month = 11)
-
except:
-
objects = []
Попробуем с этим что то сделать =) Для этого вспомним что такое kwargs и args и насколько полезными они часто бывают.
-
objects = search_for(title__icontains = param)
-
-
if not objects:
-
objects = search_for(h_date__day = param)
-
-
if not objects:
-
objects = search_for(h_date__month = month)
Как видно я вынес одинаковую часть в отдельный метод. Посмотрим что делает этот метод:
-
def search_for(*args, **kwargs):
-
try:
-
objects = MyModelObject.objects.filter(*args, **kwargs)
-
except:
-
objects = []
-
return objects
Ничего сверхъестественного, верно? А можно унифицировать метод и использовать его где захочется для простой фильтрации.
-
def filter_for(model, *args, **kwargs):
-
try:
-
objects = model.objects.filter(*args, **kwargs)
-
except:
-
objects = []
-
return objects
-
-
-
def func(request, param):
-
filter_for(MyModel, title_icontains = param)
Разместил: Виталий Волков в 05:11 Ноябрь 25, 2008. Один комментарий... »
Рубрики: Без рубрики. Теги: django, filter, kwargs, python.
Декоратор в питоне это не одно и тоже что и декоратор в шаблонах проектирования как бы это показалось на первый взгляд. Декоратор в понимании шаблонов проектирования добавляет функциональность в runtime, а python декораторы делают это только во время определения функции. В этом и есть огромная разница между ними.
Далее под словом «декоратор» имеем ввиду python декоратор.
Декоратор определяется знаком @ и названием в начале функции. Пример (взят с вики):
-
@viking_chorus
-
def menu_item():
-
print "spam"
Данное определение эквивалентно
-
def menu_item():
-
print "spam"
-
menu_item = viking_chorus(menu_item)
Здравствуй аспектно ориентированное программирование. Теперь сам декоратор.
-
def viking_chorus(myfunc):
-
def inner_func(*args, **kwargs):
-
for i in range(8):
-
myfunc(*args, **kwargs)
-
return inner_func
В итоге мы получим не что иное как вывод слова spam целых восемь раз. Декораторы как и любые функции могут принимать параметры.
Например
-
def console(text_to_print):
-
def dec(func, *args, **kwargs):
-
print text_to_print
-
func(*args, **kwargs)
-
return dec
-
-
@console("ahtung")
-
def index():
-
print "test"
Выведет сначала ahtung и только потом test.
Пример, если декорируемая функция получает дополнительные аргументы. Взят из пакета pybb, надеюсь автор не против =).
-
def ajax(func):
-
def wrapper(request, *args, **kwargs):
-
if request.method == ‘POST’:
-
try:
-
response = func(request, *args, **kwargs)
-
except Exception, ex:
-
response = {‘error’: traceback.format_exc()}
-
else:
-
response = {‘error’: {‘type’: 403, ‘message’: ‘Accepts only POST request’}}
-
if isinstance(response, dict):
-
return JsonResponse(response)
-
else:
-
return response
-
return wrapper
И пример его использования
-
@ajax
-
def setstatus(request):
-
return {‘newstate’: ‘updated’, ‘date’: ‘2008-08-21’}
Функция может быть задекорирована не только одним декоратором, их может быть несколько.
-
@accepts(int,int)
-
@returns(float)
-
def bar(low,high):
-
pass
Или тоже самое в виде списка
-
[@accepts(int,int), @returns(float)]
-
def bar(low,high):
-
pass
Как оформлять дело каждого, но скорее более читабельным все таки является последовательное декорирование, то есть первый вариант.
Использовал материал и код из
Трека pybb:
http://pybb.org/browser/pybb/util.py
Вики:
http://en.wikipedia.org/wiki/Python_syntax_and_semantics#Decorators
http://ru.wikipedia.org/wiki/Python#.D0.94.D0.B5.D0.BA.D0.BE.D1.80.D0.B0.D1.82.D0.BE.D1.80.D1.8B
Офсайта:
http://www.python.org/dev/peps/pep-0318/
Разместил: Виталий Волков в 06:11 Ноябрь 18, 2008. Комментарии выключены
Рубрики: Без рубрики. Теги: python, декоратор.
Иногда программисты которые пишут приложения почему то игнорируют написание тестов, а то и вообще их избегают. Я не могу сказать, что я профи в разработке через тестирование, но разработав пару классов и применив их в проекте, уже могу точно сказать, что классы, написанные через тесты обладают наибольшей стабильностью. Конечно, есть еще у меня некоторые недоработки, которые я стараюсь заполнять сразу же.
Практически процесс довольно интересный, хоть и может показаться долгим и утомительным, но как я заметил, когда писал код я вижу слабые участки (а порой ленюсь их исправлять, но позже все таки исправляю), код становится более чистым, особенно, когда отрефакторишь и прогонишь функционал через тесты. А видеть при прогоне слово Ok просто блаженство.
Кстати заметил фишку в разработке тестов в unittest питона. Если в начало теста поставить описание docline то при проходе отобразится не скучный путь до пакета и модуля а полноценное описание теста. К примеру
-
def testSetRatingTwice(self):
-
"Expect raising of exception when user set rating for object twice"
-
# functional of the test
-
self.assertRaises(….)
Ну конечно и отказываться от пакета и модуля не советую, оставить хотя бы название модуля и теста, для того чтобы найти в приложении нужный файл быстрее, чем рыться по полчаса в поисках.
Очень не нравится пакет pymock, который очень часто вводит меня в ступор своими Inappropriate action или чем то подобным, поэтому стараюсь как можно чаще избегать подобных тестов, а то и вообще не прибегать к mock совсем.
Продолжаю процесс разработки через тестирование.
Разместил: Виталий Волков в 21:10 Октябрь 17, 2008. Комментарии выключены
Рубрики: Познание нового, Полезное. Теги: docline, python, unittest, разработка, тестирование.