django-hero-gen 1.0.1 → 1.1.1

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.
package/README.md ADDED
@@ -0,0 +1,119 @@
1
+ # 🦸‍♂️ Django Hero Gen
2
+
3
+ **Django Hero Gen** — это мощный CLI-инструмент для мгновенного развертывания фронтенда и базовой логики Django-приложений. Больше не нужно вручную копировать Bootstrap-шаблоны, настраивать Navbar или переписывать стандартные View для авторизации. Сделайте это одной командой и сэкономьте часы рутины.
4
+
5
+ ---
6
+
7
+ ## 🚀 Быстрый старт
8
+
9
+ ### Установка
10
+
11
+ Установите пакет глобально, чтобы команда `dj-gen` была доступна в любом месте:
12
+
13
+ ```bash
14
+ npm install -g django-hero-gen
15
+
16
+ ```
17
+
18
+ Или используйте без установки через `npx`:
19
+
20
+ ```bash
21
+ npx django-hero-gen <команда>
22
+
23
+ ```
24
+
25
+ ### Полная инициализация проекта
26
+
27
+ Самый быстрый способ наполнить новое Django-приложение контентом. Создает все необходимые файлы одним махом:
28
+
29
+ ```bash
30
+ dj-gen init
31
+
32
+ ```
33
+
34
+ > **Что будет создано:** `base.html`, `home.html`, `create_course.html`, `my_course.html`, `views.py`, `order_views.py`, `admin.py`.
35
+
36
+ ---
37
+
38
+ ## 🛠 Доступные команды
39
+
40
+ ### 1. Генерация шаблонов (HTML + Bootstrap 5)
41
+
42
+ Все шаблоны поддерживают наследование и адаптированы под мобильные устройства.
43
+
44
+ | Команда | Файл | Описание |
45
+ | ------------- | -------------------- | ----------------------------------------------------------------------------------------------- |
46
+ | `dj-gen base` | `base.html` | **Фундамент:** Navbar с логикой Auth, Footer, системные уведомления и подключенный Bootstrap 5. |
47
+ | `dj-gen home` | `home.html` | **Главная:** Слайдер (Carousel) с поддержкой static и информационный блок. |
48
+ | `dj-gen form` | `create_course.html` | **Формы:** Готовая разметка для рендеринга Django-форм через Bootstrap. |
49
+ | `dj-gen list` | `my_course.html` | **Личный кабинет:** Список карточек с индикаторами статуса и встроенными модальными окнами. |
50
+
51
+ ---
52
+
53
+ ### 2. Генерация логики (Python)
54
+
55
+ Готовые обработчики для типовых задач Django.
56
+
57
+ - **`dj-gen auth`** — Создает `views.py`. Включает:
58
+ - `registration_view` (с использованием CustomUserCreationForm).
59
+ - `login_view` и `logout_view`.
60
+ - `accept_cookies` (обработка согласия пользователя через Cookies).
61
+
62
+ - **`dj-gen orders`** — Создает `order_views.py`. Чистый файл для вашей бизнес-логики заказов или курсов.
63
+ - **`dj-gen admin`** — Создает `admin.py`. Базовый импорт и место для регистрации ваших моделей.
64
+
65
+ ---
66
+
67
+ ## 📁 Структура создаваемых файлов
68
+
69
+ После выполнения команды `dj-gen init` структура вашего приложения примет следующий вид:
70
+
71
+ ```text
72
+ your_app/
73
+ ├─ templates/
74
+ │ ├─ base.html # Базовый скелет сайта
75
+ │ ├─ home.html # Главная страница (extends base.html)
76
+ │ ├─ create_course.html # Страница создания (extends base.html)
77
+ │ └─ my_course.html # Список объектов (extends base.html)
78
+ ├─ views.py # Логика пользователей и аутентификации
79
+ ├─ order_views.py # Логика обработки бизнес-задач
80
+ └─ admin.py # Регистрация моделей в панели управления
81
+
82
+ ```
83
+
84
+ ---
85
+
86
+ ## ⚙️ Важные настройки после генерации
87
+
88
+ Для корректной работы созданных файлов выполните следующие шаги:
89
+
90
+ 1. **Настройка путей:** Убедитесь, что в `settings.py` в секции `TEMPLATES` указана папка с вашими шаблонами.
91
+ 2. **Зависимости:** Установите библиотеку для работы с формами:
92
+
93
+ ```bash
94
+ pip install django-bootstrap5
95
+
96
+ ```
97
+
98
+ И добавьте `'django_bootstrap5'` в `INSTALLED_APPS`. 3. **Маршрутизация:** Подключите созданные функции в вашем `urls.py`:
99
+
100
+ ```python
101
+ from . import views, order_views
102
+
103
+ urlpatterns = [
104
+ path('', views.home_view, name='home'),
105
+ path('login/', views.login_view, name='login'),
106
+ # и так далее...
107
+ ]
108
+
109
+ ```
110
+
111
+ ---
112
+
113
+ ## 📜 Лицензия
114
+
115
+ Распространяется под лицензией **MIT**. Свободно для использования в коммерческих и личных проектах.
116
+
117
+ ---
118
+
119
+ **Удачной разработки!**
package/index.js CHANGED
@@ -1,58 +1,43 @@
1
1
  #!/usr/bin/env node
2
+ const cmds = require("./src/commands");
3
+ const [, , command] = process.argv;
2
4
 
3
- const fs = require("fs");
4
- const path = require("path");
5
+ const actions = {
6
+ // Базовые шаблоны
7
+ base: cmds.makeBase,
8
+ home: cmds.makeHome,
5
9
 
6
- const [, , command, name] = process.argv;
10
+ // Страницы курсов/заявок
11
+ form: cmds.makeCreatePage, // создание (бывш. create)
12
+ list: cmds.makeListPage, // список (бывш. list)
7
13
 
8
- if (command === "admin") {
9
- const filePath = path.join(process.cwd(), "admin.py");
10
- const template = `from django.contrib import admin\n\n# Register your models here.`;
11
- fs.writeFileSync(filePath, template);
12
- console.log(`✅ Файл admin.py успешно создан!`);
13
- process.exit(0);
14
- }
14
+ // Логика (Python)
15
+ auth: cmds.makeAuth, // вьюхи логина/регистрации
16
+ orders: cmds.makeOrders, // Теперь эта команда будет работать
17
+ admin: cmds.makeAdmin,
18
+
19
+ // Полная сборка
20
+ init: cmds.initFull,
21
+ };
15
22
 
16
- if (!name) {
23
+ if (actions[command]) {
24
+ actions[command]();
25
+ } else {
17
26
  console.log(`
18
- Использование:
19
- dj-gen page <name> - Создать HTML шаблон
20
- dj-gen view <name> - Создать Django View
21
- dj-gen admin - Создать файл admin.py
22
- `);
23
- process.exit(1);
24
- }
27
+ 🛠️ Django-Hero CLI (v1.1.0)
25
28
 
26
- const templates = {
27
- base: `<!DOCTYPE html>
28
- <html>
29
- <head>
30
- <title>{% block title %}Django App{% endblock %}</title>
31
- </head>
32
- <body>
33
- {% block content %}{% endblock %}
34
- </body>
35
- </html>`,
36
- view: `from django.views.generic import TemplateView
37
-
38
- class ${name}View(TemplateView):
39
- template_name = "${name.toLowerCase()}.html"`,
40
- };
29
+ Команды для HTML:
30
+ dj-gen base - Каркас base.html (Bootstrap + Navbar)
31
+ dj-gen home - Главная home.html (Карусель + Инфо)
32
+ dj-gen form - Страница создания заявки (create_course.html)
33
+ dj-gen list - Список заявок с модалками (my_course.html)
41
34
 
42
- if (command === "page") {
43
- const fileName = `${name}.html`;
44
- const filePath = path.join(process.cwd(), fileName);
45
-
46
- if (fs.existsSync(filePath)) {
47
- console.log(`❌ Ошибка: Файл ${fileName} уже существует!`);
48
- } else {
49
- fs.writeFileSync(filePath, templates.base);
50
- console.log(`✅ Создан HTML шаблон: ${fileName}`);
51
- }
52
- } else if (command === "view") {
53
- const fileName = `${name.toLowerCase()}_view.py`;
54
- const filePath = path.join(process.cwd(), fileName);
55
-
56
- fs.writeFileSync(filePath, templates.view);
57
- console.log(`✅ Создана View: ${fileName}`);
35
+ Команды для Python:
36
+ dj-gen auth - views.py (Логика входа, регистрации и Cookies)
37
+ dj-gen orders - order_views.py (Логика управления курсами)
38
+ dj-gen admin - Стандартный admin.py
39
+
40
+ Глобальные команды:
41
+ dj-gen init - [!] Развернуть ВСЕ файлы проекта сразу
42
+ `);
58
43
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "django-hero-gen",
3
- "version": "1.0.1",
3
+ "version": "1.1.1",
4
4
  "description": "Генератор шаблонов для Django",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -0,0 +1,49 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+
4
+ const baseTpl = require("./templates/base");
5
+ const homeTpl = require("./templates/home");
6
+ const createCourseTpl = require("./templates/create_course");
7
+ const myCourseTpl = require("./templates/my_course");
8
+ const authViewsTpl = require("./view/auth_view");
9
+ const orderViewsTpl = require("./view/order_view");
10
+
11
+ const saveFile = (fileName, content) => {
12
+ const filePath = path.join(process.cwd(), fileName);
13
+ if (fs.existsSync(filePath)) {
14
+ console.log(`⚠️ Пропуск: ${fileName} (уже существует)`);
15
+ } else {
16
+ fs.writeFileSync(filePath, content);
17
+ console.log(`✅ Создан: ${fileName}`);
18
+ }
19
+ };
20
+
21
+ const makeAll = () => {
22
+ console.log("🚀 Развертывание полного проекта...");
23
+ saveFile("base.html", baseTpl());
24
+ saveFile("home.html", homeTpl());
25
+ saveFile("create_course.html", createCourseTpl());
26
+ saveFile("my_course.html", myCourseTpl());
27
+ saveFile("views.py", authViewsTpl());
28
+ saveFile("order_views.py", orderViewsTpl());
29
+ saveFile(
30
+ "admin.py",
31
+ `from django.contrib import admin\n\n# Register your models here.`
32
+ );
33
+ console.log("✨ Готово! Не забудь настроить urls.py.");
34
+ };
35
+
36
+ module.exports = {
37
+ makeBase: () => saveFile("base.html", baseTpl()),
38
+ makeHome: () => saveFile("home.html", homeTpl()),
39
+ makeCreatePage: () => saveFile("create_course.html", createCourseTpl()),
40
+ makeListPage: () => saveFile("my_course.html", myCourseTpl()),
41
+ makeAuth: () => saveFile("views.py", authViewsTpl()),
42
+ makeOrders: () => saveFile("order_views.py", orderViewsTpl()),
43
+ makeAdmin: () =>
44
+ saveFile(
45
+ "admin.py",
46
+ `from django.contrib import admin\n\n# Register your models here.`
47
+ ),
48
+ initFull: makeAll,
49
+ };
@@ -0,0 +1,93 @@
1
+ module.exports = () => `{% load bootstrap5 %} {% load static %}
2
+ <!DOCTYPE html>
3
+ <html lang="en">
4
+ <head>
5
+ <meta charset="UTF-8" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>{% block title %}Django App{% endblock %}</title>
8
+ {% bootstrap_css %} {% bootstrap_javascript %}
9
+ </head>
10
+ <body class="d-flex flex-column min-vh-100">
11
+ <header>
12
+ <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
13
+ <div class="container-fluid">
14
+ <a class="navbar-brand" href="#">
15
+ <img
16
+ src="{% static 'photo/logo.png' %}"
17
+ alt="Логотип"
18
+ width="44"
19
+ height="40"
20
+ class="d-inline-block align-text-top rounded-circle"
21
+ />
22
+ </a>
23
+ <button
24
+ class="navbar-toggler"
25
+ type="button"
26
+ data-bs-toggle="collapse"
27
+ data-bs-target="#navbarNavAltMarkup"
28
+ aria-controls="navbarNavAltMarkup"
29
+ aria-expanded="false"
30
+ aria-label="Toggle navigation"
31
+ >
32
+ <span class="navbar-toggler-icon"></span>
33
+ </button>
34
+
35
+ <div class="collapse navbar-collapse" id="navbarNavAltMarkup">
36
+ <div class="navbar-nav">
37
+ <a
38
+ class="nav-link {% if request.resolver_match.url_name == 'home' %}active{% endif %}"
39
+ href="{% url 'home' %}"
40
+ >
41
+ Главная
42
+ </a>
43
+
44
+ {% if user.is_authenticated %}
45
+ <a
46
+ class="nav-link {% if request.resolver_match.url_name == 'my_course' %}active{% endif %}"
47
+ href="{% url 'my_course' %}"
48
+ >
49
+ Посмотреть мои заявки
50
+ </a>
51
+
52
+ <a
53
+ class="nav-link {% if request.resolver_match.url_name == 'create_course' %}active{% endif %}"
54
+ href="{% url 'create_course' %}"
55
+ >
56
+ Создать заявку
57
+ </a>
58
+ {% endif %}
59
+ </div>
60
+
61
+ <div class="navbar-nav ms-auto">
62
+ {% if user.is_authenticated %}
63
+ <a class="nav-link" href="{% url 'logout' %}">Выйти</a>
64
+ {% else %}
65
+ <a class="nav-link" href="{% url 'login' %}">Войти</a>
66
+ <a class="nav-link" href="{% url 'registration' %}"
67
+ >Регистрация</a
68
+ >
69
+ {% endif %}
70
+ </div>
71
+ </div>
72
+ </div>
73
+ </nav>
74
+ </header>
75
+ <main class="container flex-grow-1">
76
+ {% block content %} {% endblock content %}
77
+ </main>
78
+ <footer class="bg-dark text-light text-center py-3 mt-auto">
79
+ сайт © {{ year|default:2026 }}
80
+ </footer>
81
+ {% if not request.COOKIES.cookies_accepted %}
82
+ <div
83
+ class="position-fixed bottom-0 start-0 end-0 bg-dark text-white p-3 text-center"
84
+ style="z-index: 999"
85
+ >
86
+ Мы используем cookies для улучшения работы сайта.
87
+ <a href="{% url 'accept_cookies' %}" class="btn btn-sm btn-light ms-2"
88
+ >Принять</a
89
+ >
90
+ </div>
91
+ {% endif %}
92
+ </body>
93
+ </html>`;
@@ -0,0 +1,21 @@
1
+ module.exports = () => `
2
+ {% extends "base.html" %}
3
+ {% load bootstrap5 %}
4
+
5
+
6
+ {% block content %}
7
+
8
+ <div class="container mt-4">
9
+
10
+ <h2>Создание заявки</h2>
11
+
12
+ <form method="post">
13
+ {% csrf_token %}
14
+ {% bootstrap_form form %}
15
+ <button type="submit" class="btn btn-primary">Отправить заявку</button>
16
+ </form>
17
+
18
+ </div>
19
+
20
+ {% endblock content %}
21
+ `;
@@ -0,0 +1,73 @@
1
+ module.exports = () => `{% extends "base.html" %}
2
+ {% load bootstrap5 %}{% load static %}
3
+ {% block content %}
4
+ <style>
5
+ .carousel-control-prev-icon,
6
+ .carousel-control-next-icon {
7
+ filter: invert(1);
8
+ width: 2rem;
9
+ height: 2rem;
10
+ }
11
+ </style>
12
+ {% bootstrap_css %} {% bootstrap_javascript %}
13
+
14
+ <div id="carouselExampleAutoplaying" class="carousel slide py-5 mb-5" data-bs-ride="carousel">
15
+ <div class="carousel-inner">
16
+ <div class="carousel-item active">
17
+ <img src="{% static 'photo/logo.png' %}" class="d-block w-100" alt="Слайд 1">
18
+ </div>
19
+ <div class="carousel-item">
20
+ <img src="{% static 'photo/image13.webp' %}" class="d-block w-100" alt="Слайд 2">
21
+ </div>
22
+ <div class="carousel-item">
23
+ <img src="{% static 'photo/logo.png' %}" class="d-block w-100" alt="Слайд 3">
24
+ </div>
25
+ </div>
26
+
27
+ <button class="carousel-control-prev" type="button" data-bs-target="#carouselExampleAutoplaying" data-bs-slide="prev">
28
+ <span class="carousel-control-prev-icon" aria-hidden="true"></span>
29
+ <span class="visually-hidden">Предыдущий</span>
30
+ </button>
31
+ <button class="carousel-control-next" type="button" data-bs-target="#carouselExampleAutoplaying" data-bs-slide="next">
32
+ <span class="carousel-control-next-icon" aria-hidden="true"></span>
33
+ <span class="visually-hidden">Следующий</span>
34
+ </button>
35
+ </div>
36
+
37
+ <div class="py-5">
38
+ <div class="container">
39
+ <h1 class="text-center mb-4">Добро пожаловать на портал «Корочки.есть»</h1>
40
+
41
+ <div class="row justify-content-center">
42
+ <div class="col-md-10 col-lg-8">
43
+ <div class="card shadow-sm p-4 border-0">
44
+ <p>
45
+ Портал <strong>«Корочки.есть»</strong> — это система для записи на онлайн-курсы
46
+ дополнительного профессионального образования.
47
+ </p>
48
+
49
+ <p>
50
+ Чтобы воспользоваться сервисом, необходимо пройти регистрацию.
51
+ После входа в систему пользователь может подать заявку, указав:
52
+ </p>
53
+
54
+ <ul>
55
+ <li>наименование курса</li>
56
+ <li>дату начала обучения</li>
57
+ <li>способ оплаты</li>
58
+ </ul>
59
+
60
+ <p>
61
+ Все заявки отправляются администратору на проверку. Он может изменить их статус.
62
+ </p>
63
+
64
+ <p class="mb-0">
65
+ С помощью портала процесс записи становится удобным и понятным.
66
+ </p>
67
+ </div>
68
+ </div>
69
+ </div>
70
+ </div>
71
+ </div>
72
+
73
+ {% endblock content %}`;
@@ -0,0 +1,99 @@
1
+ module.exports = () => `
2
+ {% extends "base.html" %} {% load bootstrap5 %} {% block content %}
3
+ <div class="container my-5">
4
+ <div class="row">
5
+ {% for order in course %}
6
+ <div class="col-md-6 col-lg-4 mb-4">
7
+ <div class="card h-100">
8
+ <div class="card-header">
9
+ <h5 class="card-title mb-0">{{ order.get_course_display }}</h5>
10
+ </div>
11
+ <div class="card-body">
12
+ <p class="text-muted"><small>Дата: {{ order.date }}</small></p>
13
+ {% if order.review_text %}
14
+ <p><strong>Ваш отзыв:</strong> {{ order.review_text }}</p>
15
+ {% endif %}
16
+ </div>
17
+ <div class="card-footer">
18
+ <span class="badge bg-secondary">{{ order.get_status_display }}</span>
19
+
20
+ {% if order.status == 'completed' %}
21
+ <button
22
+ type="button"
23
+ class="btn btn-sm btn-outline-primary float-end"
24
+ data-bs-toggle="modal"
25
+ data-bs-target="#reviewModal{{ order.id }}"
26
+ >
27
+ Оставить отзыв
28
+ </button>
29
+ {% endif %}
30
+ </div>
31
+ </div>
32
+ </div>
33
+
34
+ <div
35
+ class="modal fade"
36
+ id="reviewModal{{ order.id }}"
37
+ tabindex="-1"
38
+ aria-hidden="true"
39
+ >
40
+ <div class="modal-dialog modal-dialog-centered">
41
+ <div class="modal-content">
42
+ <form method="post" action="{% url 'add_review' order.id %}">
43
+ {% csrf_token %}
44
+ <div class="modal-header">
45
+ <h5 class="modal-title">Оставить отзыв о курсе</h5>
46
+ <button
47
+ type="button"
48
+ class="btn-close"
49
+ data-bs-dismiss="modal"
50
+ ></button>
51
+ </div>
52
+ <div class="modal-body">
53
+ <textarea
54
+ name="review_text"
55
+ class="form-control"
56
+ rows="4"
57
+ placeholder="Напишите ваш отзыв..."
58
+ {%
59
+ if
60
+ order.review_text
61
+ %}readonly{%
62
+ endif
63
+ %}
64
+ >
65
+ {{ order.review_text }}</textarea
66
+ >
67
+ </div>
68
+ <div class="modal-footer">
69
+ <button
70
+ type="button"
71
+ class="btn btn-secondary"
72
+ data-bs-dismiss="modal"
73
+ >
74
+ Закрыть
75
+ </button>
76
+
77
+ {% if not order.review_text %}
78
+ <button type="submit" class="btn btn-primary">Отправить</button>
79
+ {% else %}
80
+ <button type="button" class="btn btn-success" disabled>
81
+ Отзыв уже оставлен
82
+ </button>
83
+ {% endif %}
84
+ </div>
85
+ </form>
86
+ </div>
87
+ </div>
88
+ </div>
89
+
90
+ {% empty %}
91
+ <div class="col-12">
92
+ <div class="alert alert-info">У вас пока нет заявок</div>
93
+ </div>
94
+ {% endfor %}
95
+ </div>
96
+ </div>
97
+ {% endblock %}
98
+
99
+ `;
@@ -0,0 +1,54 @@
1
+ module.exports = () => `
2
+ # view авторизации
3
+
4
+ from django.shortcuts import render,redirect
5
+ from django.contrib.auth import login
6
+ from django.contrib.auth.forms import AuthenticationForm
7
+
8
+ from accounts.forms import CustomUserCreatioForm
9
+
10
+ def home_view(request):
11
+ return render(request,'home.html')
12
+
13
+
14
+ def registration_vew(request):
15
+ if request.method == 'POST':
16
+ form = CustomUserCreatioForm(request.POST)
17
+ if form.is_valid():
18
+ user = form.save()
19
+ login(request,user)
20
+ return redirect('home')
21
+ else:
22
+ form = CustomUserCreatioForm()
23
+
24
+ return render(request,'auth/registration.html',{'form':form})
25
+
26
+
27
+
28
+
29
+
30
+ def login_view(request):
31
+
32
+ if request.method == 'POST':
33
+ form = AuthenticationForm(request, data = request.POST)
34
+ if form.is_valid():
35
+ user= form.get_user()
36
+ login(request,user)
37
+ return redirect('home')
38
+
39
+ else:
40
+ form = AuthenticationForm()
41
+
42
+ return render(request,'auth/login.html',{'form':form})
43
+
44
+
45
+
46
+ from django.shortcuts import redirect
47
+
48
+ def accept_cookies(request):
49
+ response = redirect(request.META.get('HTTP_REFERER', 'home'))
50
+ response.set_cookie('cookies_accepted', 'yes', max_age=60*60*24*365)
51
+ return response
52
+
53
+
54
+ `;
@@ -0,0 +1,40 @@
1
+ module.exports = () => `
2
+ # view курсов
3
+
4
+ from django.shortcuts import render,redirect
5
+ from orders.forms import OrdersForm
6
+ from .models import Orders
7
+ from django.contrib.auth.decorators import login_required
8
+ from django.views.decorators.http import require_POST
9
+
10
+ @login_required
11
+ def create_order_view(request):
12
+ if request.method == 'POST':
13
+ form = OrdersForm(request.POST)
14
+ if form.is_valid():
15
+ course = form.save(commit=False)
16
+ course.user = request.user
17
+ course.save()
18
+ return redirect('my_course')
19
+ else:
20
+ form = OrdersForm()
21
+ return render (request,'orders/createOrders.html',{'form':form})
22
+
23
+
24
+
25
+ def all_order_view(request):
26
+ course = Orders.objects.filter(user=request.user)
27
+ return render (request,'orders/listOrders.html',{'course':course})
28
+
29
+
30
+ @require_POST
31
+ def add_review(request, order_id):
32
+ order = Orders.objects.get(id=order_id, user=request.user)
33
+ review_text = request.POST.get('review', '').strip()
34
+ if review_text:
35
+ order.review_text = review_text
36
+ order.save()
37
+ return redirect('my_course')
38
+
39
+
40
+ `;