Skip to content

Instantly share code, notes, and snippets.

@protasovse
Last active April 5, 2020 06:38
Show Gist options
  • Save protasovse/45b2c6baff89f3fa65f209dd69a3e506 to your computer and use it in GitHub Desktop.
Save protasovse/45b2c6baff89f3fa65f209dd69a3e506 to your computer and use it in GitHub Desktop.
#python, #django, test model example
"""
Модели
"""
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', 'Удалить только свои сообщения'),
)
[
{
"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
}
}
]
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