Июнь 3, 2008 в 00:43 |
db
django
python
snippets
web
- Автор Александр Кошелев |
|
Я всё продолжаю по рабочим и не только нуждам ковырять наследование моделей, поэтому как и обещал - то ли ещё есть!
Очередной сюрприз ждал меня, когда я обновляя свой блог-движок под текущий транк. Я обнаружил сломанным блок "Архив" из-за того, что метод dates() перестал возвращать уникальные значения на месяца, а выдавал мне всё подряд. Я сильно удивился. Но пофиксил всё при помощи, в последнее время моего любимого, set. Да, костыль, но ковырять дальше пока желания нет.
Далее уже по рабочим нуждам обновления тест наборы для приложения, проявились некоторые особенности работы fixtures. Для примера, допустим у нас есть такие связанные наследованием модели:
class Base( models.Model ):
field1 = models.IntegerField( default = 10 )
# + неявное поле id
class Derived( Base ):
field2 = models.IntegerField( default = 1 )
# + неявное поле base_ptr
Сериализатор дампит модель наследника целиком, т.е. со всеми полями в том числе и родителей.
При загрузке модели родителей не могут подцепить свой первичный ключ, а просто делают новый INSERT, получая тем самым новый id. Потом этот ...
Май 19, 2008 в 16:11 |
django
orm
python
snippets
web
- Автор Александр Кошелев |
|
И так, некоторые время назад состоялось моё погружение в новый для джанго мир наследования моделей. Как и в моих домашних проектах и так и в рабочих. Исследованию подверглось мульти-табличное наследование. Среди достаточного количества удобных и полезных свойств наследования преподнесло несколько неожиданностей и даже ошибок, которые были обнаружены в механизме самой джанги.
Начнем с особенностей:
Кастомные менеджеры наследуются. Что вполне логично, если учесть, что менеджер это всего-лишь обычное поле класса, которое при наследовании переходит к наследнику. Но, что не очень очевидно на первый взгляд, так то, что он остается "прикрепленным" к модели предка и его использование с моделью наследника будет давать не совсем ожидаемы результат. Вот пример:
class Base( models.Model ):
field1 = models.IntegerField()
objects = models.Manager()
my_custom_manager = MyManager()
class Derived( Base ):
field2 = models.IntegerField()
#...
Derived.my_custom_manager.filter( field2 = 777 )# Вот это не сработает
# и ругнется на отсутсвие данного поля у Base модели, что есть правда
Отсюда вывод - переопределяйте свои менеджеры в моделях наследниках. Вот соответствующее обсуждение в джанго-девелоперс
Теперь немного ...
Май 14, 2008 в 00:27 |
django
orm
python
web
ссылки
- Автор Александр Кошелев |
|
В очередной раз разгребая от непомерного груза непрочитанных RSS свой ридер, наткнулся на примечательный пост некого Энди Маккея (кстати блог у него на джанге. Узнал случайно - получив от него как-то стандартный джанговский 404:)).
Суть в том, что он применяет джангу в качестве базы для прототипирования Zope приложений. Поскольку как вы сами прекрасно понимаете, на джанго быстрее и проще сделать что-работающее. Использует все вкусности ORM и CRUD'а для добавления тестовых данных. Потом набивает тесты с необходимым функционалом и "ворует" у ORM сгенерированные SQL запросы, портируя их в ZSQLMethods(это такая зопавская(вау!:)) обертка над SQL запросами). Да, зачем мучит себя ручным написанием мудреных запросов, когда можно поручить это машине, а самому кайфовать от высокоуровневых абстракций. Не правда ли элегантное и остороумное решение?:)
И действительно. Ведь так удобно: быстренька набросать модельки, попутно ещё и DDL получить бесплатно, потом набить всё это необходимой логикой и получит у любезного ORM SQL запросы. Которые после недавних событий стали гораздо валиднее и краше. Класс!
Только ...
Май 12, 2008 в 00:54 |
django
python
snippets
web
- Автор Александр Кошелев |
|
Давно уже сталкиваюсь с одним неудобством в повседневной работе с джангой.
Например у нас есть моделька:
class Entry( models.Model ):
title = models.CharField( max_length = 150 )
type = <...>
И каким полем выразить тип (да, знаю, что имя конфликтует со встроенным, но тут это не принципиально)? "Ха!" - скажут некоторые. Да просто взять IntegerField и сделать типы целыми числами от 0 до сколько надо. Легко!
TYPES = ( ( 0, _( "inactive" ) ),
( 1, _( "active" ) ) )
class Entry( models.Model ):
title = models.CharField( max_length = 150 )
type = models.PositiveIntegerField( choices = TYPES )
Казалось бы, проблема решена. И этим можно пользоваться. Но, тут сразу начинаются неудобства.
Для того чтобы код не превращался в склад "магических чисел" надо добавить соответствующие константы, которые описывают эти два типа.
INACTIVE = 0
ACTIVE = 1
# или даже
INACTIVE, ACTIVE = range( 0, 2 )
потом можно пойти ещё дальше и выразить choices через них, чтобы было меньше дублирования
TYPES = ( ( INACTIVE, _( "inactive" ) ),
( ACTIVE, _( "active" ) ) )
Теперь можно вполне себе удобно использовать это хозяйство. И выборки делать и прочие проверки ...
Апрель 27, 2008 в 08:01 |
db
django
orm
python
web
- Автор Александр Кошелев |
|
Наконец-то! Уверен, что я не один воскликнул это слово, когда узнал что долгожданная queryset-refactor ветка влилась в транк и теперь ORM в джанго стал ещё лучше и удобней! Этого момента ждали долга, поскольку это один из самых больших шагов по направлению к 1.0 версии джанги. Итак, что же мы получили.
Начну с основных изменения уже имеющегося функционала:
Указание сортировки по при-join-ненным моделям теперь стало более логичным и совпадает с фильтрами lookup'ов. Просто пример:
Order.objects.all().order_by( "product__price" )
Обновлена реализация __iter__ метода queryset'a. И не грузит все строки результат в память сразу.
Особенно меня радует: сделана нормальная обработка None значения в lookup'ах. Т.е. если раньше приходилось писать писать воркэраунды для случая когда селект осуществлялся по NULL значениям, например так:
if value is None:
queryset = queryset.filter( field__isnull = True )
else:
queryset = queryset.filter( field = value )
То теперь эта проверка лишняя не нужна. Ура!)
Есть ещё некоторое количество изменений, но они на низко уровне и на прямую ...