Last active
April 5, 2020 06:38
-
-
Save protasovse/45b2c6baff89f3fa65f209dd69a3e506 to your computer and use it in GitHub Desktop.
#python, #django, test model example
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Модели | |
""" | |
from django.db import models | |
from django.contrib.auth import get_user_model | |
class RecordManager(models.Manager): | |
def get_queryset(self): | |
return super().get_queryset().filter(deleted=False) | |
class BaseRecord(models.Model): | |
""" Базовый класс для всех типов записей """ | |
create_at = models.DateTimeField('creation date', auto_now_add=True) | |
deleted = models.BooleanField('deleted', default=False) | |
objects = models.Manager() | |
published = RecordManager() | |
class Meta: | |
abstract = True | |
class Question(BaseRecord): | |
""" Вопрос """ | |
title = models.CharField('question', max_length=255) | |
author = models.ForeignKey( | |
get_user_model(), verbose_name='author', on_delete=models.CASCADE, | |
related_name='questions') | |
def __str__(self): | |
return self.title | |
class Meta: | |
verbose_name = 'question' | |
verbose_name_plural = 'questions' | |
permissions = ( | |
('view_own_question', 'Видеть только свои вопросы'), | |
('change_own_question', 'Редактировать только свои вопросы'), | |
('delete_own_question', 'Удалить только свои вопросы'), | |
) | |
class Answer(BaseRecord): | |
""" Ветки ответов (обсуждения), участники обсуждения """ | |
question = models.ForeignKey( | |
Question, verbose_name='question', on_delete=models.CASCADE, | |
related_name='answers') | |
author = models.ForeignKey( | |
get_user_model(), verbose_name='author', on_delete=models.CASCADE, | |
related_name='answers') | |
class Meta: | |
verbose_name = 'answer thread' | |
verbose_name_plural = 'answers threads' | |
permissions = ( | |
('view_answer_on_own_question', | |
'Видеть только ответы на свои вопросы'), | |
) | |
class Message(BaseRecord): | |
""" Сообщения обсуждения """ | |
answer = models.ForeignKey( | |
Answer, verbose_name='answer thread', on_delete=models.CASCADE, | |
related_name='messages') | |
author = models.ForeignKey( | |
get_user_model(), verbose_name='author', on_delete=models.CASCADE, | |
related_name='+') | |
text = models.TextField('message text') | |
to_message = models.ForeignKey( | |
'self', verbose_name='reply to', on_delete=models.CASCADE, | |
null=True, related_name='+') | |
def __str__(self): | |
return self.text | |
class Meta: | |
verbose_name = 'message' | |
verbose_name_plural = 'messages' | |
permissions = ( | |
('view_message_on_own_question', | |
'Видеть только сообщения на свои вопросы'), | |
('add_message_on_own_question', | |
'Добавлять только сообщения на свои вопросы'), | |
('change_own_message', 'Редактировать только свои сообщения'), | |
('delete_own_message', 'Удалить только свои сообщения'), | |
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[ | |
{ | |
"pk": 1, | |
"model": "questions.question", | |
"fields": { | |
"create_at": "2020-04-04 07:15:30+00:00", | |
"title": "Какие меры принимают ритейлеры в других странах из-за коронавируса?", | |
"author_id": 3 | |
} | |
}, | |
{ | |
"pk": 2, | |
"model": "questions.question", | |
"fields": { | |
"create_at": "2020-04-04 07:20:00+00:00", | |
"title": "Как коронавирус изменил мир к вечеру 3 апреля?", | |
"author_id": 3 | |
} | |
}, | |
{ | |
"pk": 3, | |
"model": "questions.question", | |
"fields": { | |
"create_at": "2020-04-04 07:20:00+00:00", | |
"title": "Можно ли на добровольной основе выйти на работу во время нерабочей недели?", | |
"author_id": 3, | |
"deleted": true | |
} | |
}, | |
{ | |
"pk": 1, | |
"model": "questions.answer", | |
"fields": { | |
"create_at": "2020-04-05 13:00:00+00:00", | |
"question_id": 1, | |
"author_id": 2 | |
} | |
}, | |
{ | |
"pk": 2, | |
"model": "questions.answer", | |
"fields": { | |
"create_at": "2020-04-05 13:00:00+00:00", | |
"question_id": 1, | |
"author_id": 2 | |
} | |
}, | |
{ | |
"pk": 3, | |
"model": "questions.answer", | |
"fields": { | |
"create_at": "2020-04-05 13:30:00+00:00", | |
"question_id": 1, | |
"deleted": true, | |
"author_id": 2 | |
} | |
}, | |
{ | |
"pk": 4, | |
"model": "questions.answer", | |
"fields": { | |
"create_at": "2020-04-05 13:33:00+00:00", | |
"question_id": 3, | |
"deleted": true, | |
"author_id": 2 | |
} | |
}, | |
{ | |
"pk": 1, | |
"model": "questions.message", | |
"fields": { | |
"create_at": "2020-04-05 13:00:00+00:00", | |
"text": "Эпидемия коронавируса, карантины, социальное дистанцирование и режим самоизоляции заставили остановить свою работу большинство магазинов, предприятий и мест для развлечения. Однако продовольственные магазины продолжают свою работу даже в этих условиях - и им приходится изобретать новые способы функционирования; другие переходят в онлайн, надеясь таким образом продолжить свою работу.", | |
"answer_id": 1, | |
"author_id": 2 | |
} | |
}, | |
{ | |
"pk": 2, | |
"model": "questions.message", | |
"fields": { | |
"create_at": "2020-04-05 13:01:00+00:00", | |
"text": "Прежде всего, те магазины, которые продолжают работать, ввели дополнительные меры по защите продавцов и покупателей. Большинство торговых сетей сводят к минимуму наличные платежи, расставляют товары только до или после работы магазина и просят курьеров и водителей доставлять товары лишь до порога дома, а не вручать их лично, заходя внутрь; некоторые даже дополнительно обезопасили рабочие места кассиров, окружив их пластиковыми панелями - так поступила сеть супермаркетов Carrefour.", | |
"answer_id": 1, | |
"author_id": 3 | |
} | |
}, | |
{ | |
"pk": 3, | |
"model": "questions.message", | |
"fields": { | |
"create_at": "2020-04-05 13:02:00+00:00", | |
"text": "Некоторые ритейлеры стараются смотреть дальше текущего кризиса и готовятся к тому, что будет после него. Многие изучают китайский опыт - как сегодняшний, так и прошлый, связанный с предыдущими эпидемиями. Например, во время восстановления Китая после вспышки атипичной пневмонии в 2002–2003 годах произошло резкое сокращение продаж в некоторых категориях товаров долгого хранения, например чистящих средств и средств гигиены, в то время как сильно выросли продажи одежды.", | |
"answer_id": 1, | |
"author_id": 2, | |
"to_message_id": 2 | |
} | |
}, | |
{ | |
"pk": 6, | |
"model": "questions.message", | |
"fields": { | |
"create_at": "2020-04-05 13:10:00+00:00", | |
"text": "Для исследования на коронавирус у пациента с признаками ОРЗ, контактировавшего с больными CoVid-2019 или приехавшего из эпидемиологически неблагополучных регионов, берут мазок из носа и нотоглотки.", | |
"answer_id": 1, | |
"author_id": 3, | |
"to_message_id": 2, | |
"deleted": true | |
} | |
}, | |
{ | |
"pk": 4, | |
"model": "questions.message", | |
"fields": { | |
"create_at": "2020-04-05 13:03:00+00:00", | |
"text": "Согласно статье 157 ТК РФ, время простоя по причинам, не зависящим от работодателя и работника, оплачивается в размере не менее двух третей тарифной ставки, оклада (должностного оклада), рассчитанных пропорционально времени простоя.", | |
"answer_id": 2, | |
"author_id": 2 | |
} | |
}, | |
{ | |
"pk": 5, | |
"model": "questions.message", | |
"fields": { | |
"create_at": "2020-04-05 13:04:00+00:00", | |
"text": "В минувшую пятницу объявили, что со вторника закроются все бары и кафе, а рестораны почему-то нет. Но в субботу приняли решение все ускорить, в тот же день закрыли и бары. При этом, если ты продаешь еду, то тебе разрешают работать. И только что нам рассказывал в интервью один из владельцев бара, где подают еду, что к ним приходила полиция, все проверила, выяснила, что они готовят еду, и не закрыла его на этом основании. Такой формальный принцип.", | |
"answer_id": 2, | |
"author_id": 2 | |
} | |
}, | |
{ | |
"pk": 7, | |
"model": "questions.message", | |
"fields": { | |
"create_at": "2020-04-05 13:04:00+00:00", | |
"text": "Если ваша организация работает, то вопрос вашего выхода это договоренность с работодателем. Нужно его разрешение и формление соответствующих бумаг по трудовому законодательству.", | |
"answer_id": 4, | |
"author_id": 2, | |
"deleted": true | |
} | |
} | |
] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from datetime import datetime, timezone | |
from django.contrib.auth import get_user_model | |
from django.test import TestCase | |
from lc_auth.models import Author | |
from ..models import Question, Answer, Message | |
class QuestionModelTest(TestCase): | |
fixtures = ['questions_testdata.json'] | |
question = None | |
expert = None | |
user = None | |
@classmethod | |
def setUpTestData(cls): | |
""" Set up non-modified objects used by all test methods """ | |
cls.expert = Author.objects.get(username='expert') | |
cls.user = Author.objects.get(username='user') | |
cls.question = Question.objects.get(pk=1) | |
def test_title_label(self): | |
field_label = self.question._meta.get_field('title').verbose_name | |
self.assertEquals(field_label, 'question') | |
field_label = self.question._meta.get_field('author').verbose_name | |
self.assertEquals(field_label, 'author') | |
field_label = self.question._meta.get_field('create_at').verbose_name | |
self.assertEquals(field_label, 'creation date') | |
field_label = self.question._meta.get_field('deleted').verbose_name | |
self.assertEquals(field_label, 'deleted') | |
verbose_name = self.question._meta.verbose_name | |
self.assertEquals(verbose_name, 'question') | |
verbose_name_plural = self.question._meta.verbose_name_plural | |
self.assertEquals(verbose_name_plural, 'questions') | |
def test_relations(self): | |
self.assertEqual(self.question.author, self.user) | |
def test_max_length(self): | |
max_length = self.question._meta.get_field('title').max_length | |
self.assertEquals(max_length, 255) | |
def test_str_object(self): | |
expected_object_str = self.question.title | |
self.assertEquals(expected_object_str, str(self.question)) | |
def test_permissions(self): | |
self.assertTrue( | |
hasattr(self.question._meta, 'permissions'), 'not set permissions') | |
model_permissions = dict(self.question._meta.permissions) | |
self.assertEquals(len(model_permissions), 3) | |
self.assertIn('view_own_question', model_permissions) | |
self.assertIn('change_own_question', model_permissions) | |
self.assertIn('delete_own_question', model_permissions) | |
def test_defaults(self): | |
now = datetime.now(timezone.utc) | |
question = Question.objects.create( | |
title="A test question.", | |
author=self.user | |
) | |
delta = question.create_at - now | |
self.assertEqual(delta.seconds, 0) | |
self.assertFalse(question.deleted) | |
def test_relations(self): | |
answer_field = self.question._meta.get_field('answers') | |
self.assertTrue(answer_field.one_to_many) | |
self.assertIs(answer_field.related_model, Answer) | |
author_field = self.question._meta.get_field('author') | |
self.assertTrue(author_field.many_to_one, True) | |
self.assertIs(author_field.related_model, get_user_model()) | |
class AnswerModelTest(TestCase): | |
fixtures = ['questions_testdata.json'] | |
answer = None | |
question = None | |
expert = None | |
user = None | |
@classmethod | |
def setUpTestData(cls): | |
""" Set up non-modified objects used by all test methods """ | |
cls.expert = Author.objects.get(username='expert') | |
cls.answer = Answer.objects.get(pk=1) | |
cls.question = Question.objects.get(pk=1) | |
def test_labels(self): | |
field_label = self.answer._meta.get_field('create_at').verbose_name | |
self.assertEquals(field_label, 'creation date') | |
field_label = self.answer._meta.get_field('deleted').verbose_name | |
self.assertEquals(field_label, 'deleted') | |
field_label = self.answer._meta.get_field('author').verbose_name | |
self.assertEquals(field_label, 'author') | |
verbose_name = self.answer._meta.verbose_name | |
self.assertEquals(verbose_name, 'answer thread') | |
verbose_name_plural = self.answer._meta.verbose_name_plural | |
self.assertEquals(verbose_name_plural, 'answers threads') | |
def test_permissions(self): | |
self.assertTrue( | |
hasattr(self.answer._meta, 'permissions'), 'not set permissions') | |
model_permissions = dict(self.answer._meta.permissions) | |
self.assertEquals(len(model_permissions), 1) | |
self.assertIn('view_answer_on_own_question', model_permissions) | |
def test_defaults(self): | |
now = datetime.now(timezone.utc) | |
answer = Answer.objects.create( | |
question=self.question, | |
author=self.expert | |
) | |
delta = answer.create_at - now | |
self.assertEqual(delta.seconds, 0) | |
self.assertFalse(answer.deleted) | |
def test_relations(self): | |
messages_filed = self.answer._meta.get_field('messages') | |
self.assertTrue(messages_filed.one_to_many) | |
self.assertIs(messages_filed.related_model, Message) | |
author_field = self.answer._meta.get_field('author') | |
self.assertTrue(author_field.many_to_one, True) | |
self.assertIs(author_field.related_model, get_user_model()) | |
class MessageModelTest(TestCase): | |
fixtures = ['questions_testdata.json'] | |
answer = None | |
question = None | |
expert = None | |
user = None | |
message = None | |
@classmethod | |
def setUpTestData(cls): | |
cls.expert = Author.objects.get(username='expert') | |
cls.user = Author.objects.get(username='user') | |
cls.answer = Answer.objects.get(pk=1) | |
cls.question = Question.objects.get(pk=1) | |
cls.message = Message.objects.get(pk=1) | |
def test_labels(self): | |
""" test labels """ | |
field_label = self.message._meta.get_field('create_at').verbose_name | |
self.assertEquals(field_label, 'creation date') | |
field_label = self.message._meta.get_field('deleted').verbose_name | |
self.assertEquals(field_label, 'deleted') | |
field_label = self.message._meta.get_field('answer').verbose_name | |
self.assertEquals(field_label, 'answer thread') | |
field_label = self.message._meta.get_field('author').verbose_name | |
self.assertEquals(field_label, 'author') | |
field_label = self.message._meta.get_field('text').verbose_name | |
self.assertEquals(field_label, 'message text') | |
field_label = self.message._meta.get_field('to_message').verbose_name | |
self.assertEquals(field_label, 'reply to') | |
verbose_name = self.message._meta.verbose_name | |
self.assertEquals(verbose_name, 'message') | |
verbose_name = self.message._meta.verbose_name_plural | |
self.assertEquals(verbose_name, 'messages') | |
def test_relations(self): | |
""" test relations """ | |
answer_field = self.message._meta.get_field('answer') | |
self.assertTrue(answer_field.many_to_one) | |
self.assertIs(answer_field.related_model, Answer) | |
author_field = self.message._meta.get_field('author') | |
self.assertTrue(author_field.many_to_one) | |
self.assertIs(author_field.related_model, get_user_model()) | |
to_message_field = self.message._meta.get_field('to_message') | |
self.assertTrue(to_message_field.many_to_one) | |
self.assertIs( | |
to_message_field.related_model, self.message._meta.model) | |
def test_defaults(self): | |
""" test defaults""" | |
now = datetime.now(timezone.utc) | |
message = Message.objects.create( | |
answer=self.answer, | |
author=self.expert, | |
text='Super message!', | |
) | |
delta = message.create_at - now | |
self.assertEqual(delta.seconds, 0) | |
self.assertFalse(message.deleted) | |
self.assertIsNone(message.to_message) | |
def test_permissions(self): | |
""" test permissions""" | |
self.assertTrue( | |
hasattr(self.message._meta, 'permissions'), 'not set permissions') | |
model_permissions = dict(self.message._meta.permissions) | |
self.assertEquals(len(model_permissions), 4) | |
self.assertIn('view_message_on_own_question', model_permissions) | |
self.assertIn('add_message_on_own_question', model_permissions) | |
self.assertIn('change_own_message', model_permissions) | |
self.assertIn('delete_own_message', model_permissions) | |
def test_object_to_str(self): | |
object_to_str = self.message.text | |
self.assertEquals(object_to_str, str(self.message)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment