Merge branch 'feature/courses' into dev

remotes/origin/hasaccess
Ivlev Denis 8 years ago
commit cdf1b366bd
  1. 11
      apps/course/admin.py
  2. 11
      apps/course/filters.py
  3. 285
      apps/course/fixtures/course.json
  4. 73
      apps/course/migrations/0002_auto_20180126_1325.py
  5. 25
      apps/course/migrations/0003_auto_20180126_1347.py
  6. 43
      apps/course/models.py
  7. 12
      apps/course/templates/course/_items.html
  8. 5
      apps/course/templates/course/inclusion/category_menu_items.html
  9. 8
      apps/course/templatetags/lilcity_category.py
  10. 6
      apps/course/views.py
  11. 19
      docker-compose.yml
  12. BIN
      media/courses/pic-1_sTaZawQ.jpg
  13. 17
      project/settings.py
  14. 34
      project/templates/lilcity/index.html
  15. 2
      requirements.txt

@ -5,7 +5,16 @@ from .models import Course, Category
@admin.register(Course)
class CourseAdmin(admin.ModelAdmin):
pass
list_display = (
'author',
'title',
'price',
'is_infinite',
'category',
'status',
'created_at',
'update_at',
)
@admin.register(Category)

@ -0,0 +1,11 @@
import django_filters
from .models import Course
class CourseFilter(django_filters.FilterSet):
category = django_filters.CharFilter(field_name='category__title', lookup_expr='iexact')
class Meta:
model = Course
fields = ['category']

@ -0,0 +1,285 @@
[
{
"model": "course.course",
"pk": 1,
"fields": {
"author": 1,
"title": "\u0411\u0430\u0437\u043e\u0432\u044b\u0439 \u043a\u0443\u0440\u0441 \u0434\u043b\u044f \u0434\u0435\u0442\u0435\u0439 \u043f\u043e \u043e\u0441\u043d\u043e\u0432\u0430\u043c \u0438\u043b\u043b\u044e\u0441\u0442\u0440\u0430\u0446\u0438\u0438",
"short_description": "\u042d\u0442\u043e\u0442 \u043a\u0443\u0440\u0441 \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u0434\u0435\u0442\u044f\u043c \u0443\u0437\u043d\u0430\u0442\u044c \u043e \u0442\u043e\u043c \u043a\u0430\u043a \u0438\u0437 \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u0444\u043e\u0440\u043c \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0432\u0435\u0441\u0435\u043b\u044b\u0439 \u0438 \u0445\u0430\u0440\u0438\u0437\u043c\u0430\u0442\u0438\u0447\u043d\u044b\u0445 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0435\u0439.",
"cover": "courses/pic-1_sTaZawQ.jpg",
"price": "50.00",
"is_infinite": false,
"deferred_start_at": null,
"category": 2,
"duration": 1,
"is_featured": false,
"url": "https://gitlab.com/",
"status": 0,
"created_at": "2018-01-27T07:04:41.113Z",
"update_at": "2018-01-27T07:12:04.168Z"
}
},
{
"model": "course.course",
"pk": 2,
"fields": {
"author": 1,
"title": "\u0411\u0430\u0437\u043e\u0432\u044b\u0439 \u043a\u0443\u0440\u0441 \u0434\u043b\u044f \u0434\u0435\u0442\u0435\u0439 \u043f\u043e \u043e\u0441\u043d\u043e\u0432\u0430\u043c \u0438\u043b\u043b\u044e\u0441\u0442\u0440\u0430\u0446\u0438\u0438",
"short_description": "\u042d\u0442\u043e\u0442 \u043a\u0443\u0440\u0441 \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u0434\u0435\u0442\u044f\u043c \u0443\u0437\u043d\u0430\u0442\u044c \u043e \u0442\u043e\u043c \u043a\u0430\u043a \u0438\u0437 \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u0444\u043e\u0440\u043c \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0432\u0435\u0441\u0435\u043b\u044b\u0439 \u0438 \u0445\u0430\u0440\u0438\u0437\u043c\u0430\u0442\u0438\u0447\u043d\u044b\u0445 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0435\u0439.",
"cover": "courses/pic-1_sTaZawQ.jpg",
"price": "50.00",
"is_infinite": false,
"deferred_start_at": null,
"category": 1,
"duration": 1,
"is_featured": false,
"url": "https://gitlab.com/",
"status": 0,
"created_at": "2018-01-27T07:09:03.437Z",
"update_at": "2018-01-27T07:11:55.373Z"
}
},
{
"model": "course.course",
"pk": 3,
"fields": {
"author": 1,
"title": "\u0411\u0430\u0437\u043e\u0432\u044b\u0439 \u043a\u0443\u0440\u0441 \u0434\u043b\u044f \u0434\u0435\u0442\u0435\u0439 \u043f\u043e \u043e\u0441\u043d\u043e\u0432\u0430\u043c \u0438\u043b\u043b\u044e\u0441\u0442\u0440\u0430\u0446\u0438\u0438",
"short_description": "\u042d\u0442\u043e\u0442 \u043a\u0443\u0440\u0441 \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u0434\u0435\u0442\u044f\u043c \u0443\u0437\u043d\u0430\u0442\u044c \u043e \u0442\u043e\u043c \u043a\u0430\u043a \u0438\u0437 \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u0444\u043e\u0440\u043c \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0432\u0435\u0441\u0435\u043b\u044b\u0439 \u0438 \u0445\u0430\u0440\u0438\u0437\u043c\u0430\u0442\u0438\u0447\u043d\u044b\u0445 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0435\u0439.",
"cover": "courses/pic-1_sTaZawQ.jpg",
"price": "50.00",
"is_infinite": false,
"deferred_start_at": null,
"category": 9,
"duration": 1,
"is_featured": false,
"url": "https://gitlab.com/",
"status": 0,
"created_at": "2018-01-27T07:09:03.442Z",
"update_at": "2018-01-27T07:11:43.838Z"
}
},
{
"model": "course.course",
"pk": 4,
"fields": {
"author": 1,
"title": "\u0411\u0430\u0437\u043e\u0432\u044b\u0439 \u043a\u0443\u0440\u0441 \u0434\u043b\u044f \u0434\u0435\u0442\u0435\u0439 \u043f\u043e \u043e\u0441\u043d\u043e\u0432\u0430\u043c \u0438\u043b\u043b\u044e\u0441\u0442\u0440\u0430\u0446\u0438\u0438",
"short_description": "\u042d\u0442\u043e\u0442 \u043a\u0443\u0440\u0441 \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u0434\u0435\u0442\u044f\u043c \u0443\u0437\u043d\u0430\u0442\u044c \u043e \u0442\u043e\u043c \u043a\u0430\u043a \u0438\u0437 \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u0444\u043e\u0440\u043c \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0432\u0435\u0441\u0435\u043b\u044b\u0439 \u0438 \u0445\u0430\u0440\u0438\u0437\u043c\u0430\u0442\u0438\u0447\u043d\u044b\u0445 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0435\u0439.",
"cover": "courses/pic-1_sTaZawQ.jpg",
"price": "50.00",
"is_infinite": false,
"deferred_start_at": null,
"category": 8,
"duration": 1,
"is_featured": false,
"url": "https://gitlab.com/",
"status": 0,
"created_at": "2018-01-27T07:09:03.445Z",
"update_at": "2018-01-27T07:11:35.342Z"
}
},
{
"model": "course.course",
"pk": 5,
"fields": {
"author": 1,
"title": "\u0411\u0430\u0437\u043e\u0432\u044b\u0439 \u043a\u0443\u0440\u0441 \u0434\u043b\u044f \u0434\u0435\u0442\u0435\u0439 \u043f\u043e \u043e\u0441\u043d\u043e\u0432\u0430\u043c \u0438\u043b\u043b\u044e\u0441\u0442\u0440\u0430\u0446\u0438\u0438",
"short_description": "\u042d\u0442\u043e\u0442 \u043a\u0443\u0440\u0441 \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u0434\u0435\u0442\u044f\u043c \u0443\u0437\u043d\u0430\u0442\u044c \u043e \u0442\u043e\u043c \u043a\u0430\u043a \u0438\u0437 \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u0444\u043e\u0440\u043c \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0432\u0435\u0441\u0435\u043b\u044b\u0439 \u0438 \u0445\u0430\u0440\u0438\u0437\u043c\u0430\u0442\u0438\u0447\u043d\u044b\u0445 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0435\u0439.",
"cover": "courses/pic-1_sTaZawQ.jpg",
"price": "50.00",
"is_infinite": false,
"deferred_start_at": null,
"category": 7,
"duration": 1,
"is_featured": false,
"url": "https://gitlab.com/",
"status": 0,
"created_at": "2018-01-27T07:09:03.449Z",
"update_at": "2018-01-27T07:11:26.725Z"
}
},
{
"model": "course.course",
"pk": 6,
"fields": {
"author": 1,
"title": "\u0411\u0430\u0437\u043e\u0432\u044b\u0439 \u043a\u0443\u0440\u0441 \u0434\u043b\u044f \u0434\u0435\u0442\u0435\u0439 \u043f\u043e \u043e\u0441\u043d\u043e\u0432\u0430\u043c \u0438\u043b\u043b\u044e\u0441\u0442\u0440\u0430\u0446\u0438\u0438",
"short_description": "\u042d\u0442\u043e\u0442 \u043a\u0443\u0440\u0441 \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u0434\u0435\u0442\u044f\u043c \u0443\u0437\u043d\u0430\u0442\u044c \u043e \u0442\u043e\u043c \u043a\u0430\u043a \u0438\u0437 \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u0444\u043e\u0440\u043c \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0432\u0435\u0441\u0435\u043b\u044b\u0439 \u0438 \u0445\u0430\u0440\u0438\u0437\u043c\u0430\u0442\u0438\u0447\u043d\u044b\u0445 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0435\u0439.",
"cover": "courses/pic-1_sTaZawQ.jpg",
"price": "50.00",
"is_infinite": false,
"deferred_start_at": null,
"category": 6,
"duration": 1,
"is_featured": false,
"url": "https://gitlab.com/",
"status": 0,
"created_at": "2018-01-27T07:09:03.452Z",
"update_at": "2018-01-27T07:11:15.061Z"
}
},
{
"model": "course.course",
"pk": 7,
"fields": {
"author": 1,
"title": "\u0411\u0430\u0437\u043e\u0432\u044b\u0439 \u043a\u0443\u0440\u0441 \u0434\u043b\u044f \u0434\u0435\u0442\u0435\u0439 \u043f\u043e \u043e\u0441\u043d\u043e\u0432\u0430\u043c \u0438\u043b\u043b\u044e\u0441\u0442\u0440\u0430\u0446\u0438\u0438",
"short_description": "\u042d\u0442\u043e\u0442 \u043a\u0443\u0440\u0441 \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u0434\u0435\u0442\u044f\u043c \u0443\u0437\u043d\u0430\u0442\u044c \u043e \u0442\u043e\u043c \u043a\u0430\u043a \u0438\u0437 \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u0444\u043e\u0440\u043c \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0432\u0435\u0441\u0435\u043b\u044b\u0439 \u0438 \u0445\u0430\u0440\u0438\u0437\u043c\u0430\u0442\u0438\u0447\u043d\u044b\u0445 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0435\u0439.",
"cover": "courses/pic-1_sTaZawQ.jpg",
"price": "50.00",
"is_infinite": false,
"deferred_start_at": null,
"category": 5,
"duration": 1,
"is_featured": false,
"url": "https://gitlab.com/",
"status": 0,
"created_at": "2018-01-27T07:09:03.455Z",
"update_at": "2018-01-27T07:11:03.583Z"
}
},
{
"model": "course.course",
"pk": 8,
"fields": {
"author": 1,
"title": "\u0411\u0430\u0437\u043e\u0432\u044b\u0439 \u043a\u0443\u0440\u0441 \u0434\u043b\u044f \u0434\u0435\u0442\u0435\u0439 \u043f\u043e \u043e\u0441\u043d\u043e\u0432\u0430\u043c \u0438\u043b\u043b\u044e\u0441\u0442\u0440\u0430\u0446\u0438\u0438",
"short_description": "\u042d\u0442\u043e\u0442 \u043a\u0443\u0440\u0441 \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u0434\u0435\u0442\u044f\u043c \u0443\u0437\u043d\u0430\u0442\u044c \u043e \u0442\u043e\u043c \u043a\u0430\u043a \u0438\u0437 \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u0444\u043e\u0440\u043c \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0432\u0435\u0441\u0435\u043b\u044b\u0439 \u0438 \u0445\u0430\u0440\u0438\u0437\u043c\u0430\u0442\u0438\u0447\u043d\u044b\u0445 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0435\u0439.",
"cover": "courses/pic-1_sTaZawQ.jpg",
"price": "50.00",
"is_infinite": false,
"deferred_start_at": null,
"category": 4,
"duration": 1,
"is_featured": false,
"url": "https://gitlab.com/",
"status": 0,
"created_at": "2018-01-27T07:09:03.458Z",
"update_at": "2018-01-27T07:10:52.322Z"
}
},
{
"model": "course.course",
"pk": 9,
"fields": {
"author": 1,
"title": "\u0411\u0430\u0437\u043e\u0432\u044b\u0439 \u043a\u0443\u0440\u0441 \u0434\u043b\u044f \u0434\u0435\u0442\u0435\u0439 \u043f\u043e \u043e\u0441\u043d\u043e\u0432\u0430\u043c \u0438\u043b\u043b\u044e\u0441\u0442\u0440\u0430\u0446\u0438\u0438",
"short_description": "\u042d\u0442\u043e\u0442 \u043a\u0443\u0440\u0441 \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u0434\u0435\u0442\u044f\u043c \u0443\u0437\u043d\u0430\u0442\u044c \u043e \u0442\u043e\u043c \u043a\u0430\u043a \u0438\u0437 \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u0444\u043e\u0440\u043c \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0432\u0435\u0441\u0435\u043b\u044b\u0439 \u0438 \u0445\u0430\u0440\u0438\u0437\u043c\u0430\u0442\u0438\u0447\u043d\u044b\u0445 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0435\u0439.",
"cover": "courses/pic-1_sTaZawQ.jpg",
"price": "50.00",
"is_infinite": false,
"deferred_start_at": null,
"category": 3,
"duration": 1,
"is_featured": false,
"url": "https://gitlab.com/",
"status": 0,
"created_at": "2018-01-27T07:09:03.461Z",
"update_at": "2018-01-27T07:10:42.721Z"
}
},
{
"model": "course.course",
"pk": 10,
"fields": {
"author": 1,
"title": "\u0411\u0430\u0437\u043e\u0432\u044b\u0439 \u043a\u0443\u0440\u0441 \u0434\u043b\u044f \u0434\u0435\u0442\u0435\u0439 \u043f\u043e \u043e\u0441\u043d\u043e\u0432\u0430\u043c \u0438\u043b\u043b\u044e\u0441\u0442\u0440\u0430\u0446\u0438\u0438",
"short_description": "\u042d\u0442\u043e\u0442 \u043a\u0443\u0440\u0441 \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u0434\u0435\u0442\u044f\u043c \u0443\u0437\u043d\u0430\u0442\u044c \u043e \u0442\u043e\u043c \u043a\u0430\u043a \u0438\u0437 \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u0444\u043e\u0440\u043c \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0432\u0435\u0441\u0435\u043b\u044b\u0439 \u0438 \u0445\u0430\u0440\u0438\u0437\u043c\u0430\u0442\u0438\u0447\u043d\u044b\u0445 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0435\u0439.",
"cover": "courses/pic-1_sTaZawQ.jpg",
"price": "50.00",
"is_infinite": false,
"deferred_start_at": null,
"category": 2,
"duration": 1,
"is_featured": false,
"url": "https://gitlab.com/",
"status": 0,
"created_at": "2018-01-27T07:09:03.464Z",
"update_at": "2018-01-27T07:10:33.374Z"
}
},
{
"model": "course.course",
"pk": 11,
"fields": {
"author": 1,
"title": "\u0411\u0430\u0437\u043e\u0432\u044b\u0439 \u043a\u0443\u0440\u0441 \u0434\u043b\u044f \u0434\u0435\u0442\u0435\u0439 \u043f\u043e \u043e\u0441\u043d\u043e\u0432\u0430\u043c \u0438\u043b\u043b\u044e\u0441\u0442\u0440\u0430\u0446\u0438\u0438",
"short_description": "\u042d\u0442\u043e\u0442 \u043a\u0443\u0440\u0441 \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u0434\u0435\u0442\u044f\u043c \u0443\u0437\u043d\u0430\u0442\u044c \u043e \u0442\u043e\u043c \u043a\u0430\u043a \u0438\u0437 \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u0444\u043e\u0440\u043c \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0432\u0435\u0441\u0435\u043b\u044b\u0439 \u0438 \u0445\u0430\u0440\u0438\u0437\u043c\u0430\u0442\u0438\u0447\u043d\u044b\u0445 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0435\u0439.",
"cover": "courses/pic-1_sTaZawQ.jpg",
"price": "50.00",
"is_infinite": false,
"deferred_start_at": null,
"category": 1,
"duration": 1,
"is_featured": false,
"url": "https://gitlab.com/",
"status": 0,
"created_at": "2018-01-27T07:09:03.467Z",
"update_at": "2018-01-27T07:09:03.467Z"
}
},
{
"model": "course.category",
"pk": 1,
"fields": {
"title": "\u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436"
}
},
{
"model": "course.category",
"pk": 2,
"fields": {
"title": "\u0430\u043a\u0432\u0430\u0440\u0435\u043b\u044c"
}
},
{
"model": "course.category",
"pk": 3,
"fields": {
"title": "\u0438\u043b\u043b\u044e\u0441\u0442\u0440\u0430\u0446\u0438\u044f"
}
},
{
"model": "course.category",
"pk": 4,
"fields": {
"title": "\u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044f"
}
},
{
"model": "course.category",
"pk": 5,
"fields": {
"title": "\u043f\u0430\u0441\u0442\u0435\u043b\u044c"
}
},
{
"model": "course.category",
"pk": 6,
"fields": {
"title": "\u043f\u043b\u0430\u0441\u0442\u0438\u043b\u0438\u043d"
}
},
{
"model": "course.category",
"pk": 7,
"fields": {
"title": "\u043a\u0440\u0435\u0430\u0442\u0438\u0432\u043d\u043e\u0435 \u043c\u044b\u0448\u043b\u0435\u043d\u0438\u0435"
}
},
{
"model": "course.category",
"pk": 8,
"fields": {
"title": "\u043c\u043e\u0442\u043e\u0440\u0438\u043a\u0430"
}
},
{
"model": "course.category",
"pk": 9,
"fields": {
"title": "\u0436\u0438\u0432\u043e\u043f\u0438\u0441\u044c"
}
}
]

@ -0,0 +1,73 @@
# Generated by Django 2.0.1 on 2018-01-26 13:25
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('course', '0001_initial'),
]
operations = [
migrations.AlterModelOptions(
name='category',
options={'verbose_name': 'Категория', 'verbose_name_plural': 'Категории'},
),
migrations.AlterModelManagers(
name='category',
managers=[
],
),
migrations.RenameField(
model_name='course',
old_name='background',
new_name='cover',
),
migrations.RenameField(
model_name='course',
old_name='deferred_start',
new_name='deferred_start_at',
),
migrations.RenameField(
model_name='course',
old_name='is_highlighted',
new_name='is_featured',
),
migrations.RemoveField(
model_name='course',
name='created_at',
),
migrations.RemoveField(
model_name='course',
name='update_at',
),
migrations.AddField(
model_name='course',
name='author',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='course',
name='duration',
field=models.IntegerField(default=0, verbose_name='Продолжительность курса'),
),
migrations.AddField(
model_name='course',
name='is_infinite',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='course',
name='status',
field=models.PositiveSmallIntegerField(choices=[(0, 'Pending'), (1, 'Published'), (2, 'Archived')], default=0, verbose_name='Статус'),
),
migrations.AddField(
model_name='course',
name='url',
field=models.URLField(default='', verbose_name='Ссылка'),
),
]

@ -0,0 +1,25 @@
# Generated by Django 2.0.1 on 2018-01-26 13:47
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('course', '0002_auto_20180126_1325'),
]
operations = [
migrations.AddField(
model_name='course',
name='created_at',
field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
preserve_default=False,
),
migrations.AddField(
model_name='course',
name='update_at',
field=models.DateTimeField(auto_now=True),
),
]

@ -1,32 +1,55 @@
import arrow
from django.db import models
from django.utils import timezone
from django.contrib.auth import get_user_model
from .manager import CategoryQuerySet
User = get_user_model()
class Course(models.Model):
STATUS_CHOICES = (
(0, 'Pending'),
(1, 'Published'),
(2, 'Archived'),
)
author = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
title = models.CharField("Название курса", max_length=100)
short_description = models.TextField("Краткое описание курса")
background = models.ImageField("Фон курса", upload_to='courses')
cover = 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)
is_infinite = models.BooleanField(default=False)
deferred_start_at = models.DateTimeField("Отложенный запуск курса", help_text="Заполнить если курс отложенный", null=True, blank=True)
category = models.ForeignKey("Category", on_delete=models.PROTECT)
duration = models.IntegerField("Продолжительность курса", default=0)
is_featured = models.BooleanField(default=False)
url = models.URLField('Ссылка', default='')
status = models.PositiveSmallIntegerField('Статус', default=0, choices=STATUS_CHOICES)
created_at = models.DateTimeField(auto_created=True)
created_at = models.DateTimeField(auto_now_add=True)
update_at = models.DateTimeField(auto_now=True)
@property
def is_free(self):
if self.price:
return False
return True
@property
def deferred_start_at_humanize(self):
return arrow.get(self.deferred_start_at).humanize(locale='ru')
@property
def created_at_humanize(self):
return arrow.get(self.created_at).humanize(locale='ru')
@property
def is_deferred_start(self):
if not self.deferred_start:
if not self.deferred_start_at:
return False
if timezone.now() < self.deferred_start:
if timezone.now() < self.deferred_start_at:
return True
return False
@ -38,7 +61,9 @@ class Course(models.Model):
class Category(models.Model):
title = models.CharField("Название категории", max_length=100)
manager = CategoryQuerySet.as_manager()
def __str__(self):
return self.title
class Meta:
verbose_name = "Категория"
verbose_name_plural = "Категории"

@ -1,19 +1,19 @@
{% load static %}
<div class="courses__item"><a class="courses__preview" href="#"><img class="courses__pic" src="{% get_media_prefix %}{{ course.background }}"/>
<div class="courses__item"><a class="courses__preview" href="#"><img class="courses__pic" src="{{ course.cover.url }}"/>
<div class="courses__view">Подробнее</div>
{% if course.is_highlighted %}
{% if course.is_featured %}
<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 class="courses__time">{{ course.deferred_start_at_humanize }}</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>
<div class="courses__details"><a class="courses__theme theme {{ theme_color }}" href="#">{{ course.category | upper }}</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>
@ -22,9 +22,9 @@
<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__name">{{ course.author.first_name }} {{ course.author.last_name }}</div>
<div class="user__meta">
<div class="user__date">SEPT 12, 2017</div>
<div class="user__date">{{ course.created_at_humanize }}</div>
<a class="user__likes likes" href="#">
<div class="likes__counter">253</div>
<div class="likes__icon">

@ -0,0 +1,5 @@
{% for category in category_items %}
<a class="header__link" href="{% url 'courses' %}?category={{ category.title }}">
<div class="header__title">{{ category.title }}</div>
</a>
{% endfor %}

@ -2,10 +2,14 @@ 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()}
return {"category_items": Category.objects.all()}
@register.inclusion_tag('course/inclusion/category_menu_items.html')
def category_menu_items():
return {"category_items": Category.objects.all()}

@ -1,6 +1,7 @@
from django.views.generic import ListView
from .models import Course
from .filters import CourseFilter
class CoursesView(ListView):
@ -8,6 +9,11 @@ class CoursesView(ListView):
context_object_name = "course_items"
paginate_by = 6
def get_queryset(self):
queryset = super().get_queryset()
filtered = CourseFilter(self.request.GET, queryset=queryset)
return filtered.qs
def get_template_names(self):
if self.request.is_ajax():
return 'course/course_items.html'

@ -1,10 +1,16 @@
version: '3'
services:
postgres:
image: postgres:9.6
db:
image: postgres:10-alpine
environment:
- POSTGRES_PASSWORD=1234
- POSTGRES_USER=postgres
- LANG=ru_RU.UTF-8
- POSTGRES_DB=lilcity
- POSTGRES_USER=lilcity
- POSTGRES_PASSWORD=GPVs/E/{5&qe
- PGDATA=/var/lib/postgresql/data/pgdata
ports:
- "5432:5432"
web:
build: .
@ -14,7 +20,10 @@ services:
command: bash -c "python manage.py migrate && python manage.py loaddata /lilcity/apps/*/fixtures/*.json && python manage.py runserver 0.0.0.0:8000"
environment:
- DJANGO_SETTINGS_MODULE=project.settings
- DATABASE_SERVICE_HOST=db
ports:
- "8000:8000"
depends_on:
- postgres
- db
links:
- db

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

@ -39,6 +39,7 @@ INSTALLED_APPS = [
] + [
'anymail',
'active_link',
'django_filters',
] + [
'apps.auth.apps',
'apps.user',
@ -83,14 +84,24 @@ WSGI_APPLICATION = 'project.wsgi.application'
# Database
# https://docs.djangoproject.com/en/2.0/ref/settings/#databases
# DATABASES = {
# 'default': {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
# }
# }
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'lilcity',
'USER': 'lilcity',
'PASSWORD': 'GPVs/E/{5&qe',
'HOST': os.getenv('DATABASE_SERVICE_HOST', '127.0.0.1'),
'PORT': 5432,
}
}
# Password validation
# https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators

@ -1,12 +1,16 @@
{% load static %}
{% load active_link_tags %}
{% load category_menu_items from lilcity_category %}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Index Page</title>
<title>
{% block title %}Онлайн-курсы LilCity{% endblock title%}
</title>
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<meta name="theme-color" content="#fff">
@ -108,33 +112,7 @@
</div>
<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">
<a class="header__link" href="#">
<div class="header__title">ПЕРСОНАЖ</div>
</a>
<a class="header__link" href="#">
<div class="header__title">АКВАРЕЛЬ</div>
</a>
<a class="header__link" href="#">
<div class="header__title">ИЛЛЮСТРАЦИЯ</div>
</a>
<a class="header__link" href="#">
<div class="header__title">АНИМАЦИЯ</div>
</a>
<a class="header__link" href="#">
<div class="header__title">ПАСТЕЛЬ</div>
</a>
<a class="header__link" href="#">
<div class="header__title">ПЛАСТИЛИН</div>
</a>
<a class="header__link" href="#">
<div class="header__title">КРЕАТИВНОЕ МЫШЛЕНИЕ</div>
</a>
<a class="header__link" href="#">
<div class="header__title">МОТОРИКА</div>
</a>
<a class="header__link" href="#">
<div class="header__title">ЖИВОПИСЬ</div>
</a>
{% category_menu_items %}
</div>
</div>
<div class="header__group"><a class="header__section" href="#">БЛОГ</a></div>

@ -7,3 +7,5 @@ psycopg2==2.7.3.2
facepy==1.0.9
Pillow==5.0.0
django-active-link==0.1.2
arrow==0.12.1
django-filter==2.0.0.dev1

Loading…
Cancel
Save