Feature/created courses See merge request lilcity/backend!3remotes/origin/hasaccess
commit
6aa3acdd8c
22 changed files with 273 additions and 37 deletions
@ -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" |
||||||
|
Before Width: | Height: | Size: 161 KiB |
Loading…
Reference in new issue