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