├── backend
├── __init__.py
├── migrations
│ └── __init__.py
├── models.py
├── admin.py
├── apps.py
├── urls.py
├── templates
│ └── index.html
├── views.py
└── tests.py
├── djangovue
├── __init__.py
├── wsgi.py
├── urls.py
└── settings.py
├── .babelrc
├── frontend
├── img
│ └── logo.png
└── js
│ ├── main.js
│ └── App.vue
├── .gitignore
├── package.json
├── docker-compose.yml
├── manage.py
├── .dockerignore
├── LICENSE
├── vite.config.js
├── pyproject.toml
├── Dockerfile
├── .github
└── workflows
│ ├── codeql-analysis.yml
│ ├── dependencies.yml
│ └── ci.yml
├── gemini.md
├── README.md
├── Makefile
└── uv.lock
/backend/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/djangovue/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/backend/migrations/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015"]
3 | }
--------------------------------------------------------------------------------
/backend/models.py:
--------------------------------------------------------------------------------
1 | # Create your models here.
2 |
--------------------------------------------------------------------------------
/backend/admin.py:
--------------------------------------------------------------------------------
1 | # Register your models here.
2 |
--------------------------------------------------------------------------------
/frontend/img/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mikebz/djangovue/HEAD/frontend/img/logo.png
--------------------------------------------------------------------------------
/backend/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class BackendConfig(AppConfig):
5 | name = "backend"
6 |
--------------------------------------------------------------------------------
/frontend/js/main.js:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import App from './App.vue'
3 |
4 | createApp(App).mount('#app')
5 |
--------------------------------------------------------------------------------
/backend/urls.py:
--------------------------------------------------------------------------------
1 | from django.urls import path
2 |
3 | from . import views
4 |
5 | urlpatterns = [
6 | path("", views.index, name="index"),
7 | ]
8 |
--------------------------------------------------------------------------------
/backend/templates/index.html:
--------------------------------------------------------------------------------
1 | {% load django_vite %}
2 |
3 |
4 |
5 |
6 |
7 | Django Vue.js App
8 |
9 |
10 |
11 | {% vite_asset 'frontend/js/main.js' %}
12 |
13 |
--------------------------------------------------------------------------------
/backend/views.py:
--------------------------------------------------------------------------------
1 | from django.shortcuts import render
2 |
3 |
4 | def index(request):
5 | """
6 | serving up the main app page which loads the Vue.js from WebPack
7 | """
8 | context = {
9 | "data": "value",
10 | }
11 | return render(request, "index.html", context)
12 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Python virtual environments
2 | venv
3 | .venv
4 |
5 | # UV cache and environment files
6 | .python-version
7 |
8 | # VS Code
9 | .vscode
10 |
11 | # Django
12 | db.sqlite3
13 | __pycache__/
14 | *.py[cod]
15 | *.log
16 |
17 | # Node.js
18 | node_modules/
19 |
20 | # Build outputs
21 | frontend/bundles/*
22 | frontend/dist/
23 | build/
24 |
25 | # Vite
26 | .vite/
--------------------------------------------------------------------------------
/djangovue/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for djangovue 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/1.11/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", "djangovue.settings")
15 |
16 | application = get_wsgi_application()
17 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "djangovue",
3 | "version": "0.1.0",
4 | "description": "Django + Vue.js application with modern tooling",
5 | "private": true,
6 | "type": "module",
7 | "author": "Mike Borozdin",
8 | "license": "MIT",
9 | "scripts": {
10 | "dev": "vite",
11 | "build": "vite build",
12 | "preview": "vite preview",
13 | "watch": "vite build --watch"
14 | },
15 | "dependencies": {
16 | "vue": "^3.5.0"
17 | },
18 | "devDependencies": {
19 | "@vitejs/plugin-vue": "^5.2.0",
20 | "vite": "^6.0.0"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3.8'
2 |
3 | services:
4 | web:
5 | build: .
6 | ports:
7 | - "8000:8000"
8 | volumes:
9 | - .:/app
10 | - /app/node_modules
11 | - /app/.venv
12 | environment:
13 | - DEBUG=1
14 | - DJANGO_SETTINGS_MODULE=djangovue.settings
15 | command: >
16 | sh -c "uv run python manage.py migrate &&
17 | uv run python manage.py runserver 0.0.0.0:8000"
18 | healthcheck:
19 | test: ["CMD", "curl", "-f", "http://localhost:8000/"]
20 | interval: 30s
21 | timeout: 10s
22 | retries: 3
23 | start_period: 40s
24 |
25 | frontend:
26 | image: node:22-alpine
27 | working_dir: /app
28 | volumes:
29 | - .:/app
30 | - /app/node_modules
31 | command: npm run dev
32 | ports:
33 | - "3000:3000"
34 | environment:
35 | - NODE_ENV=development
36 |
--------------------------------------------------------------------------------
/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import os
3 | import sys
4 |
5 | if __name__ == "__main__":
6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "djangovue.settings")
7 | try:
8 | from django.core.management import execute_from_command_line
9 | except ImportError:
10 | # The above import may fail for some other reason. Ensure that the
11 | # issue is really that Django is missing to avoid masking other
12 | # exceptions on Python 2.
13 | try:
14 | import django
15 | except ImportError:
16 | raise ImportError(
17 | "Couldn't import Django. Are you sure it's installed and "
18 | "available on your PYTHONPATH environment variable? Did you "
19 | "forget to activate a virtual environment?"
20 | )
21 | raise
22 | execute_from_command_line(sys.argv)
23 |
--------------------------------------------------------------------------------
/djangovue/urls.py:
--------------------------------------------------------------------------------
1 | """djangovue URL Configuration
2 |
3 | The `urlpatterns` list routes URLs to views. For more information please see:
4 | https://docs.djangoproject.com/en/5.1/topics/http/urls/
5 | Examples:
6 | Function views
7 | 1. Add an import: from my_app import views
8 | 2. Add a URL to urlpatterns: path('', views.home, name='home')
9 | Class-based views
10 | 1. Add an import: from other_app.views import Home
11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
12 | Including another URLconf
13 | 1. Import the include() function: from django.urls import path, include
14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
15 | """
16 |
17 | from django.contrib import admin
18 | from django.urls import include, path
19 |
20 | urlpatterns = [
21 | path("admin/", admin.site.urls),
22 | path("", include("backend.urls")),
23 | ]
24 |
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | # Python
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 | *.so
6 | .Python
7 | env/
8 | venv/
9 | .venv/
10 | ENV/
11 | env.bak/
12 | venv.bak/
13 | .pytest_cache/
14 |
15 | # Django
16 | db.sqlite3
17 | db.sqlite3-journal
18 | media/
19 | staticfiles/
20 |
21 | # Node.js
22 | node_modules/
23 | npm-debug.log*
24 | yarn-debug.log*
25 | yarn-error.log*
26 |
27 | # Build outputs
28 | frontend/bundles/
29 | frontend/dist/
30 | build/
31 |
32 | # Development
33 | .vscode/
34 | .idea/
35 | *.swp
36 | *.swo
37 | *~
38 |
39 | # OS
40 | .DS_Store
41 | .DS_Store?
42 | ._*
43 | .Spotlight-V100
44 | .Trashes
45 | ehthumbs.db
46 | Thumbs.db
47 |
48 | # Git
49 | .git/
50 | .gitignore
51 |
52 | # Docker
53 | Dockerfile
54 | .dockerignore
55 |
56 | # CI/CD
57 | .github/
58 |
59 | # Logs
60 | *.log
61 |
62 | # Environment variables
63 | .env
64 | .env.local
65 | .env.*.local
66 |
67 | # Temporary files
68 | *.tmp
69 | *.temp
70 |
71 | # UV
72 | .uv/
73 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Mike Borozdin
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import vue from '@vitejs/plugin-vue'
3 | import path from 'path'
4 |
5 | export default defineConfig({
6 | plugins: [vue()],
7 |
8 | // Entry point
9 | build: {
10 | outDir: 'frontend/dist',
11 | emptyOutDir: true,
12 | manifest: true,
13 | rollupOptions: {
14 | input: 'frontend/js/main.js',
15 | output: {
16 | // Keep similar naming convention for Django integration
17 | entryFileNames: '[name]-[hash].js',
18 | chunkFileNames: '[name]-[hash].js',
19 | assetFileNames: '[name]-[hash].[ext]'
20 | }
21 | }
22 | },
23 |
24 | // Development server
25 | server: {
26 | host: '127.0.0.1',
27 | port: 3000,
28 | open: false,
29 | cors: true
30 | },
31 |
32 | // Asset handling
33 | resolve: {
34 | alias: {
35 | '@': path.resolve(__dirname, 'frontend'),
36 | '~': path.resolve(__dirname, 'frontend')
37 | }
38 | },
39 |
40 | // Public assets
41 | publicDir: false, // Don't copy public assets to dist
42 |
43 | // CSS handling
44 | css: {
45 | devSourcemap: true
46 | },
47 |
48 | // Define environment variables
49 | define: {
50 | __VUE_OPTIONS_API__: true,
51 | __VUE_PROD_DEVTOOLS__: false
52 | }
53 | })
54 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [project]
2 | name = "djangovue"
3 | version = "0.1.0"
4 | description = "Django + Vue application"
5 | authors = [
6 | {name = "Mike Borozdin", email = "mike@example.com"},
7 | ]
8 | readme = "README.md"
9 | license = {text = "MIT"}
10 | requires-python = ">=3.11"
11 | dependencies = [
12 | "django>=5.1,<5.2",
13 | "django-vite>=3.1.0",
14 | "pytz>=2023.3",
15 | ]
16 |
17 | [project.optional-dependencies]
18 | dev = [
19 | "ruff>=0.1.0",
20 | "black>=23.0.0",
21 | ]
22 |
23 | [build-system]
24 | requires = ["hatchling"]
25 | build-backend = "hatchling.build"
26 |
27 | [tool.ruff]
28 | line-length = 88
29 | target-version = "py313"
30 |
31 | [tool.ruff.lint]
32 | select = [
33 | "E", # pycodestyle errors
34 | "W", # pycodestyle warnings
35 | "F", # pyflakes
36 | "I", # isort
37 | "B", # flake8-bugbear
38 | "C4", # flake8-comprehensions
39 | "UP", # pyupgrade
40 | ]
41 | ignore = [
42 | "E501", # line too long, handled by black
43 | "B008", # do not perform function calls in argument defaults
44 | ]
45 |
46 | [tool.ruff.lint.isort]
47 | known-first-party = ["djangovue", "backend"]
48 |
49 | [tool.black]
50 | line-length = 88
51 | target-version = ['py313']
52 | include = '\.pyi?$'
53 | extend-exclude = '''
54 | /(
55 | # directories
56 | \.eggs
57 | | \.git
58 | | \.hg
59 | | \.mypy_cache
60 | | \.tox
61 | | \.venv
62 | | build
63 | | dist
64 | )/
65 | '''
66 |
--------------------------------------------------------------------------------
/frontend/js/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |

4 |
{{ msg }}
5 |
Essential Links
6 |
12 |
Ecosystem
13 |
19 |
20 |
21 |
22 |
32 |
33 |
61 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | # Multi-stage build for Django + Vue.js application
2 | FROM node:22-alpine AS frontend-builder
3 |
4 | # Set working directory
5 | WORKDIR /app
6 |
7 | # Copy package files
8 | COPY package*.json ./
9 |
10 | # Install dependencies
11 | RUN npm ci --only=production
12 |
13 | # Copy frontend source
14 | COPY frontend/ ./frontend/
15 | COPY vite.config.js ./
16 |
17 | # Build frontend
18 | RUN npm run build
19 |
20 | # Python application stage
21 | FROM python:3.13-slim
22 |
23 | # Set environment variables
24 | ENV PYTHONDONTWRITEBYTECODE=1 \
25 | PYTHONUNBUFFERED=1 \
26 | UV_SYSTEM_PYTHON=1
27 |
28 | # Install system dependencies
29 | RUN apt-get update \
30 | && apt-get install -y --no-install-recommends \
31 | curl \
32 | build-essential \
33 | && rm -rf /var/lib/apt/lists/*
34 |
35 | # Install UV
36 | RUN pip install uv
37 |
38 | # Set work directory
39 | WORKDIR /app
40 |
41 | # Copy Python dependency files
42 | COPY pyproject.toml uv.lock ./
43 |
44 | # Install Python dependencies
45 | RUN uv sync --frozen --no-dev
46 |
47 | # Copy project
48 | COPY . .
49 |
50 | # Copy built frontend from previous stage
51 | COPY --from=frontend-builder /app/frontend/dist/ ./frontend/dist/
52 |
53 | # Collect static files
54 | RUN python manage.py collectstatic --noinput
55 |
56 | # Create non-root user
57 | RUN adduser --disabled-password --gecos '' appuser && \
58 | chown -R appuser:appuser /app
59 | USER appuser
60 |
61 | # Expose port
62 | EXPOSE 8000
63 |
64 | # Health check
65 | HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \
66 | CMD curl -f http://localhost:8000/ || exit 1
67 |
68 | # Run application
69 | CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
70 |
--------------------------------------------------------------------------------
/.github/workflows/codeql-analysis.yml:
--------------------------------------------------------------------------------
1 | # For most projects, this workflow file will not need changing; you simply need
2 | # to commit it to your repository.
3 | #
4 | # You may wish to alter this file to override the set of languages analyzed,
5 | # or to provide custom queries or build logic.
6 | #
7 | # ******** NOTE ********
8 | # We have attempted to detect the languages in your repository. Please check
9 | # the `language` matrix defined below to confirm you have the correct set of
10 | # supported CodeQL languages.
11 | #
12 | name: "CodeQL"
13 |
14 | on:
15 | push:
16 | branches: [ master ]
17 | pull_request:
18 | # The branches below must be a subset of the branches above
19 | branches: [ master ]
20 | schedule:
21 | - cron: '29 6 * * 4'
22 |
23 | jobs:
24 | analyze:
25 | name: Analyze
26 | runs-on: ubuntu-latest
27 |
28 | strategy:
29 | fail-fast: false
30 | matrix:
31 | language: [ 'javascript', 'python' ]
32 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
33 | # Learn more:
34 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
35 |
36 | steps:
37 | - name: Checkout repository
38 | uses: actions/checkout@v2
39 |
40 | # Initializes the CodeQL tools for scanning.
41 | - name: Initialize CodeQL
42 | uses: github/codeql-action/init@v1
43 | with:
44 | languages: ${{ matrix.language }}
45 | # If you wish to specify custom queries, you can do so here or in a config file.
46 | # By default, queries listed here will override any specified in a config file.
47 | # Prefix the list here with "+" to use these queries and those in the config file.
48 | # queries: ./path/to/local/query, your-org/your-repo/queries@main
49 |
50 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
51 | # If this step fails, then you should remove it and run the build manually (see below)
52 | - name: Autobuild
53 | uses: github/codeql-action/autobuild@v1
54 |
55 | # ℹ️ Command-line programs to run using the OS shell.
56 | # 📚 https://git.io/JvXDl
57 |
58 | # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
59 | # and modify them (or add more) to build your code if your project
60 | # uses a compiled language
61 |
62 | #- run: |
63 | # make bootstrap
64 | # make release
65 |
66 | - name: Perform CodeQL Analysis
67 | uses: github/codeql-action/analyze@v1
68 |
--------------------------------------------------------------------------------
/gemini.md:
--------------------------------------------------------------------------------
1 | ## role and expertise
2 | You are a senior software engineer who follows Kent Beck's Test-Driven Development (TDD). Your purpose is to guide development following these methodologies precisely. You leave comments as to why some things are designed or implemented as such. If you need to link out to an extenal source you leave the URL in the comments.
3 |
4 | ## core development principles
5 | - Always follow the TDD cycle: Red → Green → Refactor
6 | - Write the simplest failing test first
7 | - Implement the minimum code needed to make tests pass
8 | - Refactor only after tests are passing
9 | - Follow Beck's "Tidy First" approach by separating structural changes from behavioral changes
10 | - Maintain high code quality throughout development
11 |
12 | ## tdd methodology guidance
13 | - Start by writing a failing test that defines a small increment of functionality
14 | - Use meaningful test names that describe behavior (e.g., "shouldSumTwoPositiveNumbers")
15 | - Make test failures clear and informative
16 | - Write just enough code to make the test pass - no more
17 | - Once tests pass, consider if refactoring is needed
18 | - Repeat the cycle for new functionality
19 |
20 | ## tidy first approach
21 | - Separate all changes into two distinct types:
22 | 1. STRUCTURAL CHANGES: Rearranging code without changing behavior (renaming, extracting methods, moving code)
23 | 2. BEHAVIORAL CHANGES: Adding or modifying actual functionality
24 | - Never mix structural and behavioral changes in the same commit
25 | - Always make structural changes first when both are needed
26 | - Validate structural changes do not alter behavior by running tests before and after
27 | ## commit discipline
28 | - Only commit when:
29 | 1. ALL tests are passing
30 | 2. ALL compiler/linter warnings have been resolved
31 | 3. The change represents a single logical unit of work
32 | 4. Commit messages clearly state whether the commit contains structural or behavioral changes
33 | - Use small, frequent commits rather than large, infrequent ones
34 | ## code quality standards
35 | - Eliminate duplication ruthlessly
36 | - Express intent clearly through naming and structure
37 | - Make dependencies explicit
38 | - Keep methods small and focused on a single responsibility
39 | - Minimize state and side effects
40 | - Use the simplest solution that could possibly work
41 | # refactoring guidelines
42 | - Refactor only when tests are passing (in the "Green" phase)
43 | - Use established refactoring patterns with their proper names
44 | - Make one refactoring change at a time
45 | - Run tests after each refactoring step
46 | - Prioritize refactorings that remove duplication or improve clarity
47 | # example workflow
48 | When approaching a new feature:
49 | 1. Write a simple failing test for a small part of the feature
50 | 2. Implement the bare minimum to make it pass
51 | 3. Run tests to confirm they pass (Green)
52 | 4. Make any necessary structural changes (Tidy First), running tests after each change
53 | 5. Commit structural changes separately
54 | 6. Add another test for the next small increment of functionality
55 | 7. Repeat until the feature is complete, committing behavioral changes separately from structural ones
56 | Follow this process precisely, always prioritizing clean, well-tested code over quick implementation.
57 | Always write one test at a time, make it run, then improve structure. Always run all the tests (except long-running tests) each time.
58 |
--------------------------------------------------------------------------------
/djangovue/settings.py:
--------------------------------------------------------------------------------
1 | """
2 | Django settings for djangovue project.
3 |
4 | Generated by 'django-admin startproject' using Django 1.11.5.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/1.11/topics/settings/
8 |
9 | For the full list of settings and their values, see
10 | https://docs.djangoproject.com/en/1.11/ref/settings/
11 | """
12 |
13 | import os
14 |
15 | # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
16 | BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
17 |
18 |
19 | # Quick-start development settings - unsuitable for production
20 | # See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/
21 |
22 | # SECURITY WARNING: keep the secret key used in production secret!
23 | SECRET_KEY = "(0&w0&rj&i7^jmo9#g*!#fua2q$j6umcnegqaw+gyzi-hal5!="
24 |
25 | # SECURITY WARNING: don't run with debug turned on in production!
26 | DEBUG = True
27 |
28 | ALLOWED_HOSTS = []
29 |
30 |
31 | # Application definition
32 |
33 | INSTALLED_APPS = [
34 | "django.contrib.admin",
35 | "django.contrib.auth",
36 | "django.contrib.contenttypes",
37 | "django.contrib.sessions",
38 | "django.contrib.messages",
39 | "django.contrib.staticfiles",
40 | "backend",
41 | "django_vite",
42 | ]
43 |
44 | MIDDLEWARE = [
45 | "django.middleware.security.SecurityMiddleware",
46 | "django.contrib.sessions.middleware.SessionMiddleware",
47 | "django.middleware.common.CommonMiddleware",
48 | "django.middleware.csrf.CsrfViewMiddleware",
49 | "django.contrib.auth.middleware.AuthenticationMiddleware",
50 | "django.contrib.messages.middleware.MessageMiddleware",
51 | "django.middleware.clickjacking.XFrameOptionsMiddleware",
52 | ]
53 |
54 | ROOT_URLCONF = "djangovue.urls"
55 |
56 | TEMPLATES = [
57 | {
58 | "BACKEND": "django.template.backends.django.DjangoTemplates",
59 | "DIRS": [],
60 | "APP_DIRS": True,
61 | "OPTIONS": {
62 | "context_processors": [
63 | "django.template.context_processors.debug",
64 | "django.template.context_processors.request",
65 | "django.contrib.auth.context_processors.auth",
66 | "django.contrib.messages.context_processors.messages",
67 | ],
68 | },
69 | },
70 | ]
71 |
72 | WSGI_APPLICATION = "djangovue.wsgi.application"
73 |
74 |
75 | # Database
76 | # https://docs.djangoproject.com/en/1.11/ref/settings/#databases
77 |
78 | DATABASES = {
79 | "default": {
80 | "ENGINE": "django.db.backends.sqlite3",
81 | "NAME": os.path.join(BASE_DIR, "db.sqlite3"),
82 | }
83 | }
84 |
85 |
86 | # Password validation
87 | # https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators
88 |
89 | AUTH_PASSWORD_VALIDATORS = [
90 | {
91 | "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
92 | },
93 | {
94 | "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
95 | },
96 | {
97 | "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
98 | },
99 | {
100 | "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
101 | },
102 | ]
103 |
104 |
105 | # Internationalization
106 | # https://docs.djangoproject.com/en/1.11/topics/i18n/
107 |
108 | LANGUAGE_CODE = "en-us"
109 |
110 | TIME_ZONE = "UTC"
111 |
112 | USE_I18N = True
113 |
114 | USE_L10N = True
115 |
116 | USE_TZ = True
117 |
118 |
119 | # Static files (CSS, JavaScript, Images)
120 | # https://docs.djangoproject.com/en/1.11/howto/static-files/
121 |
122 | STATIC_URL = "/static/"
123 |
124 | STATICFILES_DIRS = [
125 | os.path.join(BASE_DIR, "frontend"),
126 | os.path.join(BASE_DIR, "frontend", "dist"),
127 | ]
128 |
129 | # Vite configuration
130 | DJANGO_VITE = {
131 | "default": {
132 | "dev_mode": False, # Force production mode for now
133 | "dev_server_host": "127.0.0.1",
134 | "dev_server_port": 3000,
135 | "manifest_path": os.path.join(
136 | BASE_DIR, "frontend", "dist", ".vite", "manifest.json"
137 | ),
138 | "static_url_prefix": "",
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/backend/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import Client, TestCase
2 |
3 |
4 | class IndexViewTest(TestCase):
5 | """
6 | Test the main index view that serves the Vue.js application.
7 | Following TDD principles with clear test naming and structure.
8 | """
9 |
10 | def setUp(self):
11 | """Set up test client for each test method."""
12 | self.client = Client()
13 |
14 | def test_index_view_returns_200_status_code(self):
15 | """
16 | GIVEN: A request to the root URL
17 | WHEN: The index view is called
18 | THEN: It should return a 200 status code
19 | """
20 | response = self.client.get("/")
21 | self.assertEqual(response.status_code, 200)
22 |
23 | def test_index_view_uses_correct_template(self):
24 | """
25 | GIVEN: A request to the root URL
26 | WHEN: The index view is called
27 | THEN: It should use the index.html template
28 | """
29 | response = self.client.get("/")
30 | self.assertTemplateUsed(response, "index.html")
31 |
32 | def test_index_view_contains_vue_app_div(self):
33 | """
34 | GIVEN: A request to the root URL
35 | WHEN: The index view is called
36 | THEN: The response should contain the Vue.js app mount point
37 | """
38 | response = self.client.get("/")
39 | self.assertContains(response, '')
40 |
41 | def test_index_view_contains_vue_js_title(self):
42 | """
43 | GIVEN: A request to the root URL
44 | WHEN: The index view is called
45 | THEN: The response should contain the Vue.js App title
46 | """
47 | response = self.client.get("/")
48 | self.assertContains(response, "Vue.js App")
49 |
50 | def test_index_view_contains_javascript_bundle(self):
51 | """
52 | GIVEN: A request to the root URL
53 | WHEN: The index view is called
54 | THEN: The response should include JavaScript bundle references
55 | """
56 | response = self.client.get("/")
57 | self.assertContains(response, ".js")
58 |
59 | def test_index_view_contains_css_bundle(self):
60 | """
61 | GIVEN: A request to the root URL
62 | WHEN: The index view is called
63 | THEN: The response should include CSS bundle references
64 | """
65 | response = self.client.get("/")
66 | self.assertContains(response, ".css")
67 |
68 |
69 | class URLConfigTest(TestCase):
70 | """
71 | Test URL configuration and routing.
72 | Ensures proper URL patterns are working.
73 | """
74 |
75 | def test_root_url_resolves_to_index_view(self):
76 | """
77 | GIVEN: The root URL pattern
78 | WHEN: A request is made to '/'
79 | THEN: It should resolve to the index view
80 | """
81 | response = self.client.get("/")
82 | # Test that the response is successful
83 | self.assertEqual(response.status_code, 200)
84 | # Test that it contains expected content
85 | self.assertContains(response, "Vue.js App")
86 |
87 |
88 | class ViteIntegrationTest(TestCase):
89 | """
90 | Test Django-Vite integration.
91 | Ensures build assets are properly integrated.
92 | """
93 |
94 | def test_vite_assets_are_loaded(self):
95 | """
96 | GIVEN: A built frontend with Vite
97 | WHEN: The index page is loaded
98 | THEN: Vite-generated assets should be referenced
99 | """
100 | response = self.client.get("/")
101 | # Check that the response contains script tags
102 | self.assertContains(response, "