Тестирование уникальности поля

65 views
Skip to first unread message

flipback

unread,
May 22, 2008, 2:44:55 AM5/22/08
to Django russian
Всем привет :)
Пишу свой первый маленький проект на Django. При написании тестов
столкнулся с проблемой при тестировании уникальности поля...

Вот модель
class Unit(models.Model):
part_number = models.CharField(maxlength = 14, unique = True)
name = models.CharField(maxlength = 30)
cost = models.FloatField(decimal_places = 2, max_digits = 9)
def __str__(self):
return self.namе

А вот ее тест
class UnitTestCase(unittest.TestCase):
def setUp(self):
self.unit = Unit.objects.create(
part_number = 'part_number_1',
name = 'name_1',
cost = 10.2)

def testValidate(self):
self.assertEquals(self.unit.validate(), {})

def testStr(self):
self.assertEquals(str(self.unit), self.unit.name)

# Test field 'part_number'
def testBlankPartNumber(self):
self.unit.part_number = ""
self.assertEquals(self.unit.validate(),
{'part_number': ['This field is required.']})

def testNonePartNumber(self):
self.unit.part_number = None
self.assertEquals(self.unit.validate(),
{'part_number': ['This field cannot be null.']})

def testUniquePartNumber(self):
new_unit = Unit.objects.create(
part_number = 'new_part_number',
name = 'new_name',
cost = 23.23)
self.unit.part_number = new_unit.part_number
# дальше ступор:(
Причина ступора метод validate() - он не выводит ошибки если
уникальность поля не соблюдена. Получается что уникальность
проверяется на момент создания объекта или его сохранения и вызывается
исключение!? Зачем?

Alexander Pugachev

unread,
May 22, 2008, 2:58:06 AM5/22/08
to django-...@googlegroups.com
unique

If True, this field must be unique throughout the table.

This is enforced at the database level and at the Django admin-form
level. If you try to add save a model with a duplicate value in a
unique field, a django.db.IntegrityError will be raised by the model's
save() method.


Так написано в доке-которую-всем-надо-читать-и-перечитывать.
А что надо делать, если бд-бэкэнд кидает исключение - отправлять e-mail?

2008/5/22 flipback <ATi...@gmail.com>:

flipback

unread,
May 22, 2008, 3:38:00 AM5/22/08
to Django russian
Я наверно не правильно выразился... то что кидается исключение это
нормально. Почему, что бы выяснить, что уникальность не соблюдена мне
надо попытаться сохранить объект? Что в свойстве unique такого
особенного, что validate() его не обрабатывает?

On 22 май, 10:58, "Alexander Pugachev" <alexander.pugac...@gmail.com>
wrote:

Alex Koshelev

unread,
May 22, 2008, 4:09:37 AM5/22/08
to Django russian
А как вы себе представляете себе эту обработку?
Да, можно сделать лишний запрос к базе и попробовать вытащить оттуда
строку с таким же значение поля. Но где гарантия, что с момента
выполнения запроса, который как бы скажет что такой строки нет, и до
момента добавления вашей, там не появится строка от другого треда/
процесса? Так что СУБД в любом случае будет делать эту проверку. Вот
поэтому лучше ловить IntegrityError и не париться.

flipback

unread,
May 22, 2008, 4:29:28 AM5/22/08
to Django russian
Спасибо, я все понял... тока если мне не изменяет память, в RoR такая
валидация работатет %)

Alex Koshelev

unread,
May 22, 2008, 5:51:54 AM5/22/08
to Django russian
Так она в и джанго бы работала в 99.9%, только полной гарантии нет.
База все равно выбросит IntegrityError, случись что.

Alexander Pugachev

unread,
May 22, 2008, 8:07:27 AM5/22/08
to django-...@googlegroups.com
А как эта валидация там работает? Они таблицу на запись блокируют?

22 мая 2008 г. 12:51 пользователь Alex Koshelev <daev...@gmail.com> написал:

Aleksey Timin

unread,
May 22, 2008, 8:16:53 AM5/22/08
to django-...@googlegroups.com
Если честно я не вникал... поэтому и удивился, что в Django этого нет.

22 мая 2008 г. 16:07 пользователь Alexander Pugachev <alexander...@gmail.com> написал:

bacccr

unread,
Jun 2, 2008, 7:27:10 PM6/2/08
to Django russian
Забавно. Нашёл косяк в движке. У меня есть дерево страниц сайта,
иерархическое, и с упорядочением по специальному полю order.
Получается, что у одного родителя не должно быть записей с одинаковым
order, для чего в модели я пишу unique_together = (('parent',
'order'),)
Отлично, при синхронизации с бд в табличке создаётся ключ типа unique
key ('parent', 'order')
Но когда я в админке пытаюсь проверить работоспособность валидатора
создав 2 записи с одинаковыми parent и order, оно валится с сообщение
про неправильные символы в юникоде... Надо будет ещё попробовать
переключить на английскую локаль, у меня русская стоит в сетингстах.
Всё равно обидно.

Dmitry Shevchenko

unread,
Jun 2, 2008, 7:28:52 PM6/2/08
to django-...@googlegroups.com
Описание полей в студию

2008/6/3 bacccr <bac...@gmail.com>:

--
Best regards, Dmitry Shevchenko.

Alexander Pugachev

unread,
Jun 3, 2008, 3:40:51 AM6/3/08
to django-...@googlegroups.com
А просто с русским текстом у вас админка работает нормально?

3 июня 2008 г. 2:28 пользователь Dmitry Shevchenko <dmi...@gmail.com> написал:

Serge Matveenko

unread,
Jun 3, 2008, 3:41:34 AM6/3/08
to django-...@googlegroups.com
2008/6/3 bacccr <bac...@gmail.com>:

замените метод __str__ в описании моделей на __unicode__


--
Serge Matveenko
+7 905 22 44 386
+7 961 268 66 99
http://serge.matveenko.ru/

bacccr

unread,
Jun 3, 2008, 6:40:11 AM6/3/08
to Django russian
Да, нормально с русским работает. Глючил MySQL, пока я в его ini не
поменял кодировку по умолчанию и не пересоздал базу. Версия джанго -
срез, закачанный на прошлой неделе. С самого начала в модели не было
метода __str__, только __unicode__. И наконец, даже если поменять
локаль на английскую, валидатор вываливается с ошибкой, локаль не
влияет.
Вот models.py:

# -*- coding: utf-8 -*-

from django.db import models
from django.core import validators

class Page(models.Model):
active = models.BooleanField(verbose_name='Вкл',db_index=True)
parent =
models.ForeignKey('self',verbose_name='Родитель',db_index=True)
order = models.IntegerField(verbose_name='Порядок',default=1)
url_name =
models.SlugField(verbose_name='Ссылка',unique=True,db_index=True)
name = models.CharField(max_length=500,verbose_name='Имя
страницы',blank=True)
content = models.TextField(verbose_name='Текст',blank=True)
creation_date = models.DateTimeField(verbose_name='Дата
создания',auto_now_add=True,db_index=True)
last_update =
models.DateTimeField(verbose_name='Изменена',auto_now=True,db_index=True)

def __unicode__(self):
return self.name + ' - ' + self.url_name + ''

class Admin:
list_display = ('name', 'active', 'url_name',
'parent','creation_date','last_update',)
list_filter = ('active', 'parent',)
search_fields = ('name', 'url_name')
pass

class Meta:
verbose_name = 'страница'
verbose_name_plural = 'страницы'
ordering = ['-last_update',]
unique_together = (("parent", "order"),)

def new_order(self):
bottom_pages = Page.objects.order_by('-order')[:1]
if len(bottom_pages) == 0:
return 1
else:
return bottom_pages[0].order

def save(self):
super(Page, self).save()

def move_down(self):
return True

И, наконец, ошибка имеет следующий вид:

UnicodeDecodeError at /admin/masterstroy/page/2/
'ascii' codec can't decode byte 0xd0 in position 0: ordinal not in
range(128)

C:\Python25\Lib\site-packages\django\db\models\manipulators.py in
manipulator_validator_unique_together
309. {'object': capfirst(opts.verbose_name), 'type':
field_list[0].verbose_name, 'field': get_text_list([f.verbose_name for
f in field_list[1:]], _('and'))} ...
▼ Local vars Variable Value
ManyToOneRel <class 'django.db.models.fields.related.ManyToOneRel'>
all_data <QueryDict: {u'url_name': [u'second'], u'name':
[u'\u0412\u0442\u043e\u0440\u0430\u044f \u0441\u0442\u0440\u0430\u043d
\u0438\u0446\u0430'], u'parent': [u'3'], u'content':
[u'\u0422\u0435\u043a\u0441\u0442 \u0432\u0442\u043e\u0440\u043e\u0439
\u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b'], u'active':
[u'on'], u'order': [u'1']}>
f <django.db.models.fields.IntegerField object at 0x01584950>
field_data u'3'
field_list [<django.db.models.fields.related.ForeignKey object at
0x015848F0>, <django.db.models.fields.IntegerField object at
0x01584950>]
field_name 'order'
field_name_list ('parent', 'order')
field_val u'1'
get_text_list <function get_text_list at 0x01308B70>
kwargs {'order__iexact': u'1', 'parent__id__iexact': u'3'}
old_obj <Page: Первая страница - first>
opts <Options for Page>
self <django.db.models.manipulators.ChangeManipulator object at
0x0168CD90>

Alexander Pugachev

unread,
Jun 3, 2008, 7:34:15 AM6/3/08
to django-...@googlegroups.com
Вот дока: http://www.djangoproject.com/documentation/unicode/
Я вижу, чтоу вас строковые литералы в моделях не юникодные.

2008/6/3 bacccr <bac...@gmail.com>:

bacccr

unread,
Jun 3, 2008, 7:52:10 AM6/3/08
to Django russian
И правда помогло, спасибо. Я думал будет достаточно кодировку в начале
указать, а сейчас перед каждой русской строкой добавил u и всё
работает. Но вот что интересно - всё кроме этого валидатора до сих пор
работало отлично...

Dmitry Shevchenko

unread,
Jun 3, 2008, 9:09:32 AM6/3/08
to django-...@googlegroups.com
Просто валидатор хочет сказать что-то вроде "Поле "Порядок" уже
занято" и спотыкается на том, что verbose_name там не юникодный.

2008/6/3 bacccr <bac...@gmail.com>:

--
Best regards, Dmitry Shevchenko.

Reply all
Reply to author
Forward
0 new messages