Публикации с меткой «model»

Блог django на хабрахабре

Django Framework / [Ссылка] История валидации на уровне модели

Моим пятым переводом c DjangoAdvent.com стала статья Хонзы Крала «History of model validation». Исходя из названия можно догадаться, что речь пойдёт об истории валидации на уровне модели.

Оригинал: http://djangoadvent.com/1.2/history-model-validation/

Предыдущие переводы:
http://habr.ru/p/108389/ — Естественные ключи.
http://habr.ru/p/107035/ — Права доступа к объекту.
http://habr.ru/p/103896/ — Mingus: за что я его ненавижу.
http://habr.ru/p/113439/ ― Усовершенствование шаблонов Django.

Еще один блог о Django

По-настоящему, рабочий Django PickleField

Важно: предыдущая версия PickleField'а была практически неработающей в большинстве случаев. Теперь же появилось время в связи с ангиной, и я быстро исправил эту оплошность.

Иногда возникает необходимость хранить какие-то данные, "сериализированные" с помощью pickle или cPickle, в базе данных. Для этих случаев весьма кстати будет PickleField. Вообщем, может быть кому-то пригодится.

from django.conf import settings
from django.db import models

if getattr(settings, 'USE_CPICKLE', False):
    import cPickle as pickle
else:
    import pickle

class PickleField(models.TextField):
    __metaclass__ = models.SubfieldBase

    editable = False
    serialize = False

    def get_db_prep_value(self, value):
        return pickle.dumps(value)

    def to_python(self, value):
        if not isinstance(value, basestring):
            return value

        # Tries to convert unicode objects to string, cause loads pickle from
        # unicode excepts ugly ``KeyError: '\x00'``.
        #
        # If not possible, return this value, cause it's not pickled yet.
        if isinstance(value, unicode):
            try:
                str_value = str(value)
            except UnicodeEncodeError:
                return value
        else:
            str_value = value

        try:
            return pickle.loads(str_value)
        except ValueError:
            # If pickle could not loads from string it's means that it's Python
            # string saved to PickleField.
            return value

Также добавил простейший тест для показания работы PickleField'a:

import unittest

from django.db import models

from fields import PickleField

class PickleObject(models.Model):
    name = models.CharField(max_length=16)
    data = PickleField()

class TestPickleField(unittest.TestCase):
    def setUp(self):
        PickleObject.objects.all().delete()

    def test_not_string_data(self):
        items = [
            'Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5'
        ]

        obj = PickleObject.objects.create(name='default', data=items)
        self.assertEqual(PickleObject.objects.count(), 1)

        self.assertEqual(obj.data, items)

        obj = PickleObject.objects.get(name='default')
        self.assertEqual(obj.data, items)

    def test_string_and_unicode_data(self):
        DATA = (
            ('string', 'Simple string'),
            ('unicode', u'Simple unicode string'),
        )

        for name, data in DATA:
            obj = PickleObject.objects.create(name=name, data=data)
            self.assertEqual(obj.data, data)

        self.assertEqual(PickleObject.objects.count(), 2)

        for name, data in DATA:
            obj = PickleObject.objects.get(name=name)
            self.assertEqual(obj.data, data)

Надеюсь, что в скором времени эти изменения будут добавлены в django-fields.

Изучаем Django

Создание моделей

Немного теории

Модель в Django это описание сущностей приложения при помощи специального синтаксиса, например у нас может быть сущность пользователь с полями логин, пароль, адрес электропочты, дата рождения и сущность запись в блоге с полями заголовок, содержание и ссылкой на пользователя, который опубликовал запись. Модель описывается как класс, унаследованный от Model, поля объекта описываются путем присвоения значений из класса Model, каждое из значений означает один из допустимых типов полей. Для примера опишем указанные выше сущности:
        #сущность пользователь
 class User (models.Model):
  login = models.CharField(max_length=50)
  password = models.CharField(max_length=50)
  email = models.EmailField()
  age = models.DateField()
  
 #сущность запись в блоге
 class Post (models.Model):
  title = models.CharField(max_length=100)
  body = models.TextField()
  poster = models.ForeignKey('User')
Рассмотрим что же мы написали. Запись вида login = CharField(max_length=50) означает, что сущность пользователь обладает свойством логин, которое представлено строкой символов максимальной длиной 50, просто не правда ли? EmailField это поле для хранения адреса электропочты, DateField — для хранения даты, TextField для хранение текста, а ForeignKey определяет ссылку poster на объект класса пользователь. По описанию моделей Django сможет разработает для нас схему базы данных, создаст административный интерфейс и валидаторы. Мы написали всего 10 строчек кода, а получили достаточно много функций, это одна из основных идей рассматриваемого фреймворка — написание приложения с использованием меньшего количества кода. SQL-код сгенерированный Django по описанным моделям:
CREATE TABLE `default_post` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
    `title` varchar(100) NOT NULL,
    `body` longtext NOT NULL,
    `poster_id` integer NOT NULL
)
;
CREATE TABLE `default_user` (
    `id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
    `login` varchar(50) NOT NULL,
    `password` varchar(50) NOT NULL,
    `email` varchar(75) NOT NULL,
    `age` date NOT NULL
)
;
ALTER TABLE `default_post` ADD CONSTRAINT poster_id_refs_id_3b3164d6 
FOREIGN KEY (`poster_id`) REFERENCES `default_user` (`id`);

Приложение

Для завершения настройки нашего проекта создадим приложение — осмысленная часть нашего проекта выполняющая какие-либо действия. В Zend Framework можно найти аналогичный механизм — модуль. Пока не вижу необходимости разбивать наш проект на приложения, поэтому ограничимся одним и назовем его default. Запустите эту команду находясь в директории coblogs python manage.py startapp default Итак, мы получили новую директорию default, в ней вы найдете файл models.py, который содержит описания моделей, весь код описанный далее содержится в этом файле. Так же необходимо отредактировать settings.py, включив default в список установленных приложений
INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'coblog.default'
)

Модели

Напомню, что мы создаем сервис коллективных блогов с визуальным/wiki редактором, тегами, кармой и рейтингом постов и комментариев. Попробуем создать костяк моделей проекта, постепенно расширяя его при необходимости. Первая модель — наш дорогой и любимый пользователь, но описывать её не нужно в Django есть встроенный механизм аутентификации включающий модель User. Поля «стандартного пользователя»:
username
имя пользователя (логин), обязательное поле, не более 30 букв, цифр и знаков подчеркивания.
first_name
имя пользователя (по паспорту ;), опционально, не более 30 символов.
last_name
фамилия пользователя, опционально, не более 30 символов.
email
электропочта.
password
хеш пароля, обязательное поле, метод set_password поможет установить хэш по паролю.
is_staff
определяет, может ли пользователь использовать админку.
is_active
определяет, не заблокирован ли пользователь (true — не заблокирован).
is_superuser
если true, то пользователь имеет все возможные права.
last_login
дата и время последнего входа на сайт.
date_joined
дата и время создания аккаунта.
Кроме полей есть полезные стандартные методы, описанные в руководстве. Для пользователя в нашем проекте не хватает одного поля — кармы, добавим его, воспользовавшись механизмом профайлов:
# -*- coding: utf8 -*-  укажем кодировку этого файла

#подлючение механизма моделей
from django.db import models
#подключение стандартной модели пользователя
from django.contrib.auth.models import User
import math

class Profile(models.Model):
        #Порог уровня изменения кармы см. get_karma_delta
        KARMA_DELTA_THRESHOLD = 10

        #ссылка на стандратную модель пользователя
  user = models.ForeignKey(User, unique=True)
        __karma = models.IntegerField(default=0)

        def inc_karma(self, delta):
                """Увеличивает(или уменьшает) карму пользователя на delta"""
                self.__karma += delta

        def get_karma(self):
                """Возвращает карму пользователя"""
                return self.__karma

        def get_karma_delta(self):
                """
                Возвращает на какое значение пользователь может
                изменить карму другого пользователя
                """
                if self.__karma == 0:
                        return 1
                else:
                        return math.ceil(self.__karma/self.KARMA_DELTA_THRESHOLD)

  #Данный класс нужен для появления модели в административном интерфейсе 
                #(об этом в следующий раз)
        class Admin:
                pass
Для подключения нашего профиля добавим строку в settings.py:
AUTH_PROFILE_MODULE = "default.profile"
теперь профиль пользователя доступен при помощи метода get_profile(). Следующие модели — блог (пока содержит только название и описание) и запись в блоге:
class Blog(models.Model):
        caption = models.CharField(max_length=50)
        description = models.TextField()
        created = models.DateTimeField(auto_now_add=True)

        #функция __unicode__ определяет строковое представление объекта
  def __unicode__(self):
                return self.caption

        class Admin:
                pass

class Post(models.Model):
        """ Запись в блоге """
  #ссылка на блог в котором опубликована запись
        blog = models.ForeignKey(Blog)
  #ссылка на пользователя опубликовавшего запись
        poster = models.ForeignKey(User)

        #рейтинг записи
        __rate = models.IntegerField(default=0)

  #заголовок записи
        caption = models.CharField(max_length=50)
  #содержание записи (wiki-размеченный текст)
        content = models.TextField()
  #поле определяет, является ли запись черновиком
        draft = models.BooleanField(default = True)
  #дата создания
        created = models.DateTimeField(auto_now_add=True)
  #дата публикации (устанавливается после снятия опции черновик)
  posted = models.DateTimeField()

        def inc_rate(self, delta):
                self.__rate += delta

        def __unicode__(self):
                str = '';
                if self.draft:
                        str = ' (draft)';
                return self.caption + str

        class Admin:
                pass
И последние две модели — комментарий к записи в блоге и тэг к записи:
class Tag(models.Model):
        """ Тэг (метка) для записи в блоге """
        post = models.ForeignKey(Post)
        tag = models.CharField(max_length=30)

        def __unicode__(self):
                return self.tag

        class Admin:
                pass

class Comment(models.Model):
        post = models.ForeignKey(Post)
        parent = models.ForeignKey('self')
        user = models.ForeignKey(User)

        __rate = models.IntegerField()
        content = models.TextField()
        created = models.DateTimeField(auto_now_add=True)

        def inc_rate(self, delta):
                self.__rate += delta

        def __unicode__(self):
                return self.content

        class Admin:
                pass

Создание структуры базы данных

Пришло время магии :) создадим структуру базы данных из наших моделей. Для этого достаточно ввести команду:
python manage.py syncdb
Сгенерированный SQL-код можно посмотреть при помощи команды:
python manage.py sql default

Манипуляции с моделями

После создания структуры базы данных, можно познакомиться с Database API предоставляемый джанговским ORM. Откроем Python консоль и поэкспериментируем с методами моделей:
#> python manage.py shell
#импортируем стандартную модель пользователя
>>>from django.contrib.auth.models import User
#создадим экземпляр класса User и установим ему пароль '12345'
>>> user = User(username = 'testuser', first_name='Василий', last_name='Пупкин')
>>> user.set_password('12345')
#сохраним пользователя
>>> user.save()
#пользователь был успешно добавлен в БД, посмотрим сгенерированный id
>>> user.id
3L
#импортируем все наши модели
>>> from coblog.default.models import *
#создадим профиль пользователя для testuser и сохраним его в БД
>>> profile = Profile(user=user)
>>> profile.save()
#посмотрим карму
>>> user.get_profile().get_karma()
0L
>>> выведем имена всех пользователей
>>> for usr in User.objects.all() :
...     print usr
root
testuser
#напишем пост
>>> blog = Blog(caption='Блог о Django')
>>> blog.save()
>>> post = Post(poster= User.objects.get(username='testuser'),
caption='Database API', blog=blog)
>>> post.content = 'вот мы вкратце и ознакомились с Django Database API.'
>>> post.save()

Метки

.net .NET C# .sort 1.2 2009 2010 404 error admin ajax amazon analytics and apache api archlinux asp.net async asynchronous autocomplete bash blender blog blogengine blogs book bootstrap bot bpython buildout byteflow bzr C c plus plus C++ cache cbv Chaco checkio chrome ci ckeditor class based views clojure closure cms cms с удобной админкой code coding style collectd COM comet competition conference ConfigParser contest Context continuous integration CouchDB coverage CppCMS cpyext cpython crud csrf CSS ctypes curl custom model fields cx_freeze cython database db dbm dbqueries debian debug debugging decorator decorators deploy deployment descriptor design dev devconf developers development diveintopython Django django 1.2 django 1.3 django advent django framework django template django trunk django weblog django-admin-tools django-cms django-compressor django-hosts django-piston django-registration django-sphinx django.admin djangoadvent djangocms djangodash doc documentation drupal e-legion eclipse EGit emacs encoding Enthought epoll erlang event exception ExtJS fabric facebook fastcgi finaloption fixtures fonts forms formset fp framework freebsd freeswitch fs2web ftp fun funcparserlib functional gae gamin gandi generic views gettext gevent gil git github gitosis Google Google App Engine google picasa Google Translate google wave Google Web Toolkit grab grablab greenlet gtd gui haskell hg hgshelve highlighter host hosting how-to howto html html5lib Hudson humor i18n icfpc ide idiomatic image-scripting improvements Internet interpreter ipython ironpython izmenimsya.ru jabber java javascript jenkins jetbrains JIT job jquery json jstree jython kde kiev kiyv kyivpy l10n ldap library libs Life Links linux Linux & Unix LLVM logging logs lxml Mac OS X magic mail markdown Matplotlib Mayavi maybe mediavirus meetup memcache Memcached memory messages metaclass middleware migration mikrotik mkd model models mod_python mod_wsgi mongodb monitoring mptt musicmans.ru musicx mvc my-projects mysql netCDF networkx newforms newforms-admin news nginx Nhibernate nix nose NoSQL numpy oop open source OpenID openoffice opster optimization oracle orm os pagination parsing path patterns pdf PDF-принтер PEP PEP8 performance performance optimization perl personality photo php picture-driven computing PIL pinax pingback pip plasma plone plugin plugins postgresql programming progress bar psycopg2 py2exe pybb pybbm pycamp pycharm pycon pycow pycurl pydev pygtk pylons PyNGL pypy pyqt PyQt4 pyrad pyramid PySide Python Python 2.5 python 2.7 python 3 python c api python speed python-mssql python3 pywinauto Qt Qt4 queue rabbitmq radius raw sql re redis redsolution redsolution cms regexp regular expressions release repoze.bfg RequestContext reusable apps robokassa rss ru ruby ruby-on-rails sample satchmo scalability SciPy scraping screencast search selenium self.error seo server setattr settings setuptools shell sikuli sms snippet socket.io software sorting south sphinx spider sql sqlalchemy sqlite ssh startup step-by-step subdomain subversion svn SyntaxHighlighter system tags tdd tddspry teh drama template templates templatetags test testing thinkpad threading threads tips tips and tricks tools tornadio tornado tornado server tricks tutorial tweepy twisted twitter typography uapycon Ubuntu ucsvlog uml Uncategorized unicode unit test unit testing UnitTest Unladen Swallow upload urllib urls utf-8 uwsgi validation vcs versioning video vim virtualenv Visual Studio vkontakte voip wave web web-devel web-services web-разработка webdev webfaction webkit webpy websockets webtest widget widgets Win API windows Wirbel work wrapper wsgi wxPython wxWidgets wysiwyg xapian xml xmonad xmpp xpath yandex youtube zip zomg zope [cdata[cbv]] [cdata[ci]] [cdata[class based views]] [cdata[continuous integration]] [cdata[django framework]] [cdata[django-sphinx]] [cdata[django]] [cdata[nginx]] [cdata[python]] [cdata[virtualenv]] [cdata[программирование]] автоматизация администрирование администрирование django админка алгоритмы архитектура атрибуты базы данных Без рубрики безопасность библиотеки блоге бот веб-разработка видео Визуализация данных вконтакте Все записи гвидо ван россум граббер графика графы декоратор декораторы дескриптор дескрипторы документация заметки игра жизнь идея интересное киев Клиентам книги конференция личное математика метаклассы модели модули монады морфология мысли невозможное новости о облачные вычисления обо мне Обработка данных оптимизация оптимизация кода Основная лента основы парсинг парсинг сайтов перевод песочница Питон поебень поиск правила кодирования программирование Проектирование производительность работа рабочее размышлизмы Разное разработка разработка приложений разработки регулярные выражения сайт событие события ссылки статьи тестирование тесты Тюмень убунтариум фигня философия формы форум Хабрахабр хакинг хостинг шаблоны шаблоны проектирования эксперимент Эксперименты юмор я пиарюсь Яндекс