feat(djinit/templates): migrate templates to double-bracket placeholder syntax

New Features
- Adopt double-bracket placeholders (`[[ var ]]`) and rename templates to `.py-tpl`/.`md-tpl` extensions.
- Introduce new `runtime_txt-tpl` template.

Enhancements
- Update `api_readme`, `models`, `apps`, `routes`, `pyproject`, `readme`, and `requirements` templates with new syntax and naming.
- Align placeholder naming with a unified convention.

Bug Fixes
- None.
This commit is contained in:
sankalp committed 2026-01-31 01:39:11 +05:45
1 parent bc23b02007
commit 0fde5c7aa8
65 files changed
+378 -292

No files matched your search

@@ -24,7 +24,7 @@ If you have a `User` model in `models/user.py`, create:
### 1. `api/user/serializers.py`
```python
from rest_framework import serializers
from {{ module_name }}.models.user import User
from [[ module_name ]].models.user import User
class UserSerializer(serializers.ModelSerializer):
class Meta:
@@ -35,7 +35,7 @@ class UserSerializer(serializers.ModelSerializer):
### 2. `api/user/views.py`
```python
from rest_framework import viewsets
from {{ module_name }}.models.user import User
from [[ module_name ]].models.user import User
from .serializers import UserSerializer
class UserViewSet(viewsets.ModelViewSet):
@@ -62,7 +62,7 @@ urlpatterns = [
from django.urls import path, include
urlpatterns = [
path('user/', include('{{ module_name }}.api.user.urls')),
path('user/', include('[[ module_name ]].api.user.urls')),
# Add more API endpoints here
]
```
-8
View File
@@ -1,8 +0,0 @@
"""generated with djinit"""
from django.apps import AppConfig
class {{ app_name|title }}Config(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = '{{ app_name }}'
+6
View File
@@ -0,0 +1,6 @@
from django.apps import AppConfig
class [[ app_name|title ]]Config(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = '[[ app_name ]]'
@@ -1,5 +1,3 @@
"""generated with djinit"""
from django.db import models
# Create your models here.
@@ -69,7 +69,7 @@ Create or update `admin/__init__.py`:
```python
from django.contrib import admin
from {{ module_name }}.models import User
from [[ module_name ]].models import User
@admin.register(User)
class UserAdmin(admin.ModelAdmin):
-18
View File
@@ -1,18 +0,0 @@
"""
generated with djinit
API routes for {{ app_name }} app.
"""
from rest_framework.routers import DefaultRouter
from . import views
# Create router instance
router = DefaultRouter()
# Register viewsets with router
# Example:
# router.register(r'{{ app_name }}', views.{{ app_name|title }}ViewSet)
# Get URL patterns
urlpatterns = router.urls
@@ -0,0 +1,8 @@
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
# Register your viewsets here
# router.register(r'endpoint', YourViewSet, basename='your-endpoint')
urlpatterns = router.urls
@@ -1,14 +0,0 @@
"""
generated with djinit
serializers for {{ app_name }} app.
"""
from rest_framework import serializers
# Add your serializers here
# Example:
# class {{ app_name|title }}Serializer(serializers.ModelSerializer):
# class Meta:
# model = YourModel
# fields = '__all__'
@@ -0,0 +1,3 @@
from rest_framework import serializers
# Create your serializers here.
@@ -1,5 +1,3 @@
"""generated with djinit"""
from django.test import TestCase
# Create your tests here.
-11
View File
@@ -1,11 +0,0 @@
"""generated with djinit"""
from django.urls import path
from . import views
app_name = '{{ app_name }}'
urlpatterns = [
# Add your URL patterns here
# path('', views.index, name='index'),
]
@@ -1,5 +1,3 @@
"""generated with djinit"""
from django.shortcuts import render
# Create your views here.
@@ -7,5 +7,5 @@ from django.core.asgi import get_asgi_application
env = environ.Env()
environ.Env.read_env()
os.environ.setdefault("DJANGO_SETTINGS_MODULE", env("DJANGO_SETTINGS_MODULE", default="{{ project_name }}.settings.production"))
os.environ.setdefault("DJANGO_SETTINGS_MODULE", env("DJANGO_SETTINGS_MODULE", default="[[ project_name ]].settings.production"))
application = get_asgi_application()
@@ -29,8 +29,9 @@ THIRD_PARTY_APPS = [
]
USER_DEFINED_APPS = [
{% for app in app_names %} "{{ app }}",
{% endfor %}]
# @LOOP app in app_names "[[ app ]]",
# @ENDLOOP
]
BUILT_IN_APPS = [
"django.contrib.admin",
@@ -56,7 +57,7 @@ MIDDLEWARE = [
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
ROOT_URLCONF = "{{ project_name }}.urls"
ROOT_URLCONF = "[[ project_name ]].urls"
TEMPLATES = [
{
@@ -73,7 +74,7 @@ TEMPLATES = [
},
]
WSGI_APPLICATION = "{{ project_name }}.wsgi.application"
WSGI_APPLICATION = "[[ project_name ]].wsgi.application"
# Password validation
@@ -133,8 +134,8 @@ REST_FRAMEWORK = {
# DRF Spectacular settings
SPECTACULAR_SETTINGS = {
"TITLE": "{{ project_name }} API",
"DESCRIPTION": "API documentation for {{ project_name }}",
"TITLE": "[[ project_name ]] API",
"DESCRIPTION": "API documentation for [[ project_name ]]",
"VERSION": "1.0.0",
"SERVE_INCLUDE_SCHEMA": False,
"COMPONENT_SPLIT_REQUEST": True,
@@ -2,7 +2,7 @@
from .base import *
SECRET_KEY = "{{ secret_key }}"
SECRET_KEY = "[[ secret_key ]]"
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
@@ -8,29 +8,29 @@ SECRET_KEY = env('SECRET_KEY')
ALLOWED_HOSTS = env.list('ALLOWED_HOSTS', default=[])
# Database
{% if use_database_url %}
# @IF use_database_url
# Using dj_database_url (recommended for production)
DATABASES = {
'default': env.db('DATABASE_URL')
}
{% else %}
# @ELSE
# Using individual database parameters
DATABASES = {
'default': {
{% if database_type == 'mysql' %}
# @IF database_type == 'mysql'
'ENGINE': 'django.db.backends.mysql',
'PORT': env('DB_PORT', default='3306'),
{% else %}
# @ELSE
'ENGINE': 'django.db.backends.postgresql',
'PORT': env('DB_PORT', default='5432'),
{% endif %}
# @ENDIF
'NAME': env('DB_NAME'),
'USER': env('DB_USER'),
'PASSWORD': env('DB_PASSWORD'),
'HOST': env('DB_HOST'),
}
}
{% endif %}
# @ENDIF
# CORS settings for production
# Filter out empty strings from FRONTEND_URL
+103
View File
@@ -0,0 +1,103 @@
# @IF url_type == 'project'
"""generated with djinit"""
from django.contrib import admin
from django.urls import path
# @IF include_api or include_apps
from django.urls import include
# @ENDIF
# @IF include_api
from django.conf import settings
from drf_spectacular.views import (
SpectacularAPIView,
SpectacularSwaggerView,
)
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
TokenBlacklistView,
)
# @ENDIF
urlpatterns = [
path("admin/", admin.site.urls),
# @IF include_api
# JWT tokens
path("token/", TokenObtainPairView.as_view(), name="token_obtain_pair"),
path("token/refresh/", TokenRefreshView.as_view(), name="token_refresh"),
path("token/blacklist/", TokenBlacklistView.as_view(), name="token_blacklist"),
# @ENDIF
# @IF include_api and comment_out_api_url
# path("api/", include("[[ api_module ]].urls")),
# @ENDIF
# @IF include_api and not comment_out_api_url
path("api/", include("[[ api_module ]].urls")),
# @ENDIF
# @IF include_apps
# App URLs
# @LOOP app in app_names
path("", include("[[ app ]].urls")),
# @ENDLOOP
# @ENDIF
]
# @IF include_api
# Don't show schema in production
if settings.DEBUG:
urlpatterns += [
path("schema/", SpectacularAPIView.as_view(), name="schema"),
path("docs/", SpectacularSwaggerView.as_view(url_name="schema")),
]
# @ENDIF
# @ENDIF
# @IF url_type == 'api_root'
from django.urls import include, path
app_name = "[[ app_name ]]"
urlpatterns = [
path("[[ version ]]/", include("[[ api_module ]].[[ version ]].urls")),
]
# @ENDIF
# @IF url_type == 'api_version'
from django.urls import include, path
app_name = "[[ app_name ]]"
urlpatterns = [
# @LOOP app in app_list
path("[[ app ]]/", include("[[ app_module ]].[[ app ]].urls")),
# @ENDLOOP
]
# @ENDIF
# @IF url_type == 'drf_router'
from rest_framework.routers import DefaultRouter
# @IF has_viewset
from [[ app_module ]].views.[[ view_file ]] import [[ viewset_name ]]
# @ENDIF
# @IF has_app_name
app_name = "[[ app_name ]]"
# @ENDIF
router = DefaultRouter()
# @IF has_viewset
router.register(r"[[ router_prefix ]]", [[ viewset_name ]], basename="[[ basename ]]")
# @ENDIF
urlpatterns = [
# @IF has_include
path("", include(router.urls)),
# @ENDIF
]
# @IF not has_include
urlpatterns = router.urls
# @ENDIF
# @ENDIF
# @IF url_type == 'component'
from django.urls import path
urlpatterns = [
# Add your URL patterns here
]
# @ENDIF
-8
View File
@@ -1,8 +0,0 @@
"""generated with djinit"""
from django.contrib import admin
from django.urls import path
urlpatterns = [
path('admin/', admin.site.urls),
]
-30
View File
@@ -1,30 +0,0 @@
"""generated with djinit"""
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from drf_spectacular.views import (
SpectacularAPIView,
SpectacularSwaggerView,
)
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
TokenBlacklistView,
)
urlpatterns = [
path("admin/", admin.site.urls),
# JWT tokens
path("token/", TokenObtainPairView.as_view(), name="token_obtain_pair"),
path("token/refresh/", TokenRefreshView.as_view(), name="token_refresh"),
path("token/blacklist/", TokenBlacklistView.as_view(), name="token_blacklist"),
{% if comment_out_api_url %}# {% endif %}path("api/", include("{{ api_module }}.urls")),
]
# Don't show schema in production
if settings.DEBUG:
urlpatterns += [
path("schema/", SpectacularAPIView.as_view(), name="schema"),
path("docs/", SpectacularSwaggerView.as_view(url_name="schema")),
]
-31
View File
@@ -1,31 +0,0 @@
"""generated with djinit"""
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from drf_spectacular.views import (
SpectacularAPIView,
SpectacularSwaggerView,
)
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
TokenBlacklistView,
)
urlpatterns = [
path("admin/", admin.site.urls),
# JWT tokens
path("token/", TokenObtainPairView.as_view(), name="token_obtain_pair"),
path("token/refresh/", TokenRefreshView.as_view(), name="token_refresh"),
path("token/blacklist/", TokenBlacklistView.as_view(), name="token_blacklist"),
# App URLs
{% if comment_out_api_url %}# {% endif %} {% for app in app_names %} path("", include("{{ app }}.urls")),
{% endfor %}]
# Don't show schema in production
if settings.DEBUG:
urlpatterns += [
path("schema/", SpectacularAPIView.as_view(), name="schema"),
path("docs/", SpectacularSwaggerView.as_view(url_name="schema")),
]
@@ -7,6 +7,6 @@ from django.core.wsgi import get_wsgi_application
env = environ.Env()
environ.Env.read_env()
os.environ.setdefault("DJANGO_SETTINGS_MODULE", env("DJANGO_SETTINGS_MODULE", default="{{ project_name }}.settings.production"))
os.environ.setdefault("DJANGO_SETTINGS_MODULE", env("DJANGO_SETTINGS_MODULE", default="[[ project_name ]].settings.production"))
application = get_wsgi_application()
@@ -1,7 +0,0 @@
from django.urls import include, path
app_name = "api"
urlpatterns = [
path("v1/", include("api.v1.urls")),
]
@@ -1,7 +0,0 @@
from django.urls import include, path
app_name = "v1"
urlpatterns = [
path("users/", include("apps.users.urls")),
]
@@ -1,8 +0,0 @@
from django.db import models
class {{ model_class_name }}(models.Model):
"""Generated model for {{ app_name }} app."""
# Add fields here
pass
@@ -0,0 +1,18 @@
from django.db import models
class [[ model_class_name ]](models.Model):
"""[[ model_class_name ]] model."""
# Add your fields here
name = models.CharField(max_length=255)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
verbose_name = "[[ model_class_name ]]"
verbose_name_plural = "[[ model_class_name ]]s"
ordering = ["-created_at"]
def __str__(self):
return self.name
@@ -1,9 +0,0 @@
from rest_framework import serializers
from {{ app_module }}.models.{{ app_name }} import {{ model_class_name }}
class {{ model_class_name }}Serializer(serializers.ModelSerializer):
class Meta:
model = {{ model_class_name }}
fields = "__all__"
@@ -0,0 +1,11 @@
from rest_framework import serializers
from [[ app_module ]].models.[[ app_name ]] import [[ model_class_name ]]
class [[ model_class_name ]]Serializer(serializers.ModelSerializer):
"""Serializer for [[ model_class_name ]] model."""
class Meta:
model = [[ model_class_name ]]
fields = "__all__"
read_only_fields = ["id", "created_at", "updated_at"]
@@ -1,10 +0,0 @@
from typing import Optional
from {{ app_module }}.models.{{ app_name }} import {{ model_class_name }}
def get_{{ app_name }}_by_id(object_id: int) -> Optional[{{ model_class_name }}]:
try:
return {{ model_class_name }}.objects.get(id=object_id)
except {{ model_class_name }}.DoesNotExist:
return None
@@ -0,0 +1,36 @@
from [[ app_module ]].models.[[ app_name ]] import [[ model_class_name ]]
class [[ model_class_name ]]Service:
"""Service class for [[ model_class_name ]] business logic."""
@staticmethod
def get_all():
"""Get all [[ model_class_name ]] instances."""
return [[ model_class_name ]].objects.all()
@staticmethod
def get_by_id(id):
"""Get [[ model_class_name ]] by ID."""
try:
return [[ model_class_name ]].objects.get(id=id)
except [[ model_class_name ]].DoesNotExist:
return None
@staticmethod
def create(data):
"""Create a new [[ model_class_name ]] instance."""
return [[ model_class_name ]].objects.create(**data)
@staticmethod
def update(instance, data):
"""Update an existing [[ model_class_name ]] instance."""
for key, value in data.items():
setattr(instance, key, value)
instance.save()
return instance
@staticmethod
def delete(instance):
"""Delete a [[ model_class_name ]] instance."""
instance.delete()
@@ -1,12 +0,0 @@
import pytest
from django.urls import reverse
from rest_framework.test import APIClient
@pytest.mark.django_db
def test_{{ app_name }}_list_empty():
client = APIClient()
url = reverse("v1:{{ app_name }}-list")
response = client.get(url)
assert response.status_code == 200
assert response.json() == []
@@ -0,0 +1,55 @@
from rest_framework.test import APITestCase
from rest_framework import status
from django.contrib.auth import get_user_model
from [[ app_module ]].models.[[ app_name ]] import [[ model_class_name ]]
User = get_user_model()
class [[ model_class_name ]]APITestCase(APITestCase):
"""Test cases for [[ model_class_name ]] API endpoints."""
def setUp(self):
"""Set up test data."""
self.user = User.objects.create_user(
username="testuser", password="testpass123"
)
self.client.force_authenticate(user=self.user)
self.test_data = {"name": "Test [[ model_class_name ]]"}
def test_create_[[ app_name ]](self):
"""Test creating a [[ model_class_name ]]."""
response = self.client.post("/api/v1/[[ app_name ]]/", self.test_data)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual([[ model_class_name ]].objects.count(), 1)
def test_list_[[ app_name ]]s(self):
"""Test listing all [[ model_class_name ]]s."""
[[ model_class_name ]].objects.create(**self.test_data)
response = self.client.get("/api/v1/[[ app_name ]]/")
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data), 1)
def test_retrieve_[[ app_name ]](self):
"""Test retrieving a single [[ model_class_name ]]."""
instance = [[ model_class_name ]].objects.create(**self.test_data)
response = self.client.get(f"/api/v1/[[ app_name ]]/{instance.id}/")
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data["name"], self.test_data["name"])
def test_update_[[ app_name ]](self):
"""Test updating a [[ model_class_name ]]."""
instance = [[ model_class_name ]].objects.create(**self.test_data)
updated_data = {"name": "Updated [[ model_class_name ]]"}
response = self.client.patch(f"/api/v1/[[ app_name ]]/{instance.id}/", updated_data)
self.assertEqual(response.status_code, status.HTTP_200_OK)
instance.refresh_from_db()
self.assertEqual(instance.name, updated_data["name"])
def test_delete_[[ app_name ]](self):
"""Test deleting a [[ model_class_name ]]."""
instance = [[ model_class_name ]].objects.create(**self.test_data)
response = self.client.delete(f"/api/v1/[[ app_name ]]/{instance.id}/")
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
self.assertEqual([[ model_class_name ]].objects.count(), 0)
@@ -1,14 +0,0 @@
from django.urls import include, path
from rest_framework.routers import DefaultRouter
from {{ app_module }}.views.{{ app_name }}_view import {{ model_class_name }}ViewSet
app_name = "{{ app_name }}"
router = DefaultRouter()
router.register(r"{{ app_name }}", {{ model_class_name }}ViewSet, basename="{{ app_name }}")
urlpatterns = [
path("", include(router.urls)),
]
@@ -1,9 +0,0 @@
from rest_framework import viewsets
from {{ app_module }}.models.{{ app_name }} import {{ model_class_name }}
from {{ app_module }}.serializers.{{ app_name }}_serializer import {{ model_class_name }}Serializer
class {{ model_class_name }}ViewSet(viewsets.ModelViewSet):
queryset = {{ model_class_name }}.objects.all()
serializer_class = {{ model_class_name }}Serializer
@@ -0,0 +1,62 @@
from rest_framework import viewsets, status
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
from [[ app_module ]].models.[[ app_name ]] import [[ model_class_name ]]
from [[ app_module ]].serializers.[[ app_name ]]_serializer import [[ model_class_name ]]Serializer
from [[ app_module ]].services.[[ app_name ]]_service import [[ model_class_name ]]Service
class [[ model_class_name ]]ViewSet(viewsets.ModelViewSet):
"""ViewSet for [[ model_class_name ]] CRUD operations."""
queryset = [[ model_class_name ]].objects.all()
serializer_class = [[ model_class_name ]]Serializer
permission_classes = [IsAuthenticated]
def list(self, request):
"""List all [[ model_class_name ]] instances."""
instances = [[ model_class_name ]]Service.get_all()
serializer = self.get_serializer(instances, many=True)
return Response(serializer.data)
def retrieve(self, request, pk=None):
"""Retrieve a single [[ model_class_name ]] instance."""
instance = [[ model_class_name ]]Service.get_by_id(pk)
if not instance:
return Response(
{"error": "[[ model_class_name ]] not found"}, status=status.HTTP_404_NOT_FOUND
)
serializer = self.get_serializer(instance)
return Response(serializer.data)
def create(self, request):
"""Create a new [[ model_class_name ]] instance."""
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
instance = [[ model_class_name ]]Service.create(serializer.validated_data)
return Response(
self.get_serializer(instance).data, status=status.HTTP_201_CREATED
)
def update(self, request, pk=None):
"""Update an existing [[ model_class_name ]] instance."""
instance = [[ model_class_name ]]Service.get_by_id(pk)
if not instance:
return Response(
{"error": "[[ model_class_name ]] not found"}, status=status.HTTP_404_NOT_FOUND
)
serializer = self.get_serializer(instance, data=request.data, partial=True)
serializer.is_valid(raise_exception=True)
updated_instance = [[ model_class_name ]]Service.update(instance, serializer.validated_data)
return Response(self.get_serializer(updated_instance).data)
def destroy(self, request, pk=None):
"""Delete a [[ model_class_name ]] instance."""
instance = [[ model_class_name ]]Service.get_by_id(pk)
if not instance:
return Response(
{"error": "[[ model_class_name ]] not found"}, status=status.HTTP_404_NOT_FOUND
)
[[ model_class_name ]]Service.delete(instance)
return Response(status=status.HTTP_204_NO_CONTENT)
@@ -1,14 +0,0 @@
from django.urls import include, path
from rest_framework.routers import DefaultRouter
from apps.users.views.user_view import UserViewSet
app_name = "users"
router = DefaultRouter()
router.register(r"users", UserViewSet, basename="users")
urlpatterns = [
path("", include(router.urls)),
]
@@ -1,9 +0,0 @@
from rest_framework.response import Response
def success(data=None, status_code=200):
return Response({"success": True, "data": data}, status=status_code)
def error(message, status_code=400):
return Response({"success": False, "message": message}, status=status_code)
@@ -1,13 +1,17 @@
# @IF include_header
"""generated with djinit"""
# @ENDIF
from rest_framework.response import Response
def success(data=None, status_code=200):
"""Return a successful response."""
# @IF include_docstrings """Return a successful response."""
# @ENDIF
return Response({"success": True, "data": data}, status=status_code)
def error(message, status_code=400):
"""Return an error response."""
# @IF include_docstrings """Return an error response."""
# @ENDIF
return Response({"success": False, "message": message}, status=status_code)
@@ -62,7 +62,7 @@ jobs:
- name: Run Django tests
env:
DJANGO_SETTINGS_MODULE: {{ module_name }}.settings.development
DJANGO_SETTINGS_MODULE: [[ module_name ]].settings.development
SECRET_KEY: test-secret-key-for-ci
ALLOWED_HOSTS: localhost
DB_NAME: test_db
@@ -76,7 +76,7 @@ jobs:
- name: Check migrations
env:
DJANGO_SETTINGS_MODULE: {{ module_name }}.settings.development
DJANGO_SETTINGS_MODULE: [[ module_name ]].settings.development
SECRET_KEY: test-secret-key-for-ci
ALLOWED_HOSTS: localhost
DB_NAME: test_db
@@ -1,4 +1,4 @@
# GitLab CI/CD configuration for {{ project_name }}
# GitLab CI/CD configuration for [[ project_name ]]
stages:
- test
@@ -36,7 +36,7 @@ test:
stage: test
image: python:3.13
variables:
DJANGO_SETTINGS_MODULE: {{ module_name }}.settings.development
DJANGO_SETTINGS_MODULE: [[ module_name ]].settings.development
SECRET_KEY: test-secret-key-for-ci
ALLOWED_HOSTS: localhost
script:
@@ -52,7 +52,7 @@ test:python310:
stage: test
image: python:3.10
variables:
DJANGO_SETTINGS_MODULE: {{ module_name }}.settings.development
DJANGO_SETTINGS_MODULE: [[ module_name ]].settings.development
SECRET_KEY: test-secret-key-for-ci
ALLOWED_HOSTS: localhost
script:
@@ -69,7 +69,7 @@ test:python311:
stage: test
image: python:3.11
variables:
DJANGO_SETTINGS_MODULE: {{ module_name }}.settings.development
DJANGO_SETTINGS_MODULE: [[ module_name ]].settings.development
SECRET_KEY: test-secret-key-for-ci
ALLOWED_HOSTS: localhost
script:
@@ -86,7 +86,7 @@ test:python312:
stage: test
image: python:3.12
variables:
DJANGO_SETTINGS_MODULE: {{ module_name }}.settings.development
DJANGO_SETTINGS_MODULE: [[ module_name ]].settings.development
SECRET_KEY: test-secret-key-for-ci
ALLOWED_HOSTS: localhost
script:
@@ -103,7 +103,7 @@ test:python313:
stage: test
image: python:3.13
variables:
DJANGO_SETTINGS_MODULE: {{ module_name }}.settings.development
DJANGO_SETTINGS_MODULE: [[ module_name ]].settings.development
SECRET_KEY: test-secret-key-for-ci
ALLOWED_HOSTS: localhost
script:
@@ -121,7 +121,7 @@ security:
stage: security
image: python:3.13
variables:
DJANGO_SETTINGS_MODULE: {{ project_name }}.settings.development
DJANGO_SETTINGS_MODULE: [[ project_name ]].settings.development
SECRET_KEY: test-secret-key-for-ci
script:
- pip install uv
@@ -1,23 +1,23 @@
# Django settings
DJANGO_SETTINGS_MODULE={{ project_name }}.settings.development
DJANGO_SETTINGS_MODULE=[[ project_name ]].settings.development
SECRET_KEY= your-secret-key
ALLOWED_HOSTS=api.your-domain.com,www.your-domain.com
{% if use_database_url %}
# @IF use_database_url
# Database URL (recommended for production)
{% if database_type == 'mysql' %}
DATABASE_URL=mysql://user:password@localhost:3306/{{ project_name }}
{% else %}
DATABASE_URL=postgres://user:password@localhost:5432/{{ project_name }}
{% endif %}
{% else %}
# @IF database_type == 'mysql'
DATABASE_URL=mysql://user:password@localhost:3306/[[ project_name ]]
# @ELSE
DATABASE_URL=postgres://user:password@localhost:5432/[[ project_name ]]
# @ENDIF
# @ELSE
# Database (individual parameters)
DB_NAME=
DB_USER=
DB_PASSWORD=
DB_HOST=
DB_PORT=
{% endif %}
# @ENDIF
# Frontend URL
FRONTEND_URL=http://frontend.your-domain.com
File renamed without changes.
View File
Whitespace-only changes.
@@ -1,4 +1,4 @@
# Justfile for {{ project_name }}
# Justfile for [[ project_name ]]
# Task runner for Django development
# Install just: https://github.com/casey/just
@@ -108,15 +108,15 @@ dbshell:
# Start production server with gunicorn
server:
uv run gunicorn {{ project_name }}.wsgi:application --bind 0.0.0.0:8000
uv run gunicorn [[ project_name ]].wsgi:application --bind 0.0.0.0:8000
# Start production server with gunicorn workers
server-prod WORKERS="4":
uv run gunicorn {{ project_name }}.wsgi:application --bind 0.0.0.0:8000 --workers {{ '{{' }}WORKERS{{ '}}' }}
uv run gunicorn [[ project_name ]].wsgi:application --bind 0.0.0.0:8000 --workers {{ '{{' }}WORKERS{{ '}}' }}
# Start production server with gunicorn and reload on file changes
server-watch:
uv run gunicorn {{ project_name }}.wsgi:application --bind 0.0.0.0:8000 --reload
uv run gunicorn [[ project_name ]].wsgi:application --bind 0.0.0.0:8000 --reload
# Clean Python cache files
clean:
@@ -11,7 +11,7 @@ import environ
def main():
"""Run administrative tasks."""
os.environ.setdefault("DJANGO_SETTINGS_MODULE", os.getenv("DJANGO_SETTINGS_MODULE", "{{ project_name }}.settings.production"))
os.environ.setdefault("DJANGO_SETTINGS_MODULE", os.getenv("DJANGO_SETTINGS_MODULE", "[[ project_name ]].settings.production"))
try:
from django.core.management import execute_from_command_line
@@ -1,20 +1,20 @@
# Procfile for {{ project_name }}
# Procfile for [[ project_name ]]
# Used for deploying to PaaS platforms like Heroku, Railway, Render, etc.
# Web server process (using Gunicorn)
# Adjust workers based on your needs: (2 x CPU cores) + 1
web: gunicorn {{ project_name }}.wsgi:application --bind 0.0.0.0:$PORT --workers 2 --timeout 120 --access-logfile - --error-logfile - --log-level info
web: gunicorn [[ project_name ]].wsgi:application --bind 0.0.0.0:$PORT --workers 2 --timeout 120 --access-logfile - --error-logfile - --log-level info
# Alternative web server configurations (uncomment to use):
# web: gunicorn {{ project_name }}.wsgi:application --bind 0.0.0.0:$PORT --workers 4 --threads 2 --timeout 120
# web: gunicorn {{ project_name }}.wsgi:application --bind 0.0.0.0:$PORT --workers 2 --worker-class gevent --worker-connections 1000 --timeout 120
# web: gunicorn [[ project_name ]].wsgi:application --bind 0.0.0.0:$PORT --workers 4 --threads 2 --timeout 120
# web: gunicorn [[ project_name ]].wsgi:application --bind 0.0.0.0:$PORT --workers 2 --worker-class gevent --worker-connections 1000 --timeout 120
# Release task (runs migrations before deployment)
release: python manage.py migrate --noinput && python manage.py collectstatic --noinput
# Uncomment below to run scheduled tasks (if using Celery)
# worker: celery -A {{ project_name }} worker --loglevel=info
# beat: celery -A {{ project_name }} beat --loglevel=info
# worker: celery -A [[ project_name ]] worker --loglevel=info
# beat: celery -A [[ project_name ]] beat --loglevel=info
# Development server (for local testing with Foreman/Overmind)
# web: python manage.py runserver 0.0.0.0:$PORT
@@ -1,5 +1,5 @@
[project]
name = "{{ package_name }}"
name = "[[ package_name ]]"
version = "0.1.0"
description = ""
readme = "README.md"
@@ -14,8 +14,12 @@ dependencies = [
"drf-spectacular",
"django-cors-headers",
"whitenoise",
# @IF database_type == 'mysql'
"mysqlclient",
# @ENDIF
# @IF database_type == 'postgresql'
"psycopg2-binary",
# @ENDIF
"gunicorn",
]
@@ -39,4 +43,4 @@ ignore = [
]
[tool.ruff.lint.isort]
known-first-party = ["{{ project_name }}"]
known-first-party = ["[[ project_name ]]"]
@@ -1,4 +1,4 @@
# {{ project_name }}
# [[ project_name ]]
A Django project folder structure is generated with [djinitx/djinit/dj](https://github.com/S4NKALP/djinit).
@@ -71,9 +71,9 @@ Run `just` to see all available commands, including:
## Project Structure
```
{% if predefined_structure %}
{{ project_name }}/
├── {{ module_name }}/
# @IF predefined_structure
[[ project_name ]]/
├── [[ module_name ]]/
│ ├── settings/
│ │ ├── base.py
│ │ ├── development.py
@@ -118,8 +118,8 @@ Run `just` to see all available commands, including:
├── Procfile
├── runtime.txt
└── README.md
{% elif unified_structure %}
{{ project_name }}/
# @ELSEIF unified_structure
[[ project_name ]]/
├── apps/
│ ├── admin/
│ │ └── __init__.py
@@ -158,9 +158,9 @@ Run `just` to see all available commands, including:
├── Procfile
├── runtime.txt
└── README.md
{% else %}
{{ project_name }}/
├── {{ module_name }}/
# @ELSE
[[ project_name ]]/
├── [[ module_name ]]/
│ ├── settings/
│ │ ├── base.py
│ │ ├── development.py
@@ -191,7 +191,7 @@ For example, if you have a `User` model in `models/user.py`, create:
- `api/user/urls.py` - URL patterns for User endpoints
See the README files in `api/` and `models/` directories for more details.
{% endif %}
# @ENDIF
```
## API Documentation
@@ -10,10 +10,10 @@ djangorestframework_simplejwt
drf-spectacular
django-cors-headers
whitenoise
{% if database_type == 'mysql' %}
# @IF database_type == 'mysql'
mysqlclient
{% else %}
# @ELSE
psycopg[binary]
{% endif %}
# @ENDIF
gunicorn
{% if use_database_url %}dj-database-url{% endif %}
dj-database-url # @IF use_database_url
+1
View File
@@ -0,0 +1 @@
python-[[ python_version ]]
-1
View File
@@ -1 +0,0 @@
python-{{ python_version }}