Merge branch 'feature/created_courses' into 'master'

Feature/created courses

See merge request lilcity/backend!3
remotes/origin/hasaccess
cfwme 8 years ago
commit 6aa3acdd8c
  1. 3
      .gitignore
  2. 0
      apps/course/__init__.py
  3. 13
      apps/course/admin.py
  4. 6
      apps/course/apps.py
  5. 6
      apps/course/manager.py
  6. 45
      apps/course/migrations/0001_initial.py
  7. 0
      apps/course/migrations/__init__.py
  8. 44
      apps/course/models.py
  9. 42
      apps/course/templates/course/_items.html
  10. 4
      apps/course/templates/course/course_items.html
  11. 53
      apps/course/templates/course/courses.html
  12. 5
      apps/course/templates/course/inclusion/category_items.html
  13. 0
      apps/course/templatetags/__init__.py
  14. 11
      apps/course/templatetags/lilcity_category.py
  15. 3
      apps/course/tests.py
  16. 14
      apps/course/views.py
  17. BIN
      docs/entities-diagram.png
  18. 2
      docs/overview.md
  19. 4
      project/settings.py
  20. 40
      project/templates/lilcity/index.html
  21. 11
      project/urls.py
  22. 4
      requirements.txt

3
.gitignore vendored

@ -109,4 +109,5 @@ venv.bak/
# JavaScript # JavaScript
.map .map
node_modules node_modules
db.sqlite3

@ -0,0 +1,13 @@
from django.contrib import admin
from .models import Course, Category
@admin.register(Course)
class CourseAdmin(admin.ModelAdmin):
pass
@admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
pass

@ -0,0 +1,6 @@
from django.apps import AppConfig
class CourseConfig(AppConfig):
name = 'apps.course'
label = 'lilcity_course'

@ -0,0 +1,6 @@
from django.db import models
class CategoryQuerySet(models.QuerySet):
def all(self):
return self.filter()

@ -0,0 +1,45 @@
# Generated by Django 2.0.1 on 2018-01-22 11:43
from django.db import migrations, models
import django.db.models.deletion
import django.db.models.manager
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Category',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=100, verbose_name='Название категории')),
],
managers=[
('manager', django.db.models.manager.Manager()),
],
),
migrations.CreateModel(
name='Course',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_created=True)),
('title', models.CharField(max_length=100, verbose_name='Название курса')),
('short_description', models.TextField(verbose_name='Краткое описание курса')),
('background', models.ImageField(upload_to='courses', verbose_name='Фон курса')),
('price', models.DecimalField(blank=True, decimal_places=2, help_text='Если цены нету, то курс бесплатный', max_digits=10, null=True, verbose_name='Цена курса')),
('is_highlighted', models.BooleanField(default=False)),
('deferred_start', models.DateTimeField(blank=True, help_text='Заполнить если курс отложенный', null=True, verbose_name='Отложенный запуск курса')),
('update_at', models.DateTimeField(auto_now=True)),
('category', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='course.Category')),
],
options={
'verbose_name': 'Курс',
'verbose_name_plural': 'Курсы',
},
),
]

@ -0,0 +1,44 @@
from django.db import models
from django.utils import timezone
from .manager import CategoryQuerySet
class Course(models.Model):
title = models.CharField("Название курса", max_length=100)
short_description = models.TextField("Краткое описание курса")
background = models.ImageField("Фон курса", upload_to='courses')
price = models.DecimalField("Цена курса", help_text="Если цены нету, то курс бесплатный", max_digits=10, decimal_places=2, null=True, blank=True)
is_highlighted = models.BooleanField(default=False)
deferred_start = models.DateTimeField("Отложенный запуск курса", help_text="Заполнить если курс отложенный", null=True, blank=True)
category = models.ForeignKey("Category", on_delete=models.PROTECT)
created_at = models.DateTimeField(auto_created=True)
update_at = models.DateTimeField(auto_now=True)
def is_free(self):
if self.price:
return False
return True
def is_deferred_start(self):
if not self.deferred_start:
return False
if timezone.now() < self.deferred_start:
return True
return False
class Meta:
verbose_name = "Курс"
verbose_name_plural = "Курсы"
class Category(models.Model):
title = models.CharField("Название категории", max_length=100)
manager = CategoryQuerySet.as_manager()
def __str__(self):
return self.title

@ -0,0 +1,42 @@
{% load static %}
<div class="courses__item"><a class="courses__preview" href="#"><img class="courses__pic" src="{% get_media_prefix %}{{ course.background }}"/>
<div class="courses__view">Подробнее</div>
{% if course.is_highlighted %}
<div class="courses__label courses__label_fav"></div>
{% endif %}
{% if course.is_deferred_start %}
<div class="courses__soon">
<div class="courses__left">До запуска курса осталось:</div>
<div class="courses__time">16 часов 13 минут</div>
</div>
<div class="courses__label courses__label_clock"></div>
{% endif %}
</a>
<div class="courses__details"><a class="courses__theme theme {{ theme_color }}" href="#">АНИМАЦИЯ</a>
{% if not course.is_free %}<div class="courses__price">{{ course.price|floatformat:"-2" }}$</div>{% endif %}
</div>
<a class="courses__title" href="#">{{ course.title }}</a>
<div class="courses__content">{{ course.short_description }}
</div>
<div class="courses__user user">
<div class="user__ava ava"><img class="ava__pic" src={% static "img/user.jpg" %}/></div>
<div class="user__info">
<div class="user__name">Александра Неимоверноумная</div>
<div class="user__meta">
<div class="user__date">SEPT 12, 2017</div>
<a class="user__likes likes" href="#">
<div class="likes__counter">253</div>
<div class="likes__icon">
<svg class="icon icon-like">
<use xlink:href="{% get_static_prefix %}img/sprite.svg#icon-like"></use>
</svg>
<svg class="icon icon-like-fill">
<use xlink:href="{% get_static_prefix %}img/sprite.svg#icon-like-fill"></use>
</svg>
</div>
</a>
</div>
</div>
</div>
</div>

@ -0,0 +1,4 @@
{% for course in course_items %}
{% cycle '' 'theme_green' 'theme_violet' as theme_color silent %}
{% include "course/_items.html" %}
{% endfor %}

@ -0,0 +1,53 @@
{% extends "templates/lilcity/index.html" %}
{% load static %}
{% load category_items from lilcity_category %}
{% block content %}
<div class="main" style="background-image: url({% get_static_prefix %}img/bg-1.jpg);">
<div class="main__center center">
<div class="main__title">Онлайн-курсы LilCity</div>
</div>
</div>
<div class="section">
<div class="section__center center">
<div class="text text_lg">
<p>Учите и развивайте креативное мышление когда и где угодно. Если вам не совсем удобно заниматься с нами в прямом эфире каждый день как в
нашей онлайн-школе, специально для вас мы делаем отдельные уроки в записи, которые вы можете проходить
когда вам будем удобно.</p><img class="text__curve text__curve_four" src="{% get_static_prefix %}img/curve-4.svg" %} width="155"></div>
<div class="head">
<div class="head__title title title_center">Курсы</div>
<div class="head__right">
<div class="head__field field">
<div class="field__wrap">
<div class="field__select select js-select">
<div class="select__head js-select-head">Категории</div>
<div class="select__drop js-select-drop">
{% category_items %}
</div>
<input class="select__input" type="hidden"></div>
</div>
</div>
</div>
</div>
<div class="courses">
<div class="courses__list">
{% include "course/course_items.html" %}
</div>
<div class="courses__load load">
{% if page_obj.has_next %}
<button class="load__btn btn" data-next-page-url="?page={{ page_obj.next_page_number }}">Подгрузить еще</button>
{% endif %}
</div>
</div>
</div>
</div>
<div class="game">
<div class="game__center center">
<div class="game__wrap">
<div class="game__theme">LILCITY</div>
<div class="game__title">Приложения, развивающие игры и интерактивные книги от Lil City.</div>
<a class="game__btn btn btn_dark" href="#">УЗНАТЬ БОЛЬШЕ</a></div>
</div>
<div class="game__preview"><img class="game__pic" src="{% get_static_prefix %}img/icons.png" %}></div>
</div>
{% endblock content %}

@ -0,0 +1,5 @@
{% for category in category_items %}
<div class="select__option js-select-option">
<div class="select__title">{{ category.title }}</div>
</div>
{% endfor %}

@ -0,0 +1,11 @@
from django import template
from ..models import Category
register = template.Library()
@register.inclusion_tag('course/inclusion/category_items.html')
def category_items():
return {"category_items": Category.manager.all()}

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

@ -0,0 +1,14 @@
from django.views.generic import ListView
from .models import Course
class CoursesView(ListView):
model = Course
context_object_name = "course_items"
paginate_by = 6
def get_template_names(self):
if self.request.is_ajax():
return 'course/course_items.html'
return "course/courses.html"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 161 KiB

@ -45,4 +45,4 @@ CRUD для целей доступа к персистентным хранил
### Диаграмма сущностей проекта ### Диаграмма сущностей проекта
![Диаграмма сущностей проекта.png](entities-diagram.png) Актуальная версия: [Google Drive](https://drive.google.com/file/d/1OPt3_M0VrVBkRK1M4LTLJ-UMFEwojMzc/view?usp=sharing)

@ -39,11 +39,13 @@ INSTALLED_APPS = [
'django.contrib.staticfiles', 'django.contrib.staticfiles',
] + [ ] + [
'anymail', 'anymail',
'active_link',
] + [ ] + [
'apps.auth.apps', 'apps.auth.apps',
'apps.user', 'apps.user',
'apps.notification', 'apps.notification',
'apps.payment', 'apps.payment',
'apps.course',
] ]
MIDDLEWARE = [ MIDDLEWARE = [
@ -153,3 +155,5 @@ DEFAULT_FROM_EMAIL = "postmaster@mail.9ev.ru"
TWILIO_ACCOUNT = 'ACdf4a96b776cc764bc3ec0f0e136ba550' TWILIO_ACCOUNT = 'ACdf4a96b776cc764bc3ec0f0e136ba550'
TWILIO_TOKEN = '559a6b1fce121759c9af2dcbb3f755ea' TWILIO_TOKEN = '559a6b1fce121759c9af2dcbb3f755ea'
TWILIO_FROM_PHONE = '+37128914409' TWILIO_FROM_PHONE = '+37128914409'
ACTIVE_LINK_STRICT = True

@ -1,4 +1,6 @@
{% load static %} {% load static %}
{% load active_link_tags %}
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
@ -52,7 +54,7 @@
<use xlink:href={% static "img/sprite.svg" %}#icon-menu></use> <use xlink:href={% static "img/sprite.svg" %}#icon-menu></use>
</svg> </svg>
</button> </button>
<a class="header__logo logo" href="#"></a> <a class="header__logo logo" href="/"></a>
<div class="header__wrap js-header-wrap"> <div class="header__wrap js-header-wrap">
<div class="header__top"> <div class="header__top">
<button class="header__close js-header-close"> <button class="header__close js-header-close">
@ -70,7 +72,7 @@
</form> </form>
</div> </div>
<nav class="header__nav"> <nav class="header__nav">
<div class="header__group"><a class="header__section header__section_sub js-header-section active" href="#">ОНЛАЙН-ШКОЛА</a> <div class="header__group"><a class="header__section header__section_sub js-header-section {% active_link 'index' %}" href="{% url 'index' %}">ОНЛАЙН-ШКОЛА</a>
<div class="header__list js-header-list"> <div class="header__list js-header-list">
<a class="header__link" href="#"> <a class="header__link" href="#">
<div class="header__title">О школе</div> <div class="header__title">О школе</div>
@ -104,7 +106,7 @@
</a> </a>
</div> </div>
</div> </div>
<div class="header__group"><a class="header__section header__section_sub js-header-section" href="#">ВИДЕО-КУРСЫ</a> <div class="header__group"><a class="header__section header__section_sub js-header-section {% active_link 'courses' %}" href="{% url 'courses' %}">ВИДЕО-КУРСЫ</a>
<div class="header__list js-header-list"> <div class="header__list js-header-list">
<a class="header__link" href="#"> <a class="header__link" href="#">
<div class="header__title">ПЕРСОНАЖ</div> <div class="header__title">ПЕРСОНАЖ</div>
@ -147,40 +149,12 @@
</div> </div>
</header> </header>
<div class="container"> <div class="container">
<div class="center" style="padding-top: 50px; padding-bottom: 50px;"> {% block content %}{% endblock content %}
<div><a href="email/index.html">email.html</a></div>
<br>
<div><a href="ui-kit.html">ui-kit.html</a></div>
<br>
<div><a href="main.html">main.html</a></div>
<div><a href="main-online.html">main-online.html</a></div>
<div><a href="main-online-soon.html">main-online-soon.html</a></div>
<div><a href="courses.html">courses.html</a></div>
<div><a href="result.html">result.html</a></div>
<div><a href="result-empty.html">result-empty.html</a></div>
<div><a href="course.html">course.html</a></div>
<div><a href="course-v2.html">course-v2.html</a></div>
<div><a href="course-soon.html">course-soon.html</a></div>
<div><a href="course-lock.html">course-lock.html</a></div>
<div><a href="course-bought.html">course-bought.html</a></div>
<div><a href="lesson.html">lesson.html</a></div>
<div><a href="profile.html">profile.html</a></div>
<div><a href="profile-settings.html">profile-settings.html</a></div>
<div><a href="profile-alerts.html">profile-alerts.html</a></div>
<div><a href="become-author.html">become-author.html</a></div>
<div><a href="history-transactions.html">history-transactions.html</a></div>
<div><a href="success-payment.html">success-payment.html</a></div>
<div><a href="success-application.html">success-application.html</a></div>
<br>
<div><a href="course-add.html">course-add.html</a></div>
<div><a href="course-add-lessons.html">course-add-lessons.html</a></div>
<div><a href="lesson-add.html">lesson-add.html</a></div>
</div>
</div> </div>
<footer class="footer"> <footer class="footer">
<div class="footer__center center"> <div class="footer__center center">
<div class="footer__row footer__row_first"> <div class="footer__row footer__row_first">
<div class="footer__col footer__col_md"><a class="footer__logo logo" href="#"></a> <div class="footer__col footer__col_md"><a class="footer__logo logo" href="/"></a>
<div class="footer__content">Первая онлайн-школа креативного мышления Lil City School</div> <div class="footer__content">Первая онлайн-школа креативного мышления Lil City School</div>
</div> </div>
<div class="footer__col"> <div class="footer__col">

@ -16,9 +16,18 @@ Including another URLconf
from django.contrib import admin from django.contrib import admin
from django.urls import path, include from django.urls import path, include
from django.views.generic import TemplateView from django.views.generic import TemplateView
from django.conf import settings
from apps.course.views import CoursesView
urlpatterns = [ urlpatterns = [
path('admin/', admin.site.urls), path('admin/', admin.site.urls),
path('auth/', include(('apps.auth.urls', 'lilcity'))), path('auth/', include(('apps.auth.urls', 'lilcity'))),
path('', TemplateView.as_view(template_name="templates/lilcity/index.html")), path('courses/', CoursesView.as_view(), name='courses'),
path('', TemplateView.as_view(template_name="templates/lilcity/index.html"), name='index'),
] ]
if settings.DEBUG:
from django.conf.urls.static import static
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

@ -4,4 +4,6 @@ django-anymail[mailgun]==1.2
paymentwall-python==1.0.7 paymentwall-python==1.0.7
twilio==6.10.0 twilio==6.10.0
psycopg2==2.7.3.2 psycopg2==2.7.3.2
facepy==1.0.9 facepy==1.0.9
Pillow==5.0.0
django-active-link==0.1.2

Loading…
Cancel
Save