django-modules-forms 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,46 @@
1
+ {% extends 'base.html' %}
2
+
3
+ {% block title %}Отзыв - Пластинка{% endblock %}
4
+
5
+ {% block content %}
6
+ <div class="row justify-content-center">
7
+ <div class="col-md-8 col-lg-6">
8
+ <div class="glass-card p-4 p-md-5">
9
+ <div class="text-center mb-4">
10
+ <div class="display-1 mb-3">⭐</div>
11
+ <h2 class="mb-2">Оставить отзыв</h2>
12
+ <p class="text-secondary">Поделись впечатлениями о курсе</p>
13
+ </div>
14
+
15
+ <div class="glass-card p-3 mb-4">
16
+ <h5 class="mb-2">{{ application.course }}</h5>
17
+ <p class="text-secondary mb-1">📅 {{ application.desired_start_date|date:"d.m.Y" }}</p>
18
+ <p class="text-secondary mb-0">💳 {{ application.get_payment_method_display }}</p>
19
+ </div>
20
+
21
+ <form method="post">
22
+ {% csrf_token %}
23
+ {% for field in form %}
24
+ <div class="mb-3">
25
+ <label for="{{ field.id_for_label }}" class="form-label">{{ field.label }}</label>
26
+ {{ field }}
27
+ {% if field.errors %}
28
+ <div class="text-danger small mt-1">
29
+ {% for error in field.errors %}
30
+ {{ error }}
31
+ {% endfor %}
32
+ </div>
33
+ {% endif %}
34
+ </div>
35
+ {% endfor %}
36
+ <button type="submit" class="btn btn-primary w-100 py-3">
37
+ 📝 Опубликовать отзыв
38
+ </button>
39
+ <a href="{% url 'applications' %}" class="btn btn-outline-secondary w-100 mt-2">
40
+ Отмена
41
+ </a>
42
+ </form>
43
+ </div>
44
+ </div>
45
+ </div>
46
+ {% endblock %}
@@ -0,0 +1,73 @@
1
+ {% extends 'base.html' %}
2
+ {% load static %}
3
+
4
+ {% block title %}Мои заявки - Пластинка{% endblock %}
5
+
6
+ {% block content %}
7
+ <div class="d-flex justify-content-between align-items-center mb-4">
8
+ <div>
9
+ <h2 class="mb-1">Мои заявки</h2>
10
+ <p class="text-secondary">Все твои заявки на обучение</p>
11
+ </div>
12
+ <a href="{% url 'create_application' %}" class="btn btn-primary">
13
+ ➕ Новая заявка
14
+ </a>
15
+ </div>
16
+
17
+ {% if applications %}
18
+ <div class="row">
19
+ {% for application in applications %}
20
+ <div class="col-md-6 mb-4">
21
+ <div class="application-card p-4
22
+ {% if application.status == 'new' %}application-new
23
+ {% elif application.status == 'in_progress' %}application-in-progress
24
+ {% elif application.status == 'completed' %}application-completed{% endif %}">
25
+
26
+ <div class="d-flex justify-content-between align-items-start mb-3">
27
+ <h4 class="mb-0">{{ application.course }}</h4>
28
+ <span class="badge
29
+ {% if application.status == 'new' %}bg-success
30
+ {% elif application.status == 'in_progress' %}bg-warning
31
+ {% else %}bg-secondary{% endif %}">
32
+ {{ application.get_status_display }}
33
+ </span>
34
+ </div>
35
+
36
+ <div class="text-secondary mb-3">
37
+ <div class="mb-2">
38
+ <span class="me-3">📅 {{ application.desired_start_date|date:"d.m.Y" }}</span>
39
+ <span>💳 {{ application.get_payment_method_display }}</span>
40
+ </div>
41
+ <div>🕐 Подана: {{ application.created_at|date:"d.m.Y H:i" }}</div>
42
+ </div>
43
+
44
+ {% if application.status == 'completed' %}
45
+ <div class="mt-3">
46
+ {% if application.review %}
47
+ <div class="alert alert-info">
48
+ <strong>⭐ Твой отзыв:</strong><br>
49
+ Оценка: {{ application.review.rating }}/5<br>
50
+ {{ application.review.text }}
51
+ </div>
52
+ {% else %}
53
+ <a href="{% url 'add_review' application.id %}" class="btn btn-outline-primary">
54
+ 📝 Оставить отзыв
55
+ </a>
56
+ {% endif %}
57
+ </div>
58
+ {% endif %}
59
+ </div>
60
+ </div>
61
+ {% endfor %}
62
+ </div>
63
+ {% else %}
64
+ <div class="glass-card text-center p-5">
65
+ <div class="display-1 mb-3">📭</div>
66
+ <h4 class="mb-2">У тебя пока нет заявок</h4>
67
+ <p class="text-secondary mb-4">Подай первую заявку на обучение!</p>
68
+ <a href="{% url 'create_application' %}" class="btn btn-primary btn-lg">
69
+ 🎵 Подать заявку
70
+ </a>
71
+ </div>
72
+ {% endif %}
73
+ {% endblock %}
@@ -0,0 +1,66 @@
1
+ {% load static %}
2
+ <!DOCTYPE html>
3
+ <html lang="ru">
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
7
+ <title>{% block title %}Пластинка{% endblock %}</title>
8
+ <meta name="description" content="{% block description %}Онлайн курсы дополнительного профессионального образования{% endblock %}">
9
+ <meta name="keywords" content="{% block keywords %}курсы, обучение, образование{% endblock %}">
10
+
11
+ <!-- Локальный Bootstrap CSS -->
12
+ <link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet">
13
+
14
+ <!-- Локальные стили -->
15
+ <link href="{% static 'styles.css' %}" rel="stylesheet">
16
+
17
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
18
+ <style>
19
+ body {
20
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
21
+ }
22
+ </style>
23
+ </head>
24
+ <body>
25
+ <nav class="navbar navbar-expand-lg fixed-top">
26
+ <div class="container">
27
+ <a class="navbar-brand" href="/">🎵 Пластинка</a>
28
+ <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
29
+ <span class="navbar-toggler-icon"></span>
30
+ </button>
31
+ <div class="collapse navbar-collapse" id="navbarNav">
32
+ <div class="navbar-nav ms-auto">
33
+ {% if user.is_authenticated %}
34
+ <a class="nav-link" href="/applications/">📋 Мои заявки</a>
35
+ <a class="nav-link" href="/applications/create/">🎵 Подать заявку</a>
36
+ {% if user.is_staff %}
37
+ <a class="nav-link" href="/admin/">⚡ Админка</a>
38
+ {% endif %}
39
+ <a class="nav-link" href="/logout/">🚪 Выйти ({{ user.username }})</a>
40
+ {% else %}
41
+ <a class="nav-link" href="/login/">🔑 Войти</a>
42
+ <a class="nav-link" href="/register/">✨ Регистрация</a>
43
+ {% endif %}
44
+ </div>
45
+ </div>
46
+ </div>
47
+ </nav>
48
+
49
+ <main class="container">
50
+ {% if messages %}
51
+ {% for message in messages %}
52
+ <div class="alert alert-{{ message.tags }} alert-dismissible fade show" role="alert">
53
+ {{ message }}
54
+ <button type="button" class="btn-close" data-bs-dismiss="alert"></button>
55
+ </div>
56
+ {% endfor %}
57
+ {% endif %}
58
+
59
+ {% block content %}
60
+ {% endblock %}
61
+ </main>
62
+
63
+ <!-- Локальный Bootstrap JS -->
64
+ <script src="{% static 'js/bootstrap.bundle.min.js' %}"></script>
65
+ </body>
66
+ </html>
@@ -0,0 +1,40 @@
1
+ {% extends 'base.html' %}
2
+
3
+ {% block title %}Подача заявки - Пластинка{% endblock %}
4
+
5
+ {% block content %}
6
+ <div class="row justify-content-center">
7
+ <div class="col-md-8 col-lg-6">
8
+ <div class="glass-card p-4 p-md-5">
9
+ <div class="text-center mb-4">
10
+ <div class="display-1 mb-3">🎵</div>
11
+ <h2 class="mb-2">Новая заявка</h2>
12
+ <p class="text-secondary">Заполни форму и начни обучение</p>
13
+ </div>
14
+
15
+ <form method="post">
16
+ {% csrf_token %}
17
+ {% for field in form %}
18
+ <div class="mb-3">
19
+ <label for="{{ field.id_for_label }}" class="form-label">{{ field.label }}</label>
20
+ {{ field }}
21
+ {% if field.help_text %}
22
+ <div class="form-text">{{ field.help_text }}</div>
23
+ {% endif %}
24
+ {% if field.errors %}
25
+ <div class="text-danger small mt-1">
26
+ {% for error in field.errors %}
27
+ {{ error }}
28
+ {% endfor %}
29
+ </div>
30
+ {% endif %}
31
+ </div>
32
+ {% endfor %}
33
+ <button type="submit" class="btn btn-primary w-100 py-3">
34
+ ✨ Отправить заявку
35
+ </button>
36
+ </form>
37
+ </div>
38
+ </div>
39
+ </div>
40
+ {% endblock %}
@@ -0,0 +1,69 @@
1
+ {% extends 'base.html' %}
2
+ {% load static %}
3
+
4
+ {% block title %}Главная - Пластинка{% endblock %}
5
+
6
+ {% block content %}
7
+ <div class="row justify-content-center">
8
+ <div class="col-12 col-lg-10">
9
+ <div id="courseSlider" class="carousel slide" data-bs-ride="carousel">
10
+ <div class="carousel-indicators">
11
+ <button type="button" data-bs-target="#courseSlider" data-bs-slide-to="0" class="active"></button>
12
+ <button type="button" data-bs-target="#courseSlider" data-bs-slide-to="1"></button>
13
+ <button type="button" data-bs-target="#courseSlider" data-bs-slide-to="2"></button>
14
+ <button type="button" data-bs-target="#courseSlider" data-bs-slide-to="3"></button>
15
+ </div>
16
+ <div class="carousel-inner rounded-4">
17
+ <div class="carousel-item active">
18
+ <img src="{% static 'images/slide1.jpg' %}" class="d-block w-100 slider-image" alt="Курсы">
19
+ <div class="carousel-caption">
20
+ <h5>Основы алгоритмизации</h5>
21
+ <p>Научитесь основам программирования</p>
22
+ </div>
23
+ </div>
24
+ <div class="carousel-item">
25
+ <img src="{% static 'images/slide2.jpg' %}" class="d-block w-100 slider-image" alt="Веб-дизайн">
26
+ <div class="carousel-caption">
27
+ <h5>Веб-дизайн</h5>
28
+ <p>Освойте современные веб-интерфейсы</p>
29
+ </div>
30
+ </div>
31
+ <div class="carousel-item">
32
+ <img src="{% static 'images/slide3.jpg' %}" class="d-block w-100 slider-image" alt="Базы данных">
33
+ <div class="carousel-caption">
34
+ <h5>Базы данных</h5>
35
+ <p>Изучите SQL и проектирование БД</p>
36
+ </div>
37
+ </div>
38
+ <div class="carousel-item">
39
+ <img src="{% static 'images/slide4.jpg' %}" class="d-block w-100 slider-image" alt="Документы">
40
+ <div class="carousel-caption">
41
+ <h5>Официальные документы</h5>
42
+ <p>После успешного завершения курсов</p>
43
+ </div>
44
+ </div>
45
+ </div>
46
+ <button class="carousel-control-prev" type="button" data-bs-target="#courseSlider" data-bs-slide="prev">
47
+ <span class="carousel-control-prev-icon"></span>
48
+ </button>
49
+ <button class="carousel-control-next" type="button" data-bs-target="#courseSlider" data-bs-slide="next">
50
+ <span class="carousel-control-next-icon"></span>
51
+ </button>
52
+ </div>
53
+ </div>
54
+ </div>
55
+ {% endblock %}
56
+
57
+ {% block scripts %}
58
+ <script>
59
+ document.addEventListener('DOMContentLoaded', function() {
60
+ var myCarousel = document.getElementById('courseSlider');
61
+ if (myCarousel) {
62
+ new bootstrap.Carousel(myCarousel, {
63
+ interval: 4000,
64
+ wrap: true
65
+ });
66
+ }
67
+ });
68
+ </script>
69
+ {% endblock %}
@@ -0,0 +1,46 @@
1
+ {% extends 'base.html' %}
2
+
3
+ {% block title %}Вход - Пластинка{% endblock %}
4
+
5
+ {% block content %}
6
+ <div class="row justify-content-center min-vh-100 align-items-center">
7
+ <div class="col-md-6 col-lg-5">
8
+ <div class="glass-card p-4 p-md-5">
9
+ <div class="text-center mb-4">
10
+ <div class="display-1 mb-3">🔑</div>
11
+ <h2 class="mb-2">Добро пожаловать</h2>
12
+ <p class="text-secondary">Войди в свой аккаунт</p>
13
+ </div>
14
+
15
+ {% if messages %}
16
+ {% for message in messages %}
17
+ <div class="alert alert-danger">{{ message }}</div>
18
+ {% endfor %}
19
+ {% endif %}
20
+
21
+ <form method="post">
22
+ {% csrf_token %}
23
+ <div class="mb-3">
24
+ <label for="username" class="form-label">Логин</label>
25
+ <input type="text" class="form-control" id="username" name="username" required
26
+ placeholder="Введите логин">
27
+ </div>
28
+ <div class="mb-4">
29
+ <label for="password" class="form-label">Пароль</label>
30
+ <input type="password" class="form-control" id="password" name="password" required
31
+ placeholder="Введите пароль">
32
+ </div>
33
+ <button type="submit" class="btn btn-primary w-100 py-3">
34
+ 🔓 Войти
35
+ </button>
36
+ </form>
37
+
38
+ <div class="text-center mt-4">
39
+ <p class="text-secondary">Нет аккаунта?
40
+ <a href="{% url 'register' %}" class="text-primary">Зарегистрироваться</a>
41
+ </p>
42
+ </div>
43
+ </div>
44
+ </div>
45
+ </div>
46
+ {% endblock %}
@@ -0,0 +1,126 @@
1
+ {% extends 'base.html' %}
2
+
3
+ {% block title %}Регистрация - Пластинка{% endblock %}
4
+ {% block description %}Создайте аккаунт для доступа к онлайн курсам{% endblock %}
5
+
6
+ {% block content %}
7
+ <div class="row justify-content-center min-vh-100 align-items-center">
8
+ <div class="col-md-6 col-lg-5">
9
+ <div class="glass-card p-4 p-md-5">
10
+ <div class="text-center mb-4">
11
+ <div class="display-1 mb-3">✨</div>
12
+ <h2 class="mb-2">Создай аккаунт</h2>
13
+ <p class="text-secondary">Начни своё обучение прямо сейчас</p>
14
+ </div>
15
+
16
+ <form method="post">
17
+ {% csrf_token %}
18
+
19
+ <!-- Логин -->
20
+ <div class="mb-3">
21
+ <label for="{{ form.username.id_for_label }}" class="form-label">Логин</label>
22
+ <input type="text" name="username" class="form-control" id="{{ form.username.id_for_label }}"
23
+ placeholder="Введите логин" required>
24
+ {% if form.username.help_text %}
25
+ <div class="form-text">{{ form.username.help_text }}</div>
26
+ {% endif %}
27
+ {% if form.username.errors %}
28
+ <div class="text-danger small mt-1">{{ form.username.errors.0 }}</div>
29
+ {% endif %}
30
+ </div>
31
+
32
+ <!-- ФИО -->
33
+ <div class="mb-3">
34
+ <label for="{{ form.fio.id_for_label }}" class="form-label">ФИО</label>
35
+ <input type="text" name="fio" class="form-control" id="{{ form.fio.id_for_label }}"
36
+ placeholder="Введите ФИО" required>
37
+ {% if form.fio.help_text %}
38
+ <div class="form-text">{{ form.fio.help_text }}</div>
39
+ {% endif %}
40
+ {% if form.fio.errors %}
41
+ <div class="text-danger small mt-1">{{ form.fio.errors.0 }}</div>
42
+ {% endif %}
43
+ </div>
44
+
45
+ <!-- Телефон -->
46
+ <div class="mb-3">
47
+ <label for="phone-input" class="form-label">Телефон</label>
48
+ <input type="text" name="phone" class="form-control" id="phone-input"
49
+ placeholder="+7(XXX)XXX-XX-XX" required>
50
+ {% if form.phone.help_text %}
51
+ <div class="form-text">{{ form.phone.help_text }}</div>
52
+ {% endif %}
53
+ {% if form.phone.errors %}
54
+ <div class="text-danger small mt-1">{{ form.phone.errors.0 }}</div>
55
+ {% endif %}
56
+ </div>
57
+
58
+ <!-- Email -->
59
+ <div class="mb-3">
60
+ <label for="{{ form.email.id_for_label }}" class="form-label">Email</label>
61
+ <input type="email" name="email" class="form-control" id="{{ form.email.id_for_label }}"
62
+ placeholder="example@mail.com" required>
63
+ {% if form.email.help_text %}
64
+ <div class="form-text">{{ form.email.help_text }}</div>
65
+ {% endif %}
66
+ {% if form.email.errors %}
67
+ <div class="text-danger small mt-1">{{ form.email.errors.0 }}</div>
68
+ {% endif %}
69
+ </div>
70
+
71
+ <!-- Пароль -->
72
+ <div class="mb-3">
73
+ <label for="{{ form.password1.id_for_label }}" class="form-label">Пароль</label>
74
+ <input type="password" name="password1" class="form-control" id="{{ form.password1.id_for_label }}"
75
+ placeholder="Введите пароль" required>
76
+ {% if form.password1.help_text %}
77
+ <div class="form-text">{{ form.password1.help_text }}</div>
78
+ {% endif %}
79
+ {% if form.password1.errors %}
80
+ <div class="text-danger small mt-1">{{ form.password1.errors.0 }}</div>
81
+ {% endif %}
82
+ </div>
83
+
84
+ <!-- Подтверждение пароля -->
85
+ <div class="mb-4">
86
+ <label for="{{ form.password2.id_for_label }}" class="form-label">Подтверждение пароля</label>
87
+ <input type="password" name="password2" class="form-control" id="{{ form.password2.id_for_label }}"
88
+ placeholder="Повторите пароль" required>
89
+ {% if form.password2.help_text %}
90
+ <div class="form-text">{{ form.password2.help_text }}</div>
91
+ {% endif %}
92
+ {% if form.password2.errors %}
93
+ <div class="text-danger small mt-1">{{ form.password2.errors.0 }}</div>
94
+ {% endif %}
95
+ </div>
96
+
97
+ <button type="submit" class="btn btn-primary w-100 py-3">
98
+ ✨ Создать аккаунт
99
+ </button>
100
+ </form>
101
+
102
+ <div class="text-center mt-4">
103
+ <p class="text-secondary">Уже есть аккаунт?
104
+ <a href="{% url 'login' %}" class="text-primary">Войти</a>
105
+ </p>
106
+ </div>
107
+ </div>
108
+ </div>
109
+ </div>
110
+
111
+ <script>
112
+ document.addEventListener('DOMContentLoaded', function() {
113
+ var phoneInput = document.getElementById('phone-input');
114
+ if (phoneInput) {
115
+ phoneInput.addEventListener('input', function(e) {
116
+ let x = e.target.value.replace(/\D/g, '').match(/(\d{0,1})(\d{0,3})(\d{0,3})(\d{0,2})(\d{0,2})/);
117
+ if (x[1]) {
118
+ e.target.value = '+' + x[1] + (x[2] ? '(' + x[2] : '') + (x[3] ? ')' + x[3] : '') + (x[4] ? '-' + x[4] : '') + (x[5] ? '-' + x[5] : '');
119
+ } else {
120
+ e.target.value = '';
121
+ }
122
+ });
123
+ }
124
+ });
125
+ </script>
126
+ {% endblock %}
@@ -0,0 +1,7 @@
1
+ User-agent: *
2
+ Allow: /
3
+
4
+ Sitemap: http://127.0.0.1:8000/sitemap.xml
5
+
6
+ Disallow: /admin/
7
+ Disallow: /logout/
@@ -0,0 +1,33 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
3
+ <url>
4
+ <loc>http://127.0.0.1:8000/</loc>
5
+ <lastmod>{% now "Y-m-d" %}</lastmod>
6
+ <changefreq>daily</changefreq>
7
+ <priority>1.0</priority>
8
+ </url>
9
+ <url>
10
+ <loc>http://127.0.0.1:8000/register/</loc>
11
+ <lastmod>{% now "Y-m-d" %}</lastmod>
12
+ <changefreq>monthly</changefreq>
13
+ <priority>0.8</priority>
14
+ </url>
15
+ <url>
16
+ <loc>http://127.0.0.1:8000/login/</loc>
17
+ <lastmod>{% now "Y-m-d" %}</lastmod>
18
+ <changefreq>monthly</changefreq>
19
+ <priority>0.7</priority>
20
+ </url>
21
+ <url>
22
+ <loc>http://127.0.0.1:8000/applications/</loc>
23
+ <lastmod>{% now "Y-m-d" %}</lastmod>
24
+ <changefreq>weekly</changefreq>
25
+ <priority>0.6</priority>
26
+ </url>
27
+ <url>
28
+ <loc>http://127.0.0.1:8000/applications/create/</loc>
29
+ <lastmod>{% now "Y-m-d" %}</lastmod>
30
+ <changefreq>weekly</changefreq>
31
+ <priority>0.6</priority>
32
+ </url>
33
+ </urlset>
@@ -0,0 +1,17 @@
1
+ from django.contrib import admin
2
+ from django.urls import path
3
+ from django.contrib.auth import views as auth_views
4
+ from main import views
5
+
6
+ urlpatterns = [
7
+ path('admin/', admin.site.urls),
8
+ path('', views.home, name='home'), # Это главная страница
9
+ path('register/', views.register, name='register'),
10
+ path('login/', views.custom_login, name='login'),
11
+ path('logout/', views.custom_logout, name='logout'),
12
+ path('applications/', views.applications, name='applications'),
13
+ path('applications/create/', views.create_application, name='create_application'),
14
+ path('applications/<int:application_id>/review/', views.add_review, name='add_review'),
15
+ path('sitemap.xml', views.sitemap_xml, name='sitemap'),
16
+ path('robots.txt', views.robots_txt, name='robots_txt'),
17
+ ]
@@ -0,0 +1,16 @@
1
+ """
2
+ WSGI config for kurochki project.
3
+
4
+ It exposes the WSGI callable as a module-level variable named ``application``.
5
+
6
+ For more information on this file, see
7
+ https://docs.djangoproject.com/en/6.0/howto/deployment/wsgi/
8
+ """
9
+
10
+ import os
11
+
12
+ from django.core.wsgi import get_wsgi_application
13
+
14
+ os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'kurochki.settings')
15
+
16
+ application = get_wsgi_application()
File without changes
@@ -0,0 +1,7 @@
1
+ from django.contrib import admin
2
+ from .models import CustomUser, Application, Review
3
+
4
+
5
+ admin.site.register(CustomUser)
6
+ admin.site.register(Application)
7
+ admin.site.register(Review)
@@ -0,0 +1,5 @@
1
+ from django.apps import AppConfig
2
+
3
+
4
+ class MainConfig(AppConfig):
5
+ name = 'main'