Django Support¶
Rejig provides specialized tools for refactoring Django projects: managing settings, URLs, apps, and dependencies.
Installation¶
DjangoProject¶
The DjangoProject class provides Django-specific operations.
DjangoProject expects the project root to contain a Django root directory
(named django-root by default; override with django_root_name).
from rejig.django import DjangoProject
# Use context manager for automatic cleanup
with DjangoProject("/path/to/project") as project:
# Django-specific operations
project.add_installed_app("myapp")
# Customize the Django root directory name
with DjangoProject("/path/to/project", django_root_name="src") as project:
project.add_installed_app("myapp")
Settings Management¶
Add to INSTALLED_APPS¶
with DjangoProject(".") as project:
# Add app at the end
project.add_installed_app("myapp")
# Add after a specific app
project.add_installed_app("myapp", after_app="django.contrib.auth")
Add Middleware¶
# Add at the beginning (default position is "first")
project.add_middleware("myapp.middleware.CustomMiddleware")
# Add at specific position
project.add_middleware(
"myapp.middleware.SecurityMiddleware",
position="first" # Before all other middleware
)
# Add at the end
project.add_middleware(
"myapp.middleware.LoggingMiddleware",
position="last"
)
# Add after a specific middleware
project.add_middleware(
"myapp.middleware.LoggingMiddleware",
position="after",
after="django.middleware.common.CommonMiddleware"
)
Update Middleware Path¶
project.update_middleware_path(
"deprecated.middleware.OldMiddleware",
"myapp.middleware.NewMiddleware",
)
Manage Settings Variables¶
# Add a new setting
project.add_setting("MY_SETTING", '"value"')
project.add_setting("CACHE_TIMEOUT", "3600")
project.add_setting("DEBUG_TOOLBAR", "True")
# Add with comment
project.add_setting(
"API_KEY",
'os.environ.get("API_KEY")',
comment="API key from environment"
)
# Update existing setting
project.update_setting("DEBUG", "False")
project.update_setting("ALLOWED_HOSTS", '["*"]')
# Delete setting
project.delete_setting("DEPRECATED_SETTING")
URL Configuration¶
Add URL Patterns¶
with DjangoProject(".") as project:
# Add a simple URL pattern
project.add_url_pattern(
path_str="api/users/",
view="UserListView.as_view()",
name="user-list"
)
# Add a path with parameters
project.add_url_pattern(
path_str="api/users/<int:pk>/",
view="UserDetailView.as_view()",
name="user-detail"
)
Add URL Include¶
# Include another URLconf
project.add_url_include("api.urls", path_prefix="api/")
project.add_url_include("myapp.urls", path_prefix="myapp/")
Remove URL Patterns¶
# Remove by view name
project.remove_url_pattern_by_view("OldView")
# Remove by matching a regex against the path() line
project.remove_url_pattern(r'.*deprecated.*')
Find and Move URL Patterns¶
# Find a URL pattern line (searches all urls.py via include() if no file given)
match = project.find_url_pattern(view_name="UserListView")
if match:
line, file_path = match
print(f"Found in {file_path}: {line}")
# Move a URL pattern (and its view import) from one urls.py to another
project.move_url_pattern(
"UserListView",
source_urls=project.root_urls_path,
dest_urls=project.django_root / "api" / "urls.py",
)
App Discovery¶
Find apps and files containing specific code:
with DjangoProject(".") as project:
# Find which app contains a class
app_name = project.find_app_containing_class("MyView", filename="views.py")
print(f"MyView is in app: {app_name}")
# Find file containing a class
file_path = project.find_file_containing_class("MyModel")
print(f"MyModel is in: {file_path}")
# Find which app matches an arbitrary regex pattern
app_name = project.find_app_containing_pattern(
r"class\s+User\b", filename="models.py"
)
Dependency Management¶
Manage pyproject.toml dependencies for Django projects:
with DjangoProject(".") as project:
# Add Django dependency
project.add_dependency("django", "^4.2.0")
# Add related packages
project.add_dependency("django-rest-framework", "^3.14.0")
project.add_dependency("django-cors-headers", "^4.0.0")
# Update dependency
project.update_dependency("django", "^5.0.0")
# Remove dependency
project.remove_dependency("django-deprecated-package")
App Creation¶
Create a new Django app directory with starter files:
with DjangoProject(".") as project:
project.create_app(
"newapp",
files={
"views.py": "from django.shortcuts import render\n",
"urls.py": "from django.urls import path\n\nurlpatterns = []\n",
},
)
# Check whether an app exists / get its path
if project.app_exists("newapp"):
print(project.get_app_path("newapp"))
Moving Code (rope)¶
DjangoProject delegates rope-based moves to the internal Rejig instance.
These update imports across the project automatically:
with DjangoProject(".") as project:
project.move_class(
project.django_root / "myapp" / "views.py",
"UserListView",
"myapp.api.views",
)
project.move_function(
project.django_root / "myapp" / "utils.py",
"helper",
"myapp.common",
)
Common Patterns¶
Set Up New Django App¶
with DjangoProject(".") as project:
app_name = "newapp"
# Add to INSTALLED_APPS
project.add_installed_app(app_name)
# Add URL include
project.add_url_include(f"{app_name}.urls", path_prefix=f"{app_name}/")
# Add any required middleware
if needs_middleware:
project.add_middleware(f"{app_name}.middleware.CustomMiddleware")
Migrate to Django REST Framework¶
with DjangoProject(".") as project:
# Add DRF to dependencies
project.add_dependency("djangorestframework", "^3.14.0")
# Add to INSTALLED_APPS
project.add_installed_app("rest_framework")
# Add REST framework settings
project.add_setting("REST_FRAMEWORK", """{
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
}""")
Update Django Version¶
with DjangoProject(".") as project:
# Update dependency
project.update_dependency("django", "^5.0.0")
# Update deprecated settings
project.delete_setting("USE_L10N") # Removed in Django 4.0
# Rename a middleware path (if a class moved between versions)
project.update_middleware_path(
"django.middleware.csrf.OldCsrfViewMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
)
Add Authentication App¶
with DjangoProject(".") as project:
# Add dependencies
project.add_dependency("django-allauth", "^0.54.0")
# Add to INSTALLED_APPS
for app in [
"django.contrib.sites",
"allauth",
"allauth.account",
"allauth.socialaccount",
]:
project.add_installed_app(app)
# Add settings
project.add_setting("SITE_ID", "1")
project.add_setting("AUTHENTICATION_BACKENDS", """[
'django.contrib.auth.backends.ModelBackend',
'allauth.account.auth_backends.AuthenticationBackend',
]""")
# Add URLs
project.add_url_include("allauth.urls", path_prefix="accounts/")
Integration with Core Rejig¶
For CST-level operations (renaming, editing classes/functions), use a Rejig
instance scoped at the Django root alongside the Django-specific operations:
from rejig import Rejig
from rejig.django import DjangoProject
with DjangoProject(".") as project:
# Django-specific operations
project.add_installed_app("newapp")
project.add_middleware("myapp.middleware.Custom")
# Core Rejig operations on the same tree
rj = Rejig(project.django_root)
rj.find_class("MyModel").add_method("__str__")
Settings and Path Resolution¶
DjangoProject resolves key paths relative to the Django root. The default
settings file is django_site/settings/base.py:
with DjangoProject(".") as project:
print(f"Project root: {project.project_root}")
print(f"Django root: {project.django_root}")
print(f"Settings file: {project.settings_path}")
print(f"Root urls.py: {project.root_urls_path}")
print(f"pyproject: {project.pyproject_path}")
Settings operations accept an explicit settings_file argument to target a
different settings module: