# Django Package File Structure Guide

This document outlines the recommended file structure and standards for creating Django packages, following best practices for maintainability, distribution, and development workflow.

## Overview

The structure separates:
- **Package code** (`src/`) - The actual package that gets distributed
- **Development files** (root level) - Files needed for development but not distribution
- **Tests** (`tests/`) - Test suite excluded from distribution
- **Documentation** (`docs/`) - Documentation excluded from distribution

## Directory Structure

```
django-package-name/               # Project root
├── src/                           # Package source code (included in distribution)
│   └── django_package_name/       # Package name (matches PyPI name)
│       ├── __init__.py            # Package initialization
│       ├── apps.py                # Django app configuration
│       ├── models.py              # Database models (if needed)
│       ├── views.py               # Views (if needed)
│       ├── urls.py                # URL patterns (if needed)
│       ├── admin.py               # Django admin configuration (if needed)
│       ├── management/            # Management commands (if needed)
│       │   └── commands/
│       │       └── your_command.py
│       ├── migrations/            # Database migrations (if needed)
│       │   └── 0001_initial.py
│       └── ...                    # Other package modules
│
├── tests/                         # Test suite (excluded from distribution)
│   ├── __init__.py
│   ├── settings.py                # Django test settings
│   ├── models.py                  # Test models (if needed)
│   ├── apps.py                    # Test app configuration (if needed)
│   ├── migrations/                # Test migrations (if needed)
│   ├── requirements.txt           # Test dependencies
│   ├── run_tests.sh               # Test runner script (optional)
│   ├── README.md                  # Test documentation (optional)
│   ├── test_*.py                  # Test files (one per module)
│   ├── urls.py                    # Test URLs (if needed)
│   └── wsgi.py                    # Test WSGI (if needed)
│
├── docs/                          # Documentation (excluded from distribution)
│   ├── architecture.md            # Architecture documentation
│   ├── usage.md                   # Usage guide
│   ├── api.md                     # API reference (if needed)
│   └── package-structure.md       # This file
│
├── manage.py                      # Django management script (excluded from distribution)
├── examples.py                    # Example usage (excluded from distribution)
├── README.md                      # Project README (included in distribution)
├── LICENSE                        # License file (included in distribution)
├── pyproject.toml                 # Modern Python packaging configuration
├── setup.py                       # Setup script (backward compatibility)
├── MANIFEST.in                    # Files to include/exclude in distribution
└── .gitignore                     # Git ignore rules
```

## Directory Details

### `src/` - Package Source Code

**Purpose**: Contains the actual package code that will be distributed via PyPI or installed via pip.

**Key Points**:
- All package code lives here
- The package name directory (e.g., `django_package_name/`) matches the PyPI package name
- This is the only directory included in package distribution (along with README.md and LICENSE)
- Follows Django app structure conventions

**Structure**:
```
src/django_package_name/
├── __init__.py          # Package exports (use lazy imports to avoid AppRegistryNotReady)
├── apps.py              # Django app config (AppConfig class)
├── models.py            # Database models (if needed)
├── views.py             # Views (if needed)
├── urls.py              # URL patterns (if needed)
├── admin.py             # Django admin integration (if needed)
├── decorators.py        # Public decorators (if needed)
├── exceptions.py        # Custom exceptions (if needed)
├── utils.py             # Utility functions (if needed)
├── management/          # Management commands (if needed)
│   └── commands/        # Custom Django commands
└── migrations/          # Database migrations (if needed)
```

**Best Practices**:
- Use lazy imports in `__init__.py` to avoid `AppRegistryNotReady` errors
- Keep public API clean and well-documented
- Use type hints for better IDE support
- Follow Django conventions for app structure
- Only include files/modules that are actually needed for your package

### `tests/` - Test Suite

**Purpose**: Contains all test files and test configuration.

**Key Points**:
- Excluded from package distribution
- Contains its own Django settings for testing
- Can have its own migrations if needed
- Includes test dependencies in `requirements.txt`

**Structure**:
```
tests/
├── __init__.py
├── settings.py          # Django test settings
├── models.py            # Test models (if needed)
├── apps.py              # Test app config
├── migrations/          # Test migrations (if needed)
├── requirements.txt     # Test dependencies
├── run_tests.sh         # Quick test runner
├── README.md            # Test documentation
└── test_*.py            # Test files (one per module)
```

**Best Practices**:
- Use Django's TestCase for database-backed tests
- Mock external services (APIs, third-party libraries, etc.)
- Use Django's in-memory email backend for email tests
- Keep tests organized by module (`test_models.py`, `test_views.py`, etc.)
- Test standard cases, edge cases, and outlier cases
- Use descriptive test method names: `test_<what>_<expected_behavior>`
- Keep tests isolated and independent

### `docs/` - Documentation

**Purpose**: Contains project documentation.

**Key Points**:
- Excluded from package distribution
- Can include architecture docs, usage guides, etc.
- README.md in root is included in distribution, but docs/ folder is not

**Best Practices**:
- Keep documentation up to date
- Use Markdown format
- Include code examples
- Document architecture decisions

### Root Level Files

#### `manage.py`
- Django management script for running commands during development
- **Excluded from distribution** (users will use their own manage.py)
- Used for running tests: `python manage.py test tests`

#### `examples.py` or `example_*.py`
- Example usage code showing how to use the package
- **Excluded from distribution** (documentation serves this purpose)
- Useful for developers working on the package
- Can be multiple files if needed (e.g., `example_basic.py`, `example_advanced.py`)

#### `README.md`
- Project overview and quick start guide
- **Included in distribution** (shown on PyPI)
- Should include installation instructions and basic usage

#### `LICENSE`
- License file (MIT, Apache, etc.)
- **Included in distribution**

## Configuration Files

### `pyproject.toml` - Modern Python Packaging

**Purpose**: Modern Python packaging configuration (PEP 518, PEP 621).

**Key Configuration**:
```toml
[build-system]
requires = ["setuptools>=68"]
build-backend = "setuptools.build_meta"

[project]
name = "django-package-name"
version = "0.1.0"
description = "A Django package description"
requires-python = ">=3.8"
dependencies = [
    "django>=3.2,<6.0",
]

[project.optional-dependencies]
dev = [
    "django>=3.2,<6.0",
    "pytest>=7.0",
    "pytest-django>=4.5",
]
extra-feature = ["requests>=2.25.0"]

[tool.setuptools]
package-dir = {"" = "src"}

[tool.setuptools.packages.find]
where = ["src"]
exclude = [
    "*.tests*",
    "*test*",
    "*_test.py",
]
```

**Key Points**:
- `package-dir = {"" = "src"}` tells setuptools to look in `src/` for packages
- `where = ["src"]` specifies where to find packages
- `exclude` patterns automatically exclude test files
- Optional dependencies allow users to install extras: `pip install django-package-name[dev,extra-feature]`
- Use `dev` extra for development dependencies
- Use descriptive names for optional feature dependencies

### `setup.py` - Backward Compatibility

**Purpose**: Provides backward compatibility for tools that don't support `pyproject.toml` yet.

**Key Configuration**:
```python
from setuptools import setup, find_packages

setup(
    name='django-package-name',
    package_dir={'': 'src'},  # Important: points to src/
    packages=find_packages(where='src', exclude=['tests', 'tests.*']),
    include_package_data=True,
    # ... other config (version, description, etc. from pyproject.toml)
)
```

**Key Points**:
- `package_dir={'': 'src'}` matches `pyproject.toml` configuration
- `find_packages(where='src')` finds packages in `src/` directory
- Excludes `tests` from package distribution
- Can be minimal if using `pyproject.toml` (most metadata should be in `pyproject.toml`)

### `MANIFEST.in` - Distribution File Control

**Purpose**: Explicitly controls which files are included/excluded in distribution.

**Example**:
```
include README.md
include LICENSE
recursive-include src/django_package_name *.py
recursive-exclude * __pycache__
recursive-exclude * *.py[co]
recursive-exclude tests *
recursive-exclude docs *
exclude manage.py
exclude examples.py
exclude example_*.py
```

**Key Points**:
- `include` - Explicitly include files (README.md, LICENSE)
- `recursive-include` - Include all matching files in directory tree
- `recursive-exclude` - Exclude entire directories (tests, docs, etc.)
- `exclude` - Exclude specific files (manage.py, examples.py, etc.)

**Best Practices**:
- Be explicit about what to include
- Always exclude `__pycache__` and `*.pyc` files
- Exclude development-only directories (tests, docs)
- Exclude example files and development scripts
- Include only necessary files to keep package size small

## Package Distribution

### What Gets Included

✅ **Included**:
- All files in `src/django_package_name/`
- `README.md` (from root)
- `LICENSE` (from root)
- Package metadata from `pyproject.toml` or `setup.py`

❌ **Excluded**:
- `tests/` directory
- `docs/` directory
- `manage.py`
- `examples.py` and `example_*.py`
- `__pycache__/` directories
- `*.pyc` files
- Any other development-only files

### Building and Distributing

```bash
# Install build tools
pip install build

# Build source distribution
python -m build

# Build wheel distribution
python -m build --wheel

# Both create files in dist/
# dist/
#   ├── django-package-name-0.1.0.tar.gz
#   └── django_package_name-0.1.0-py3-none-any.whl
```

### Installing Locally

```bash
# Install in editable mode (for development)
pip install -e .

# Install from source
pip install .

# Install with extras
pip install -e .[dev,extra-feature]
```

## Development Workflow

### Initial Setup

```bash
# 1. Create virtual environment
python3 -m venv venv
source venv/bin/activate  # Linux/Mac
# OR
venv\Scripts\activate  # Windows

# 2. Install package in editable mode
pip install -e .

# 3. Install test dependencies
pip install -r tests/requirements.txt
```

### Running Tests

```bash
# Run all tests
python manage.py test tests --verbosity=2

# Run specific test file
python manage.py test tests.test_models

# Run specific test class
python manage.py test tests.test_models.ModelTests

# Run specific test method
python manage.py test tests.test_models.ModelTests.test_specific_behavior

# Alternative: Use pytest (if configured)
pytest tests/
pytest tests/test_models.py
pytest tests/test_models.py::ModelTests::test_specific_behavior
```

### Creating Migrations

```bash
# Create migrations for the package
python manage.py makemigrations django_package_name

# Apply migrations
python manage.py migrate django_package_name

# Show migration status
python manage.py showmigrations django_package_name
```

## Testing Standards

### Test Organization

**File Naming**:
- One test file per module: `test_models.py`, `test_views.py`, `test_utils.py`
- Test files should mirror the package structure
- Use descriptive test class names: `ModelTests`, `ViewTests`, `UtilTests`

**Test Structure**:
```python
from django.test import TestCase
from django_package_name.models import YourModel

class ModelTests(TestCase):
    """Tests for YourModel."""
    
    def setUp(self):
        """Set up test data."""
        self.obj = YourModel.objects.create(...)
    
    def test_standard_case(self):
        """Test normal operation."""
        # Test standard behavior
        pass
    
    def test_edge_case_empty_value(self):
        """Test behavior with empty values."""
        # Test edge cases
        pass
    
    def test_outlier_case_invalid_input(self):
        """Test behavior with invalid inputs."""
        # Test outlier cases
        pass
```

### Test Categories

**Standard Cases**:
- Normal operations with valid inputs
- Successful execution paths
- Expected behavior under typical conditions

**Edge Cases**:
- Empty/null values
- Boundary values (min/max)
- Long strings or large numbers
- Future/past dates (if applicable)
- Missing optional parameters

**Outlier Cases**:
- Invalid inputs
- Network failures (mock external services)
- Database errors
- Permission errors
- Exception handling

### Testing Best Practices

1. **Isolation**: Each test should be independent and not rely on other tests
2. **Naming**: Use descriptive names: `test_<what>_<expected_behavior>`
3. **Arrange-Act-Assert**: Structure tests clearly
4. **Mocking**: Mock external services (APIs, email, file system)
5. **Fixtures**: Use `setUp()` and `tearDown()` for common setup
6. **Coverage**: Aim for high coverage of critical paths
7. **Speed**: Use in-memory database and fast mocks
8. **Documentation**: Add docstrings explaining what each test validates

### Test Requirements File

**`tests/requirements.txt`** should include:
```
# Core testing dependencies
pytest>=7.0
pytest-django>=4.5
pytest-cov>=4.0  # For coverage reports

# Mocking
responses>=0.23  # For mocking HTTP requests
freezegun>=1.2   # For mocking time/dates

# Code quality (optional)
black>=23.0
flake8>=6.0
mypy>=1.0
```

### Running Tests with Coverage

```bash
# Install coverage tool
pip install coverage pytest-cov

# Run tests with coverage
coverage run --source='django_package_name' manage.py test tests
coverage report
coverage html  # Generates HTML report in htmlcov/

# Or with pytest
pytest --cov=django_package_name --cov-report=html tests/
```

## Best Practices

### 1. Package Structure
- ✅ Use `src/` layout for better separation
- ✅ Keep package name consistent (directory name = PyPI name)
- ✅ Follow Django app conventions
- ✅ Only include necessary files/modules

### 2. Imports
- ✅ Use lazy imports in `__init__.py` to avoid `AppRegistryNotReady` (if needed)
- ✅ Use `TYPE_CHECKING` for forward references
- ✅ Keep imports organized and minimal
- ✅ Use absolute imports

### 3. Testing
- ✅ Exclude tests from distribution
- ✅ Use Django's TestCase for database tests
- ✅ Mock external services
- ✅ Test standard, edge, and outlier cases
- ✅ Maintain high test coverage for critical paths
- ✅ Keep tests fast and isolated

### 4. Distribution
- ✅ Use `pyproject.toml` for modern packaging
- ✅ Keep `setup.py` for backward compatibility
- ✅ Use `MANIFEST.in` for explicit file control
- ✅ Exclude development-only files
- ✅ Test the built package before publishing

### 5. Documentation
- ✅ Keep README.md up to date
- ✅ Document public API
- ✅ Include usage examples
- ✅ Document configuration options
- ✅ Add docstrings to public classes/functions
- ✅ Keep architecture docs in `docs/` folder

### 6. Version Control
- ✅ Use `.gitignore` to exclude:
  - `__pycache__/`
  - `*.pyc`, `*.pyo`
  - `venv/`, `.venv/`
  - `dist/`, `build/`, `*.egg-info/`
  - `.pytest_cache/`, `.coverage`, `htmlcov/`
  - IDE-specific files (`.vscode/`, `.idea/`)

## Common Patterns

### Lazy Imports in `__init__.py`

**Why**: Avoids `AppRegistryNotReady` errors when Django models are imported at module level.

```python
"""Django Package Name."""

def __getattr__(name):
    """Lazy import to avoid AppRegistryNotReady errors."""
    if name == 'YourClass':
        from django_package_name.module import YourClass
        return YourClass
    if name == 'your_function':
        from django_package_name.module import your_function
        return your_function
    # ... other exports
    raise AttributeError(f"module {__name__!r} has no attribute {name!r}")

def __dir__():
    """List available exports for IDE autocomplete."""
    return ['YourClass', 'your_function', ...]
```

**Alternative**: If you don't need lazy imports, you can use standard imports:
```python
"""Django Package Name."""
from django_package_name.module import YourClass, your_function

__all__ = ['YourClass', 'your_function']
```

### Django App Configuration

```python
# apps.py
from django.apps import AppConfig

class DjangoPackageNameConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'django_package_name'
    verbose_name = 'Django Package Name'
    
    def ready(self):
        """Called when Django starts."""
        # Import signal handlers, register tasks, etc.
        pass
```

### Test Settings

```python
# tests/settings.py
SECRET_KEY = 'test-secret-key-for-testing-only'
DEBUG = True

INSTALLED_APPS = [
    'django.contrib.contenttypes',
    'django.contrib.auth',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.admin',  # Only if using admin in tests
    'django_package_name',
    'tests',  # Your test app
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
]

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': ':memory:',  # In-memory database for faster tests
    }
}

# Use in-memory email backend for testing
EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'
```

## Documentation Standards

### README.md (Root Level)

Should include:
- Package description and purpose
- Installation instructions
- Quick start guide with code examples
- Basic usage examples
- Configuration options
- Links to full documentation in `docs/`
- License information

### Documentation in `docs/`

Recommended structure:
- **architecture.md** - System design, components, data flow
- **usage.md** - Detailed usage guide, patterns, examples
- **api.md** - API reference (if needed)
- **package-structure.md** - This file

**Best Practices**:
- Use Markdown format
- Include code examples
- Keep documentation up to date with code changes
- Use clear headings and structure
- Add diagrams if helpful (Mermaid, PlantUML, etc.)

## Summary

This structure provides:
- ✅ Clear separation between package code and development files
- ✅ Proper exclusion of tests and docs from distribution
- ✅ Modern Python packaging with `pyproject.toml`
- ✅ Backward compatibility with `setup.py`
- ✅ Explicit file control with `MANIFEST.in`
- ✅ Easy development workflow with editable installs
- ✅ Comprehensive testing setup with standards
- ✅ Well-organized documentation structure

Following this structure ensures your Django package is:
- **Well-organized and maintainable** - Clear separation of concerns
- **Properly distributed** - Only necessary files included
- **Easy to develop** - Standard structure familiar to Django developers
- **Easy to test** - Comprehensive test suite with clear standards
- **Well-documented** - Clear documentation for users and contributors
- **Modern** - Uses current Python packaging standards
- **Professional** - Follows Django and Python best practices

## Quick Reference Checklist

When creating a new Django package:

- [ ] Create `src/django_package_name/` directory structure
- [ ] Set up `pyproject.toml` with proper configuration
- [ ] Create minimal `setup.py` for backward compatibility
- [ ] Configure `MANIFEST.in` to exclude tests/docs
- [ ] Create `tests/` directory with test settings
- [ ] Add `tests/requirements.txt` with test dependencies
- [ ] Create `docs/` directory for documentation
- [ ] Write comprehensive `README.md`
- [ ] Add `manage.py` for development (excluded from distribution)
- [ ] Set up `.gitignore` for common Python/Django files
- [ ] Implement lazy imports in `__init__.py` (if needed)
- [ ] Create Django app configuration in `apps.py`
- [ ] Write tests covering standard, edge, and outlier cases
- [ ] Document architecture and usage in `docs/`
