feature/fix_generate_pass
Andrey 8 years ago
parent e97c343995
commit f41af94e52
  1. 6
      access/migrations/0001_initial.py
  2. 76
      access/migrations/0002_auto_20171212_2307.py
  3. 14
      access/models/other.py
  4. 2
      achievements/migrations/0001_initial.py
  5. 51
      achievements/migrations/0002_auto_20171212_2307.py
  6. 4
      courses/admin.py
  7. 38
      courses/migrations/0001_initial.py
  8. 31
      courses/migrations/0002_auto_20171212_2307.py
  9. 105
      courses/models.py
  10. 30
      courses/serializers.py
  11. 4
      csv/load_courses.py
  12. 4
      csv/load_student_teachers_threads.py
  13. 6
      finance/migrations/0001_initial.py
  14. 2
      library/migrations/0001_initial.py
  15. 4
      maps/migrations/0001_initial.py
  16. 5
      storage/admin.py
  17. 14
      storage/migrations/0001_initial.py
  18. 15
      storage/models.py
  19. 4
      storage/serializers.py
  20. 28
      storage/tests.py
  21. 47
      storage/views.py

@ -1,8 +1,9 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-12-12 16:07 # Generated by Django 1.11.6 on 2017-12-12 23:07
from __future__ import unicode_literals from __future__ import unicode_literals
import access.models.user import access.models.user
import django.contrib.postgres.fields
from django.db import migrations, models from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion
@ -69,7 +70,8 @@ class Migration(migrations.Migration):
name='PivotProgressVertex', name='PivotProgressVertex',
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('status', models.SmallIntegerField(choices=[(0, 'Выполненно'), (1, 'Ожидание'), (2, 'Не выполненно')], default=0)), ('status', models.SmallIntegerField(choices=[(2, 'Выполненно'), (1, 'Ожидание'), (0, 'Не выполненно')], default=0)),
('comment', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(blank=True, max_length=15, verbose_name='Ссылки на комменты'), size=None)),
], ],
), ),
migrations.CreateModel( migrations.CreateModel(

@ -0,0 +1,76 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-12-12 23:07
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('courses', '0002_auto_20171212_2307'),
('auth', '0008_alter_user_username_max_length'),
('maps', '0001_initial'),
('access', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='progress',
name='course',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='courses.Course', verbose_name='Курс'),
),
migrations.AddField(
model_name='progress',
name='teacher',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='teacher_progress', to=settings.AUTH_USER_MODEL, verbose_name='Преподователь по умолчанию'),
),
migrations.AddField(
model_name='progress',
name='template',
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='maps.CourseRoute', verbose_name='Шаблон для прохождения если не указан явно смотри функцию get_template()'),
),
migrations.AddField(
model_name='progress',
name='user',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Студент'),
),
migrations.AddField(
model_name='pivotprogressvertex',
name='progress',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='access.Progress'),
),
migrations.AddField(
model_name='pivotprogressvertex',
name='vertex',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Vertex'),
),
migrations.AddField(
model_name='invite',
name='owner',
field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Кому приглошение'),
),
migrations.AddField(
model_name='account',
name='owner',
field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='user',
name='groups',
field=models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups'),
),
migrations.AddField(
model_name='user',
name='user_permissions',
field=models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions'),
),
migrations.AlterUniqueTogether(
name='progress',
unique_together=set([('user', 'course')]),
),
]

@ -1,4 +1,5 @@
from django.conf import settings from django.conf import settings
from django.contrib.postgres.fields import ArrayField
from django.db import models from django.db import models
from courses.models import Course, Vertex from courses.models import Course, Vertex
@ -65,6 +66,11 @@ class Progress(models.Model):
@transaction_decorator @transaction_decorator
def add_vertex(self, vertex): def add_vertex(self, vertex):
PivotProgressVertex.objects.create(
progress=self,
vertex=vertex,
)
self.progress_list.add(vertex) self.progress_list.add(vertex)
parent = vertex.vertex_set.first() if vertex.vertex_set.all().exists() else None parent = vertex.vertex_set.first() if vertex.vertex_set.all().exists() else None
if parent: if parent:
@ -93,11 +99,13 @@ class Progress(models.Model):
class PivotProgressVertex(models.Model): class PivotProgressVertex(models.Model):
VERTEX_STATUS = ( VERTEX_STATUS = (
(0, 'Выполненно'), (2, 'Выполненно'),
(1, 'Ожидание'), (1, 'Ожидание'),
(2, 'Не выполненно'), (0, 'Не выполненно'),
) )
progress = models.ForeignKey(to=Progress) progress = models.ForeignKey(to=Progress)
vertex = models.ForeignKey(to=Vertex) vertex = models.ForeignKey(to=Vertex)
status = models.SmallIntegerField(choices=VERTEX_STATUS, default=0) status = models.SmallIntegerField(choices=VERTEX_STATUS, default=0)
comment = models.ManyToManyField(to=Comment) comment = ArrayField(
models.CharField(max_length=15, blank=True, verbose_name='Ссылки на комменты'),
)

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-12-12 16:07 # Generated by Django 1.11.6 on 2017-12-12 23:07
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import migrations, models from django.db import migrations, models

@ -0,0 +1,51 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-12-12 23:07
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('courses', '0001_initial'),
('achievements', '0001_initial'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.AddField(
model_name='skillj',
name='lesson',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Vertex', verbose_name='Урок'),
),
migrations.AddField(
model_name='skillj',
name='skill',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='achievements.Skills', verbose_name='Навык'),
),
migrations.AddField(
model_name='diplomagen',
name='course',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Course'),
),
migrations.AddField(
model_name='diploma',
name='template',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='achievements.DiplomaGen', verbose_name='Использовать шаблон'),
),
migrations.AddField(
model_name='diploma',
name='user',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='achievements',
name='users',
field=models.ManyToManyField(to=settings.AUTH_USER_MODEL),
),
]

@ -1,9 +1,7 @@
from django.contrib import admin from django.contrib import admin
from courses.models import Course, Tutorial, Topic, Task, Vertex from courses.models import Course, Topic, Vertex
admin.site.register(Topic) admin.site.register(Topic)
admin.site.register(Task)
admin.site.register(Vertex) admin.site.register(Vertex)
admin.site.register(Tutorial)
admin.site.register(Course) admin.site.register(Course)

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-12-12 16:07 # Generated by Django 1.11.6 on 2017-12-12 23:07
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import migrations, models from django.db import migrations, models
@ -11,7 +11,6 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
('contenttypes', '0002_remove_content_type_name'),
('storage', '0001_initial'), ('storage', '0001_initial'),
] ]
@ -37,29 +36,18 @@ class Migration(migrations.Migration):
'verbose_name_plural': 'Курсы', 'verbose_name_plural': 'Курсы',
}, },
), ),
migrations.CreateModel(
name='Task',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('is_exam', models.BooleanField(default=False, verbose_name='Экзамен или домашка')),
('materials', models.ManyToManyField(blank=True, to='storage.Storage', verbose_name='Материалы для домашней работы')),
],
),
migrations.CreateModel( migrations.CreateModel(
name='Topic', name='Topic',
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=255, verbose_name='Название')),
('icon', models.ImageField(blank=True, null=True, upload_to='', verbose_name='Иконка темы')), ('icon', models.ImageField(blank=True, null=True, upload_to='', verbose_name='Иконка темы')),
('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Course')),
], ],
), options={
migrations.CreateModel( 'verbose_name': 'Тема',
name='Tutorial', 'verbose_name_plural': 'Темы',
fields=[ },
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('on_comment', models.BooleanField(default=False, verbose_name='Комментарии')),
('video', models.TextField(blank=True, default='', verbose_name='Код видео')),
('materials', models.ManyToManyField(blank=True, to='storage.Storage', verbose_name='Материалы урока')),
],
), ),
migrations.CreateModel( migrations.CreateModel(
name='Vertex', name='Vertex',
@ -68,10 +56,14 @@ class Migration(migrations.Migration):
('title', models.CharField(max_length=255, verbose_name='Название')), ('title', models.CharField(max_length=255, verbose_name='Название')),
('free', models.BooleanField(default=True, verbose_name='Привилегии для узла не будут проверяться')), ('free', models.BooleanField(default=True, verbose_name='Привилегии для узла не будут проверяться')),
('description', models.TextField(blank=True, default='', null=True, verbose_name='Описание')), ('description', models.TextField(blank=True, default='', null=True, verbose_name='Описание')),
('object_id', models.PositiveIntegerField()), ('video', models.TextField(blank=True, default='', null=True, verbose_name='Код видео')),
('children', models.ManyToManyField(blank=True, to='courses.Vertex')), ('valid_type', models.SmallIntegerField(choices=[(3, 'Автаматическая валидация'), (2, 'Полуавтаматическая валидация'), (1, 'Ручная валидация'), (0, 'Без валидации')], default=0)),
('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType')), ('materials', models.ManyToManyField(blank=True, to='storage.File', verbose_name='Материалы урока')),
('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Course')), ('topic', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Topic')),
], ],
options={
'verbose_name': 'Урок',
'verbose_name_plural': 'Уроки',
},
), ),
] ]

@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-12-12 23:07
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
('courses', '0001_initial'),
('maps', '0001_initial'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.AddField(
model_name='course',
name='route',
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='maps.CourseRoute', verbose_name='Порядок прохождения по умолчанию'),
),
migrations.AddField(
model_name='course',
name='teachers',
field=models.ManyToManyField(related_name='course_teachers', to=settings.AUTH_USER_MODEL, verbose_name='Преподаватели'),
),
]

@ -13,7 +13,7 @@ from maps.models import CourseRoute, CourseMap
from lms.tools import decode_base64, get_real_name from lms.tools import decode_base64, get_real_name
from lms.global_decorators import transaction_decorator from lms.global_decorators import transaction_decorator
from library.models import Tags from library.models import Tags
from storage.models import Storage from storage.models import File
import random import random
COURSE_LEVEL = ( COURSE_LEVEL = (
@ -163,58 +163,33 @@ class Course(models.Model):
verbose_name_plural = "Курсы" verbose_name_plural = "Курсы"
class VertexManager(models.Manager): class Topic(models.Model):
# Менеджер вершин графа. title = models.CharField(verbose_name='Название', max_length=255)
@transaction_decorator icon = models.ImageField(verbose_name='Иконка темы', null=True, blank=True)
def create_with_dependencies(self, model, course, title, description, extra_data=None, course = models.ForeignKey(to=Course)
free=True, materials=None, parents=None, children=None):
extra_data = json.loads(extra_data)
content_type = ContentType.objects.get(app_label='courses', model=model)
obj = content_type.model_class().objects.create(**extra_data)
[obj.materials.add(i) for i in materials] if materials else None
res = self.create(
content_type=content_type,
object_id=obj.id,
course=course,
title=title,
description=description,
free=free,
)
if children:
for child in children:
res.children.add(child)
if parents:
for parent in parents:
parent.children.add(res)
return res class Meta:
verbose_name = "Тема"
verbose_name_plural = "Темы"
class Vertex(models.Model): class Vertex(models.Model):
""" VALID_TYPE = (
Основная структурная единица узел графа курса. (3, 'Автаматическая валидация'),
Позволяет работать со структурой курса на более высоком уровне абстракции. (2, 'Полуавтаматическая валидация'),
""" (1, 'Ручная валидация'),
(0, 'Без валидации'),
course = models.ForeignKey(to=Course) )
topic = models.ForeignKey(to=Topic)
title = models.CharField(verbose_name='Название', max_length=255) title = models.CharField(verbose_name='Название', max_length=255)
free = models.BooleanField(default=True, verbose_name='Привилегии для узла не будут проверяться') free = models.BooleanField(default=True, verbose_name='Привилегии для узла не будут проверяться')
description = models.TextField(verbose_name='Описание', default='', blank=True, null=True) description = models.TextField(verbose_name='Описание', default='', blank=True, null=True)
children = models.ManyToManyField(to='Vertex', blank=True) video = models.TextField(verbose_name='Код видео', default='', blank=True, null=True)
content_type = models.ForeignKey(to=ContentType) materials = models.ManyToManyField(File, verbose_name='Материалы урока', blank=True)
object_id = models.PositiveIntegerField() valid_type = models.SmallIntegerField(choices=VALID_TYPE, default=0)
content_object = GenericForeignKey('content_type', 'object_id')
objects = VertexManager()
def __str__(self): def __str__(self):
return self.title + ': ' + str(self.content_type.model) return self.title
def get_next(self, route): def get_next(self, route):
return route.get_first().get_next(self) return route.get_first().get_next(self)
@ -271,42 +246,6 @@ class Vertex(models.Model):
res = None res = None
return res return res
class Meta:
# Модели нового API со временем всё, что выше будет выпилено verbose_name = "Урок"
class Tutorial(models.Model): verbose_name_plural = "Уроки"
"""
Модель урока.
Урок может быть открыт для комментирования и закрыт, по дефолту открыт,
вероятно закрывать нужно будет крайне редко.
Видео к уроку фрейм который лежит прямо в базе, конечно же костыль и со временем
мы уйдём от этого, все видео хостятся на двух онлайн сервисах на клиент нужно передовать
id и сервис на котором, это дело хостится, а правило отображения оставить клиенту.
Материалы для урока по сути FileField, нужна только для создания лишней связи в таблице
и дублирования метазаголовков файла
"""
on_comment = models.BooleanField(verbose_name=u'Комментарии', default=False)
video = models.TextField(verbose_name=u'Код видео', default='', blank=True)
materials = models.ManyToManyField(Storage, verbose_name=u'Материалы урока', blank=True)
class Task(models.Model):
"""
Модель таска.
Исторически сложилось, что на сервере хостятся два типа тасков отличающихся лишь наименованием
домашние работы и экзамены, не нужно быть гением, чтобы понять для чего нужно булево значение
is_exam
Материалы для урока по сути FileField, нужна только для создания лишней связи в таблице
и дублирования метазаголовков файла
"""
materials = models.ManyToManyField(Storage, verbose_name='Материалы для домашней работы', blank=True)
is_exam = models.BooleanField(default=False, verbose_name='Экзамен или домашка')
class Topic(models.Model):
"""
Модель темы, нужно просто для объединения тасков и уроков.
У некоторых тем есть иконка.
Возможно поле icon перекачует в Vertex, а данная модель отвалится за ненадобностью
"""
icon = models.ImageField(verbose_name='Иконка темы', null=True, blank=True)

@ -1,24 +1,6 @@
from rest_framework import serializers from rest_framework import serializers
from courses.models import Course, Vertex, Tutorial, Topic, Task from courses.models import Course, Vertex, Topic
class TutorialSerializer(serializers.ModelSerializer):
materials = serializers.SerializerMethodField()
class Meta:
model = Tutorial
exclude = ['id']
@staticmethod
def get_materials(self):
return [i.original.url for i in self.materials.all()]
class TaskSerializer(serializers.ModelSerializer):
class Meta:
model = Task
exclude = ['id']
class TopicSerializer(serializers.ModelSerializer): class TopicSerializer(serializers.ModelSerializer):
@ -49,15 +31,7 @@ class MiniVertexSerializer(serializers.ModelSerializer):
class VertexSerializer(MiniVertexSerializer): class VertexSerializer(MiniVertexSerializer):
class Meta: class Meta:
model = Vertex model = Vertex
fields = ('id', 'title', 'type', 'object', "description") fields = '__all__'
@staticmethod
def get_object(self):
if self.content_type.model == 'tutorial':
return TutorialSerializer(self.content_object).data
if self.content_type.model == 'task':
return TaskSerializer(self.content_object).data
return False
class CourseInitSerializer(serializers.ModelSerializer): class CourseInitSerializer(serializers.ModelSerializer):

@ -8,7 +8,7 @@ django.setup()
from courses.models import Course, Vertex from courses.models import Course, Vertex
from maps.models import CourseRoute, CourseMap, PivotVertex, PivotCourseMap from maps.models import CourseRoute, CourseMap, PivotVertex, PivotCourseMap
from storage.models import Storage from storage.models import File
if __name__ == '__main__': if __name__ == '__main__':
CourseMap.objects.all().delete() CourseMap.objects.all().delete()
@ -37,7 +37,7 @@ if __name__ == '__main__':
storage_reader = csv.DictReader(storage_csv) storage_reader = csv.DictReader(storage_csv)
for row in storage_reader: for row in storage_reader:
if row['original']: if row['original']:
Storage.objects.get_or_create(**row) File.objects.get_or_create(**row)
with open('./course/vertex.csv') as vertex_csv: with open('./course/vertex.csv') as vertex_csv:
vertex_reader = csv.DictReader(vertex_csv) vertex_reader = csv.DictReader(vertex_csv)

@ -9,7 +9,7 @@ django.setup()
from courses.models import Vertex from courses.models import Vertex
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from journals.models import Thread, Journal from journals.models import Thread, Journal
from storage.models import Storage from storage.models import File
if __name__ == '__main__': if __name__ == '__main__':
csv.field_size_limit(500 * 1024 * 1024) csv.field_size_limit(500 * 1024 * 1024)
@ -53,5 +53,5 @@ if __name__ == '__main__':
for file_id in row['files'].split("[")[1].split("]")[0].split(", "): for file_id in row['files'].split("[")[1].split("]")[0].split(", "):
if file_id: if file_id:
journal.files.add(Storage.objects.get(id=file_id)) journal.files.add(File.objects.get(id=file_id))

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-12-12 16:07 # Generated by Django 1.11.6 on 2017-12-12 23:07
from __future__ import unicode_literals from __future__ import unicode_literals
from django.conf import settings from django.conf import settings
@ -12,9 +12,9 @@ class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
('yandex_money', '0002_auto_20171128_1150'), ('courses', '0002_auto_20171212_2307'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL), migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('courses', '0002_auto_20171212_1607'), ('yandex_money', '0002_auto_20171128_1150'),
] ]
operations = [ operations = [

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-12-12 16:07 # Generated by Django 1.11.6 on 2017-12-12 23:07
from __future__ import unicode_literals from __future__ import unicode_literals
import datetime import datetime

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-12-12 16:07 # Generated by Django 1.11.6 on 2017-12-12 23:07
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import migrations, models from django.db import migrations, models
@ -73,6 +73,6 @@ class Migration(migrations.Migration):
), ),
migrations.AlterUniqueTogether( migrations.AlterUniqueTogether(
name='pivotcoursemap', name='pivotcoursemap',
unique_together=set([('sort', 'route'), ('map_course', 'route')]), unique_together=set([('map_course', 'route'), ('sort', 'route')]),
), ),
] ]

@ -1,4 +1,5 @@
from django.contrib import admin from django.contrib import admin
from storage.models import Storage from storage.models import File, Comment
admin.site.register(Storage) admin.site.register(File)
admin.site.register(Comment)

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-12-12 16:07 # Generated by Django 1.11.6 on 2017-12-12 23:07
from __future__ import unicode_literals from __future__ import unicode_literals
from django.db import migrations, models from django.db import migrations, models
@ -17,11 +17,17 @@ class Migration(migrations.Migration):
name='Comment', name='Comment',
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('text', models.TextField(default='')), ('email', models.CharField(max_length=63, verbose_name='email автора')),
('text', models.TextField(default='', verbose_name='Текст комментария')),
('key', models.SlugField(unique=True, verbose_name='Получения комментария по ключу')),
], ],
options={
'verbose_name': 'Коммент',
'verbose_name_plural': 'Комменты',
},
), ),
migrations.CreateModel( migrations.CreateModel(
name='Storage', name='File',
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('original', models.FileField(max_length=255, upload_to='files', verbose_name='Файл')), ('original', models.FileField(max_length=255, upload_to='files', verbose_name='Файл')),
@ -35,6 +41,6 @@ class Migration(migrations.Migration):
migrations.AddField( migrations.AddField(
model_name='comment', model_name='comment',
name='files', name='files',
field=models.ManyToManyField(blank=True, to='storage.Storage'), field=models.ManyToManyField(blank=True, to='storage.File', verbose_name='Файлы'),
), ),
] ]

@ -2,7 +2,7 @@
from django.db import models from django.db import models
class Storage(models.Model): class File(models.Model):
original = models.FileField(max_length=255, verbose_name='Файл', upload_to="files") original = models.FileField(max_length=255, verbose_name='Файл', upload_to="files")
name = models.CharField(max_length=255, null=True, blank=True, verbose_name='Видимое имя файла') name = models.CharField(max_length=255, null=True, blank=True, verbose_name='Видимое имя файла')
@ -15,5 +15,14 @@ class Storage(models.Model):
class Comment(models.Model): class Comment(models.Model):
text = models.TextField(default="") email = models.CharField(verbose_name="email автора", max_length=63)
files = models.ManyToManyField(to=Storage, blank=True) text = models.TextField(default="", verbose_name="Текст комментария")
files = models.ManyToManyField(to=File, blank=True, verbose_name='Файлы')
key = models.SlugField(unique=True, verbose_name="Получения комментария по ключу")
def __str__(self):
return '%s' % self.key
class Meta:
verbose_name = 'Коммент'
verbose_name_plural = 'Комменты'

@ -1,10 +1,10 @@
from rest_framework import serializers from rest_framework import serializers
from storage.models import Storage from storage.models import File
class StorageSerializer(serializers.ModelSerializer): class StorageSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Storage model = File
exclude = ('id',) exclude = ('id',)

@ -0,0 +1,28 @@
from django.test import TestCase
from storage.views import add_comment, delete_comment, update_comment, get_comment
from django.core.files.uploadedfile import SimpleUploadedFile
class CommentTestCase(TestCase):
def setUp(self):
self.first_comment = add_comment("first comment", "vasia@rambler.ru")
self.second_comment = add_comment(text="Привет, отличная работа", email="artem4000@gmail.com")
def test_comment_get(self):
self.assertEqual(self.first_comment, get_comment(self.first_comment.key))
def test_comment_update(self):
new_text = "Новый текст для коммента"
update_comment(key=self.first_comment.key, text=new_text)
self.assertEqual(get_comment(self.first_comment.key).text, new_text)
def test_comment_create(self):
token = 'fskjfskj'
comment1 = add_comment(text=token, email="artem4000@gmail.com")
self.assertEqual(comment1.text, token)
file_for_upload = SimpleUploadedFile('1.txt', 'Я файл!'.encode('utf-8'))
file_name = 'Клёвый файл'
object_for_upload = {'original': file_for_upload, 'name': file_name}
comment2 = add_comment(text=token, email="artem4000@gmail.com", files=[object_for_upload])
self.assertEqual(comment2.files.count(), 1)
self.assertEqual(comment2.files.all()[0].name, file_name)

@ -0,0 +1,47 @@
import random
import string
from storage.models import Comment, File
def add_comment(text: str, email: str, files=None) -> Comment:
"""
:param text: sting
:param email: string
:param files: {name?: string, file?: File, base64?: string}[] одно из двух последних свойств должно быть указано
:return: Comment
"""
key = ''.join(random.choice(string.ascii_letters) for _x in range(15))
comment = Comment.objects.create(
text=text,
email=email,
key=key,
)
if files:
for file in files:
new_file = File.objects.create(original=file['original'])
if 'name' in file.keys():
new_file.name = file['name']
new_file.save()
comment.files.add(new_file)
return comment
def get_comment(key):
comment = Comment.objects.get(key=key)
return comment
def update_comment(key, **kwargs):
comment = Comment.objects.get(key=key)
comment.__dict__.update(kwargs)
comment.save()
return comment
def delete_comment(key):
comment = Comment.objects.get(key=key).delete()
return comment
Loading…
Cancel
Save