### Arborescence du projet `{project_name}`
```
{project_name}/
■■■ .env
■■■ .gitignore
■■■ config/
■ ■■■ __init__.py
■ ■■■ asgi.py
■ ■■■ wsgi.py
■ ■■■ settings/
■ ■ ■■■ __init__.py
■ ■ ■■■ base.py
■ ■ ■■■ dev.py
■ ■ ■■■ prod.py
■ ■■■ urls.py
■■■ apps/
■ ■■■ accounts/
■ ■■■ __init__.py
■ ■■■ admin.py
■ ■■■ apps.py
■ ■■■ forms.py
■ ■■■ models.py
■ ■■■ urls.py
■ ■■■ views.py
■ ■■■ tokens.py
■ ■■■ templates/
■ ■■■ accounts/
■ ■■■ base.html
■ ■■■ login.html
■ ■■■ signup.html
■ ■■■ password_reset.html
■ ■■■ password_reset_confirm.html
■ ■■■ profile.html
■■■ requirements.txt
■■■ Pipfile
■■■ manage.py
■■■ Dockerfile
■■■ docker-compose.yml
■■■ .github/
■■■ workflows/
■■■ ci.yml
```
## 1. Fichier de démarrage : `manage.py`
```python
#!/usr/bin/env python
import os
import sys
def main():
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings.dev')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django."
) from exc
execute_from_command_line(sys.argv)
if __name__ == '__main__':
main()
```
## 2. ASGI et WSGI
### `config/asgi.py`
```python
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings.prod')
application = get_asgi_application()
```
### `config/wsgi.py`
```python
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings.prod')
application = get_wsgi_application()
```
## 3. Fichiers restants
### `config/settings/base.py`
```python
from pathlib import Path
import environ
env = environ.Env()
environ.Env.read_env()
BASE_DIR = Path(__file__).resolve().parent.parent.parent
SECRET_KEY = env("SECRET_KEY")
DEBUG = env.bool("DEBUG", default=True)
ALLOWED_HOSTS = env.list("ALLOWED_HOSTS", default=[])
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'apps.core',
'apps.accounts',
]
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',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'config.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates'],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'config.wsgi.application'
DATABASES = {
'default': env.db(),
}
AUTH_PASSWORD_VALIDATORS = [
{'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'},
{'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator'},
{'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator'},
{'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'},
]
LANGUAGE_CODE = 'fr-fr'
TIME_ZONE = 'Africa/Douala'
USE_I18N = True
USE_TZ = True
STATIC_URL = 'static/'
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
AUTH_USER_MODEL = 'accounts.User'
```
### `apps/accounts/models.py`
```python
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
bio = models.TextField(blank=True)
avatar = models.ImageField(upload_to='avatars/', blank=True, null=True)
```
### `apps/accounts/forms.py`
```python
from django import forms
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
from .models import User
class SignUpForm(UserCreationForm):
class Meta:
model = User
fields = ('username', 'email', 'password1', 'password2')
class LoginForm(AuthenticationForm):
pass
class ProfileForm(forms.ModelForm):
class Meta:
model = User
fields = ('bio', 'avatar')
```
### `apps/accounts/views.py`
```python
from django.contrib.auth import login, logout
from django.contrib.auth.views import LoginView, LogoutView, PasswordResetView,
PasswordResetConfirmView
from django.urls import reverse_lazy
from django.views.generic import CreateView, UpdateView
from .forms import SignUpForm, ProfileForm
from .models import User
from django.contrib.auth.mixins import LoginRequiredMixin
class SignUpView(CreateView):
form_class = SignUpForm
success_url = reverse_lazy('login')
template_name = 'accounts/signup.html'
class ProfileView(LoginRequiredMixin, UpdateView):
model = User
form_class = ProfileForm
template_name = 'accounts/profile.html'
success_url = reverse_lazy('profile')
def get_object(self):
return self.request.user
```
### `apps/accounts/urls.py`
```python
from django.urls import path
from django.contrib.auth import views as auth_views
from .views import SignUpView, ProfileView
urlpatterns = [
path('signup/', SignUpView.as_view(), name='signup'),
path('login/', auth_views.LoginView.as_view(template_name='accounts/login.html'),
name='login'),
path('logout/', auth_views.LogoutView.as_view(), name='logout'),
path('password_reset/', auth_views.PasswordResetView.as_view(
template_name='accounts/password_reset.html',
email_template_name='accounts/password_reset_email.html',
subject_template_name='accounts/password_reset_subject.txt',
success_url='done/'
), name='password_reset'),
path('password_reset/done/', auth_views.PasswordResetDoneView.as_view(
template_name='accounts/password_reset_done.html'
), name='password_reset_done'),
path('reset/<uidb64>/<token>/', auth_views.PasswordResetConfirmView.as_view(
template_name='accounts/password_reset_confirm.html',
success_url='/accounts/reset/complete/'
), name='password_reset_confirm'),
path('reset/complete/', auth_views.PasswordResetCompleteView.as_view(
template_name='accounts/password_reset_complete.html'
), name='password_reset_complete'),
path('profile/', ProfileView.as_view(), name='profile'),
]
```
### Templates vitrine et supplémentaires
(Templates `base.html`, `home.html`, `about.html`, `pictures.html`, `privacy.html`,
`blog.html`)