commit
6926b4c694
38 changed files with 797 additions and 279 deletions
@ -1,27 +1,11 @@ |
||||
#**SkillBox LMS** |
||||
|
||||
Подробные шаги для проверки работоспособности CI |
||||
Нужно выполнить миграции и запустить скрипт update_db.py без параметров в модуле courses (скрипт на всякий случай пока не удалять) |
||||
|
||||
1) Проверяем доступ к репозиторию кода https://gitlab.com/skillbox/go.skillbox.ru |
||||
2) Клонируем проект |
||||
3) Вносим изменения в код |
||||
4) Комитим изменения в новый branch (ОБЯЗАТЕЛЬНО в отдельный Branch) |
||||
4.1) Пушим изменения |
||||
5) Ждем выполнения создания тестового сайта https://gitlab.com/skillbox/go.skillbox.ru/pipelines |
||||
6) Сайт будет доступен по адресу <branch_name>.lms.test.spicycms.com |
||||
Фактически в структуре данных изменилось только то, что появилась новая табличка NormalMap. Скрипт собирает все treeview курсов и кладёт в эту табличку |
||||
|
||||
**Правила для разработчика** |
||||
Появилась новая зависимость django_rest_framework. |
||||
|
||||
* Разрабока ведется в отдельном брэнче |
||||
* После комита изменений можно проверить свою работу по следующему адресу: .lms.test.spicycms.com |
||||
* После проверки тестового сайта по имени брэнча, брэнч помечается к мерж реквесту |
||||
* Ответсвенный инженер производит код ревью и запускает/отклоняет мерж |
||||
* Если сайт запустился на демо сайте, код в ручом режиме можно обновить на продакшен сервере |
||||
Изменения никак не трогают старый функционал. |
||||
|
||||
**Замечания** |
||||
|
||||
* Мерж реквест лучше производить в ветку develop(чтобы исключить случайного обновления кода на демо сайте) |
||||
* Внимание! Разработчик обязан проверить работоспособность тестового сайта по имени созданного брэнча .lms.test.spicycms.com |
||||
* Если необходимы тестовые данные разработчик их подготавливает дополнительно |
||||
* Если нет возможности добавить тестовые данные в авто режиме, разработчик добавляет инструкцию в README файл по запуску необходимых команд |
||||
(Под тестовыми данными подразумеваются фикстуры) |
||||
Имеет смысл пробежаться по middl |
||||
|
||||
@ -0,0 +1,21 @@ |
||||
# -*- coding: utf-8 -*- |
||||
# Generated by Django 1.9.3 on 2017-09-18 08:11 |
||||
from __future__ import unicode_literals |
||||
|
||||
from django.db import migrations, models |
||||
import django.utils.timezone |
||||
|
||||
|
||||
class Migration(migrations.Migration): |
||||
|
||||
dependencies = [ |
||||
('access', '0089_auto_20170810_0904'), |
||||
] |
||||
|
||||
operations = [ |
||||
migrations.AlterField( |
||||
model_name='user', |
||||
name='delay_date', |
||||
field=models.DateTimeField(blank=True, default=django.utils.timezone.now, null=True, verbose_name='Задержка до. Не включая этот день.'), |
||||
), |
||||
] |
||||
@ -0,0 +1,12 @@ |
||||
from django.conf.urls import url |
||||
from access import new_view as views |
||||
|
||||
urlpatterns = [ |
||||
url(r'teachers/$', views.TeacherListView.as_view()), |
||||
url(r'info/$', views.InfoUserView.as_view()), |
||||
url(r'check/$', views.CheckUserView.as_view()), |
||||
url(r'registration/$', views.RegistrationView.as_view()), |
||||
url(r'change_password/$', views.ChangePasswordView.as_view()), |
||||
url(r'login/$', views.LoginView.as_view()), |
||||
url(r'logout/$', views.LogoutView.as_view()), |
||||
] |
||||
@ -0,0 +1,100 @@ |
||||
from django.contrib.auth import get_user_model |
||||
from django.contrib import auth |
||||
from rest_framework.views import APIView |
||||
from rest_framework.renderers import JSONRenderer |
||||
from rest_framework.response import Response |
||||
|
||||
from access.serializers import UserInitSerializer |
||||
from courses.models import Course |
||||
|
||||
|
||||
class TeacherListView(APIView): |
||||
renderer_classes = (JSONRenderer,) |
||||
status_code = 200 |
||||
|
||||
def get(self, request): |
||||
kwargs = dict( |
||||
in_role='T', |
||||
is_active=True, |
||||
reg_status=4, |
||||
) |
||||
res = [] |
||||
course_id = request.GET.get('course_id', 0) |
||||
if course_id: |
||||
kwargs['course_teachers'] = Course.objects.get(id=course_id) |
||||
for teacher in get_user_model().objects.filter(**kwargs): |
||||
res.append(teacher.full_name()) |
||||
return Response(res, self.status_code) |
||||
|
||||
|
||||
class CheckUserView(APIView): |
||||
renderer_classes = (JSONRenderer,) |
||||
status_code = 200 |
||||
|
||||
def get(self, request): |
||||
if request.user.is_authenticated() and (request.user.in_role in ['M', 'S', 'S2', 'A'] or request.user.is_admin): |
||||
return Response(True, status=self.status_code) |
||||
return Response(False, status=self.status_code) |
||||
|
||||
|
||||
class InfoUserView(APIView): |
||||
renderer_classes = (JSONRenderer,) |
||||
status_code = 200 |
||||
|
||||
def get(self, request): |
||||
if request.user.is_authenticated(): |
||||
return Response(UserInitSerializer(request.user).data, status=self.status_code) |
||||
return Response('anonymous', status=self.status_code) |
||||
|
||||
|
||||
class RegistrationView(APIView): |
||||
renderer_classes = (JSONRenderer,) |
||||
|
||||
@staticmethod |
||||
def post(request): |
||||
try: |
||||
user = get_user_model().objects.get(email=request.JSON['email'].lower()) |
||||
except get_user_model().DoesNotExist: |
||||
user = get_user_model().objects.create_user( |
||||
email=request.JSON['email'].lower(), |
||||
) |
||||
user.set_password(request.JSON['password']) |
||||
user.reg_status = '2' |
||||
user.save() |
||||
return Response(UserInitSerializer(user).data, status=200) |
||||
|
||||
|
||||
class ChangePasswordView(APIView): |
||||
renderer_classes = (JSONRenderer,) |
||||
|
||||
@staticmethod |
||||
def post(request): |
||||
if request.user.is_authenticated and not request.user.check_password(request.JSON['old_password']): |
||||
return Response("Неверный пароль", status=404) |
||||
request.user.set_password(request.JSON['new_password']) |
||||
request.user.save() |
||||
return Response("Пароль был изменён", status=200) |
||||
|
||||
|
||||
class LoginView(APIView): |
||||
renderer_classes = (JSONRenderer,) |
||||
|
||||
@staticmethod |
||||
def post(request): |
||||
if not request.user.is_authenticated(): |
||||
user = auth.authenticate(email=request.JSON.get('email'), password=request.JSON.get('password')) |
||||
try: |
||||
auth.login(request, user) |
||||
except AttributeError: |
||||
return Response("Неверный пароль", status=404) |
||||
return Response(UserInitSerializer(request.user).data, status=200) |
||||
|
||||
|
||||
class LogoutView(APIView): |
||||
renderer_classes = (JSONRenderer,) |
||||
|
||||
@staticmethod |
||||
def post(request): |
||||
if request.user.is_authenticated(): |
||||
auth.logout(request) |
||||
return Response(status=204) |
||||
@ -0,0 +1,10 @@ |
||||
from django.contrib.auth import get_user_model |
||||
from rest_framework import serializers |
||||
|
||||
|
||||
class UserInitSerializer(serializers.ModelSerializer): |
||||
|
||||
class Meta: |
||||
model = get_user_model() |
||||
fields = ['id', 'email', 'phone', 'name', |
||||
'fname', 'oname', 'city', 'b_day'] |
||||
@ -0,0 +1,6 @@ |
||||
from django.conf.urls import url, include |
||||
|
||||
urlpatterns = [ |
||||
url(r'courses/', include('courses.new_urls')), |
||||
url(r'users/', include('access.new_urls')), |
||||
] |
||||
@ -1,22 +0,0 @@ |
||||
# -*- coding: utf-8 -*- |
||||
# Generated by Django 1.9.3 on 2017-08-10 09:04 |
||||
from __future__ import unicode_literals |
||||
|
||||
import datetime |
||||
from django.db import migrations, models |
||||
import django.db.models.deletion |
||||
|
||||
|
||||
class Migration(migrations.Migration): |
||||
|
||||
dependencies = [ |
||||
('courses', '0044_auto_20170621_1548'), |
||||
] |
||||
|
||||
operations = [ |
||||
migrations.AlterField( |
||||
model_name='lesson', |
||||
name='on_comment', |
||||
field=models.CharField(choices=[('N', 'Включены'), ('F', 'Отключены'), ('T', 'Подчиняется теме')], default='T', help_text='https://go.skillbox.ru/management/faq/37', max_length=1, verbose_name='Блок комментариев'), |
||||
), |
||||
] |
||||
@ -0,0 +1,53 @@ |
||||
# -*- coding: utf-8 -*- |
||||
# Generated by Django 1.9.3 on 2017-09-18 08:11 |
||||
from __future__ import unicode_literals |
||||
|
||||
import datetime |
||||
from django.conf import settings |
||||
from django.db import migrations, models |
||||
import django.db.models.deletion |
||||
|
||||
|
||||
class Migration(migrations.Migration): |
||||
|
||||
dependencies = [ |
||||
('courses', '0044_auto_20170621_1548'), |
||||
] |
||||
|
||||
operations = [ |
||||
migrations.AlterField( |
||||
model_name='course', |
||||
name='mentors', |
||||
field=models.ManyToManyField(blank=True, related_name='course_mentors', to=settings.AUTH_USER_MODEL, verbose_name='Кураторы'), |
||||
), |
||||
migrations.AlterField( |
||||
model_name='diploma', |
||||
name='date_size', |
||||
field=models.IntegerField(null=True, verbose_name='Размер даты'), |
||||
), |
||||
migrations.AlterField( |
||||
model_name='diploma', |
||||
name='key', |
||||
field=models.IntegerField(verbose_name='Последний ключ'), |
||||
), |
||||
migrations.AlterField( |
||||
model_name='diploma', |
||||
name='key_size', |
||||
field=models.IntegerField(null=True, verbose_name='Размер ключа'), |
||||
), |
||||
migrations.AlterField( |
||||
model_name='diploma', |
||||
name='name_size', |
||||
field=models.IntegerField(null=True, verbose_name='Размер имени'), |
||||
), |
||||
migrations.AlterField( |
||||
model_name='lesson', |
||||
name='on_comment', |
||||
field=models.CharField(choices=[('N', 'Включены'), ('F', 'Отключены'), ('T', 'Подчиняется теме')], default='T', help_text='https://go.skillbox.ru/management/faq/37', max_length=1, verbose_name='Блок комментариев'), |
||||
), |
||||
migrations.AlterField( |
||||
model_name='materialdirection', |
||||
name='mentors', |
||||
field=models.ManyToManyField(to=settings.AUTH_USER_MODEL, verbose_name='Кураторы'), |
||||
), |
||||
] |
||||
@ -0,0 +1,11 @@ |
||||
from django.conf.urls import url |
||||
from courses import new_view as views |
||||
|
||||
urlpatterns = [ |
||||
url(r'theme/detail/([0-9]{1,99})/$', views.ThemeDetailView.as_view()), |
||||
url(r'lesson/detail/([0-9]{1,99})/$', views.LessonDetailView.as_view()), |
||||
url(r'detail/([0-9]{1,99})/$', views.CourseDetailView.as_view()), |
||||
url(r'tree/([0-9]{1,99})/$', views.TreeView.as_view()), |
||||
url(r'directions/$', views.DirectionListView.as_view()), |
||||
url(r'^$', views.CourseListView.as_view()), |
||||
] |
||||
@ -0,0 +1,159 @@ |
||||
from rest_framework import serializers |
||||
import json |
||||
# from django.contrib.auth import get_user_model |
||||
# from django.core.exceptions import ObjectDoesNotExist |
||||
|
||||
from courses.models import Course, CourseTheme, Lesson, Homework, Exam |
||||
|
||||
|
||||
class LessonSerializer(serializers.ModelSerializer): |
||||
on_comment = serializers.SerializerMethodField() |
||||
|
||||
class Meta: |
||||
model = Lesson |
||||
fields = ( |
||||
'id', 'title', 'on_comment', 'materials', |
||||
'free', 'video', 'video_id', |
||||
) |
||||
|
||||
@staticmethod |
||||
def get_on_comment(self): |
||||
return self.on_comment == 'N' or self.on_comment == 'T' and self.theme.on_comment |
||||
|
||||
|
||||
class ThemeSerializer(serializers.ModelSerializer): |
||||
|
||||
class Meta: |
||||
model = CourseTheme |
||||
exclude = ('price_type', '_type', 'sort', 'on_comment') |
||||
|
||||
|
||||
class CourseListSerializer(serializers.ModelSerializer): |
||||
length = serializers.SerializerMethodField() |
||||
level = serializers.SerializerMethodField() |
||||
direction = serializers.SerializerMethodField() |
||||
|
||||
class Meta: |
||||
model = Course |
||||
fields = ['id', 'title', 'length', |
||||
'level', 'direction', 'image',] |
||||
|
||||
@staticmethod |
||||
def get_length(self): |
||||
summary = 0 |
||||
for theme_slim in json.loads(self.normalmap.json_tree): |
||||
for simple_object in theme_slim['body']: |
||||
if simple_object.split('_')[1] == 'L': |
||||
summary += 1 |
||||
return summary |
||||
|
||||
@staticmethod |
||||
def get_level(self): |
||||
return self.get_level_display() |
||||
|
||||
@staticmethod |
||||
def get_direction(self): |
||||
return self.direction.title |
||||
|
||||
|
||||
class CourseTreeSerializer(serializers.ModelSerializer): |
||||
children = serializers.SerializerMethodField() |
||||
|
||||
class Meta: |
||||
model = Course |
||||
fields = ['id', 'title', 'children'] |
||||
|
||||
@staticmethod |
||||
def get_children(self): |
||||
theme_list = json.loads(self.normalmap.json_tree) |
||||
map = [] |
||||
for theme_slim in theme_list: |
||||
theme = CourseTheme.objects.get(id=theme_slim['id']) |
||||
theme_obj = { |
||||
'id': theme.id, |
||||
'title': theme.title, |
||||
'lessons': [], |
||||
'tasks': [], |
||||
} |
||||
for simple_object in theme_slim['body']: |
||||
val = simple_object.split('_')[0] |
||||
if simple_object.split('_')[1] == 'L': |
||||
lesson = Lesson.objects.get(id=val) |
||||
lesson_obj = {'id': lesson.id, 'title': lesson.title} |
||||
theme_obj['lessons'].append(lesson_obj) |
||||
|
||||
if simple_object.split('_')[1] == 'H': |
||||
task = Homework.objects.get(id=val) |
||||
task_obj = { |
||||
'id': task.id, |
||||
'is_exam': False, |
||||
} |
||||
theme_obj['tasks'].append(task_obj) |
||||
|
||||
if simple_object.split('_')[1] == 'E': |
||||
task = Exam.objects.get(id=val) |
||||
task_obj = { |
||||
'id': task.id, |
||||
'is_exam': True, |
||||
} |
||||
theme_obj['tasks'].append(task_obj) |
||||
|
||||
map.append(theme_obj) |
||||
|
||||
return map |
||||
|
||||
|
||||
class CourseDetailSerializer(serializers.ModelSerializer): |
||||
level = serializers.SerializerMethodField() |
||||
direction = serializers.SerializerMethodField() |
||||
teachers = serializers.SerializerMethodField() |
||||
|
||||
class Meta: |
||||
model = Course |
||||
exclude = ( |
||||
'slug', 'mentors', 'page', 'sort', |
||||
'preview', 'use_fail', 'basic_len', |
||||
'addition_len', 'min_price', 'buy_icon', |
||||
'must_build', 'keywords', 'recommend', |
||||
) |
||||
|
||||
@staticmethod |
||||
def get_level(self): |
||||
return self.get_level_display() |
||||
|
||||
@staticmethod |
||||
def get_direction(self): |
||||
return self.direction.title |
||||
|
||||
@staticmethod |
||||
def get_teachers(self): |
||||
return [teacher.full_name() for teacher in self.teachers.all()] |
||||
|
||||
|
||||
# class UserSerializer(serializers.ModelSerializer): |
||||
# statistics = serializers.SerializerMethodField('get_statistic') |
||||
# games = serializers.SerializerMethodField('get_my_games') |
||||
# is_anonymous = serializers.BooleanField() |
||||
# |
||||
# @staticmethod |
||||
# def get_my_games(self): |
||||
# res = {} |
||||
# try: |
||||
# res['active'] = GameSerializer(self.game_set.get(state__lte=1)).data |
||||
# except ObjectDoesNotExist: |
||||
# res['active'] = {} |
||||
# |
||||
# res['archive'] = [GameSerializer(i).data for i in self.game_set.all().filter(state=2)] |
||||
# return res |
||||
# |
||||
# @staticmethod |
||||
# def get_statistic(self): |
||||
# try: |
||||
# statistics = StatisticSerializer(Statistic.objects.get(user=self)).data |
||||
# except ObjectDoesNotExist: |
||||
# statistics = {} |
||||
# return statistics |
||||
# |
||||
# class Meta: |
||||
# model = get_user_model() |
||||
# fields = ['id', 'username', 'email', 'is_active', 'statistics', 'games', 'is_anonymous'] |
||||
@ -0,0 +1,22 @@ |
||||
import os, sys |
||||
import django, json |
||||
|
||||
sys.path.append("../") |
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "lms.settings") |
||||
django.setup() |
||||
|
||||
from courses.models import Course, NormalMap, CourseTheme, Lesson, Homework, Exam |
||||
|
||||
if __name__ == '__main__': |
||||
for course in Course.objects.all(): |
||||
tree = [] |
||||
for theme in CourseTheme.objects.filter(course=course).order_by('sort'): |
||||
tree.append({'id': theme.id, 'body': |
||||
[str(i.id) + "_L" for i in Lesson.objects.filter(theme=theme).order_by('sort')] + |
||||
[str(i.id) + "_H" for i in Homework.objects.filter(theme=theme).order_by('sort')] + |
||||
[str(i.id) + "_E" for i in Exam.objects.filter(theme=theme).order_by('sort')] |
||||
}) |
||||
|
||||
obj, _is_create = NormalMap.objects.get_or_create(course=course) |
||||
obj.json_tree = json.dumps(tree) |
||||
obj.save() |
||||
@ -0,0 +1,42 @@ |
||||
# -*- coding: utf-8 -*- |
||||
# Generated by Django 1.9.3 on 2017-09-18 08:11 |
||||
from __future__ import unicode_literals |
||||
|
||||
from django.db import migrations, models |
||||
import django.db.models.deletion |
||||
|
||||
|
||||
class Migration(migrations.Migration): |
||||
|
||||
dependencies = [ |
||||
('courses', '0045_auto_20170918_0811'), |
||||
('finance', '0070_auto_20170424_1638'), |
||||
] |
||||
|
||||
operations = [ |
||||
migrations.AlterField( |
||||
model_name='bill', |
||||
name='create_letters', |
||||
field=models.ManyToManyField(blank=True, editable=False, related_name='bill_create_letter', to='service.MailBox', verbose_name='Письма при создании'), |
||||
), |
||||
migrations.AlterField( |
||||
model_name='bill', |
||||
name='finish_letters', |
||||
field=models.ManyToManyField(blank=True, editable=False, related_name='bill_finish_letter', to='service.MailBox', verbose_name='Письма завершения'), |
||||
), |
||||
migrations.AlterField( |
||||
model_name='installment', |
||||
name='payments', |
||||
field=models.ManyToManyField(blank=True, related_name='bill_point', to='finance.Bill', verbose_name='Платежи'), |
||||
), |
||||
migrations.AlterField( |
||||
model_name='price', |
||||
name='included', |
||||
field=models.ManyToManyField(blank=True, help_text='Если задействовать эту функцию, стандартная схема подписок будет не активна', to='courses.CourseMap', verbose_name='Включены'), |
||||
), |
||||
migrations.AlterField( |
||||
model_name='requestalert', |
||||
name='requests', |
||||
field=models.ManyToManyField(blank=True, editable=False, to='finance.ServiceRequest', verbose_name='Количество заявок'), |
||||
), |
||||
] |
||||
@ -1,22 +0,0 @@ |
||||
# -*- coding: utf-8 -*- |
||||
# Generated by Django 1.9.3 on 2017-08-10 09:04 |
||||
from __future__ import unicode_literals |
||||
|
||||
from django.db import migrations, models |
||||
import django.db.models.deletion |
||||
|
||||
|
||||
class Migration(migrations.Migration): |
||||
|
||||
dependencies = [ |
||||
('courses', '0045_auto_20170810_0904'), |
||||
('finance', '0070_auto_20170424_1638'), |
||||
] |
||||
|
||||
operations = [ |
||||
migrations.AddField( |
||||
model_name='bill', |
||||
name='flow', |
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='courses.Flow', verbose_name='Поток'), |
||||
), |
||||
] |
||||
@ -0,0 +1,25 @@ |
||||
# -*- coding: utf-8 -*- |
||||
# Generated by Django 1.9.3 on 2017-09-18 08:11 |
||||
from __future__ import unicode_literals |
||||
|
||||
from django.db import migrations, models |
||||
|
||||
|
||||
class Migration(migrations.Migration): |
||||
|
||||
dependencies = [ |
||||
('journals', '0072_auto_20170810_0904'), |
||||
] |
||||
|
||||
operations = [ |
||||
migrations.AlterField( |
||||
model_name='diplomaj', |
||||
name='key', |
||||
field=models.IntegerField(blank=True, null=True, verbose_name='Ключ'), |
||||
), |
||||
migrations.AlterField( |
||||
model_name='teacherj', |
||||
name='waiting', |
||||
field=models.ManyToManyField(blank=True, related_name='map_waiting', to='courses.CourseMap', verbose_name='Доп изучения'), |
||||
), |
||||
] |
||||
@ -0,0 +1,36 @@ |
||||
# -*- coding: utf-8 -*- |
||||
# Generated by Django 1.9.3 on 2017-09-18 08:11 |
||||
from __future__ import unicode_literals |
||||
|
||||
from django.conf import settings |
||||
from django.db import migrations, models |
||||
|
||||
|
||||
class Migration(migrations.Migration): |
||||
|
||||
dependencies = [ |
||||
('library', '0022_auto_20161101_1321'), |
||||
] |
||||
|
||||
operations = [ |
||||
migrations.AlterField( |
||||
model_name='article', |
||||
name='comments', |
||||
field=models.ManyToManyField(blank=True, editable=False, to='management.Comment', verbose_name='Комментарии'), |
||||
), |
||||
migrations.AlterField( |
||||
model_name='article', |
||||
name='favorite', |
||||
field=models.ManyToManyField(blank=True, editable=False, related_name='article_as_favorites', to=settings.AUTH_USER_MODEL, verbose_name='В фаворитах'), |
||||
), |
||||
migrations.AlterField( |
||||
model_name='article', |
||||
name='likes', |
||||
field=models.ManyToManyField(blank=True, editable=False, max_length=255, related_name='acticle_likes', to=settings.AUTH_USER_MODEL, verbose_name='Лайки'), |
||||
), |
||||
migrations.AlterField( |
||||
model_name='article', |
||||
name='tags', |
||||
field=models.ManyToManyField(blank=True, to='library.Tags', verbose_name='Теги'), |
||||
), |
||||
] |
||||
@ -0,0 +1,30 @@ |
||||
# -*- coding: utf-8 -*- |
||||
# Generated by Django 1.9.3 on 2017-09-18 08:11 |
||||
from __future__ import unicode_literals |
||||
|
||||
from django.db import migrations, models |
||||
|
||||
|
||||
class Migration(migrations.Migration): |
||||
|
||||
dependencies = [ |
||||
('management', '0090_auto_20161230_1643'), |
||||
] |
||||
|
||||
operations = [ |
||||
migrations.AlterField( |
||||
model_name='comment', |
||||
name='answers', |
||||
field=models.ManyToManyField(blank=True, editable=False, related_name='_comment_answers_+', to='management.Comment', verbose_name='Форумные ответы'), |
||||
), |
||||
migrations.AlterField( |
||||
model_name='comment', |
||||
name='replies', |
||||
field=models.ManyToManyField(blank=True, editable=False, related_name='_comment_replies_+', to='management.Comment', verbose_name='Ответы'), |
||||
), |
||||
migrations.AlterField( |
||||
model_name='faq', |
||||
name='comments', |
||||
field=models.ManyToManyField(blank=True, editable=False, to='management.Comment', verbose_name='Комментарии'), |
||||
), |
||||
] |
||||
Binary file not shown.
@ -0,0 +1,31 @@ |
||||
# -*- coding: utf-8 -*- |
||||
# Generated by Django 1.9.3 on 2017-09-18 08:11 |
||||
from __future__ import unicode_literals |
||||
|
||||
from django.conf import settings |
||||
from django.db import migrations, models |
||||
|
||||
|
||||
class Migration(migrations.Migration): |
||||
|
||||
dependencies = [ |
||||
('practice', '0020_workshop_body'), |
||||
] |
||||
|
||||
operations = [ |
||||
migrations.AlterField( |
||||
model_name='datasheet', |
||||
name='users', |
||||
field=models.ManyToManyField(blank=True, editable=False, to=settings.AUTH_USER_MODEL, verbose_name='Пользователи'), |
||||
), |
||||
migrations.AlterField( |
||||
model_name='workshop', |
||||
name='tools', |
||||
field=models.ManyToManyField(blank=True, to='practice.WorkshopTools', verbose_name='Используемые инструменты'), |
||||
), |
||||
migrations.AlterField( |
||||
model_name='workshop', |
||||
name='users', |
||||
field=models.ManyToManyField(blank=True, editable=False, to=settings.AUTH_USER_MODEL, verbose_name='Пользователи'), |
||||
), |
||||
] |
||||
Loading…
Reference in new issue