Skip to content

Commit

Permalink
fix storages
Browse files Browse the repository at this point in the history
  • Loading branch information
Tim Santor committed Jan 9, 2024
1 parent 9c89eed commit 774bdf1
Show file tree
Hide file tree
Showing 9 changed files with 91 additions and 38 deletions.
55 changes: 50 additions & 5 deletions README-FORK.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,51 @@
This forked version of the cookiecutter-django repo keeps all the features of that repo, plus adds additional features to get started on more complex projects quickly.
This forked version of the [cookiecutter-django](https://github.com/cookiecutter/cookiecutter-django) repo retains all the features of that repo and adds additional optional features to get started on more complex projects quickly.

# Features
- Optional Mosquitto integration
- Optional Nginx integration for static file serving
- Optional `robots` package
## Features
- Makefile with some helpful commands
- Custom AdminSite class
- Custom Storage classes
- Prebuilt Celery Tasks
- Custom JSONRenderer (consistent DRF response format)
- Simple Model Mixins
- Simple Admin Mixins
- Bash Utility Scripts
- Create User
- Install Docker
- Traefik
- Dashboard enabled (traefik.domain.com/dashboard)
- Access log enabled


## Optional Integrations
These features can be enabled during initial project setup.
- Mosquitto service
- Nginx integration for static file serving (via Traefix proxy)
- `django-robots` package
- `dj-rest-auth` package (see known issues below)
- `djangorestframework-simplejwt` package
- `django-oauth-toolkit` package
- `django-auditlog` package
- `django-celery-results` package
- `django-perm-filter` package


## Usage
```
cookiecutter https://github.com/tsantor/cookiecutter-django
```
You'll be prompted for some values. Provide them, then a Django project will be created for you.


## Production Deployment via Docker

- On local machine run, `push_production_env`
- On production, run `make nginx_htaccess` - this
- On production, run `make traefik_htaccess`
- On production, run `make deploy_prod`


## Known issues
- Enabling rest-auth will thrown an error as it is not compatible with django-allauth > 0.54.0

## TODO
- Need to make work with frontend pipelines other than Gulp
7 changes: 4 additions & 3 deletions cookiecutter.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,13 @@
"Other SMTP"
],
"use_async": "n",
"use_dj_rest_auth": "y",
"use_simplejwt": "y",
"use_dj_rest_auth": "n",
"use_simplejwt": "n",
"use_oauth": "y",
"use_mosquitto": "n",
"use_django_auditlog": "y",
"use_django_auditlog": "n",
"use_robots": "n",
"use_perm_filter": "y",
"use_drf": "n",
"frontend_pipeline": [
"None",
Expand Down
3 changes: 2 additions & 1 deletion {{cookiecutter.project_slug}}/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ mutagen_down: ## mutagen terminate
# -----------------------------------------------------------------------------
# Experimental
# -----------------------------------------------------------------------------
rsync_to_prod:

rsync_to_prod: ## rsync to prod (for down n' dirty testing)
# rsync -avzP -e "ssh -i ~/.ssh/your-key.pem" . ${prod_ssh}:~/${project_dir}/
rsync -avzP . ${prod_ssh}:~/${project_dir}/
28 changes: 18 additions & 10 deletions {{cookiecutter.project_slug}}/config/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@
{%- endif %}
"rest_framework.authentication.SessionAuthentication",
"rest_framework.authentication.TokenAuthentication",
{% if cookiecutter.use_simplejwt == "y" -%}
{%- if cookiecutter.use_simplejwt == "y" %}
"rest_framework_simplejwt.authentication.JWTAuthentication",
{%- endif %}
),
Expand Down Expand Up @@ -466,9 +466,11 @@
REST_AUTH = {
'USE_JWT': True,
'JWT_AUTH_COOKIE': 'jwt-auth',
"USER_DETAILS_SERIALIZER": "django_spaday.api.serializers.UserAuthSerializer",
# "USER_DETAILS_SERIALIZER": "django_spaday.api.serializers.UserAuthSerializer",
}
{%- endif %}

{% if cookiecutter.use_simplejwt == "y" -%}
# https://django-rest-framework-simplejwt.readthedocs.io/en/latest/settings.htm
SIMPLE_JWT = {
"ACCESS_TOKEN_LIFETIME": timedelta(minutes=5),
Expand All @@ -485,6 +487,7 @@

# SESSION_COOKIE_SAMESITE = 'Strict'

{%- if cookiecutter.use_perm_filter == 'y' %}
# django-perm-filter
# -------------------------------------------------------------------------------
PERM_FILTER = {
Expand All @@ -498,11 +501,11 @@
# All-auth
"account",
"socialaccount",

{%- if cookiecutter.use_celery == "y" %}
# Celery
"django_celery_beat",
"django_celery_results",

{%- endif %}
"thumbnail",
# Django built-in auth permissions
"auth.view_permission",
Expand All @@ -518,7 +521,7 @@
"authtoken.add_tokenproxy",
"authtoken.change_tokenproxy",
"authtoken.delete_tokenproxy",

{%- if cookiecutter.use_oauth == "y" %}
# oAuth2
"oauth2_provider.view_idtoken",
"oauth2_provider.add_idtoken",
Expand All @@ -532,16 +535,18 @@
"oauth2_provider.add_refreshtoken",
"oauth2_provider.change_refreshtoken",
"oauth2_provider.delete_refreshtoken",

{%- endif %}
],
"UNREGISTER_MODELS": [
{%- if cookiecutter.use_drf == "y" %}
"rest_framework.authtoken.models.TokenProxy",
{%- endif %}
# All-auth
"allauth.account.models.EmailAddress",
"allauth.socialaccount.models.SocialAccount",
"allauth.socialaccount.models.SocialApp",
"allauth.socialaccount.models.SocialToken",

{%- if cookiecutter.use_celery == "y" %}
# Celery
"django_celery_beat.models.ClockedSchedule",
# "django_celery_beat.models.CrontabSchedule",
Expand All @@ -550,14 +555,16 @@
"django_celery_beat.models.SolarSchedule",
"django_celery_results.models.GroupResult",
# "django_celery_results.models.TaskResult",

{%- endif %}
# "django.contrib.sites.models.Site",

{%- if cookiecutter.use_oauth == "y" %}
# oAuth2
"oauth2_provider.models.IDToken",
"oauth2_provider.models.Grant",
{%- endif %}
],
}
{%- endif %}

{%- if cookiecutter.frontend_pipeline == 'Webpack' %}
# django-webpack-loader
Expand All @@ -581,7 +588,8 @@
re.compile(r'^/robots\.txt$'),
]

PROJECT_TITLE = env("PROJECT_TITLE")
PROJECT_TITLE = env("PROJECT_TITLE", default="{{ cookiecutter.project_name }}")
BASE_URL = env("BASE_URL", default="https://{{ cookiecutter.domain_name }}")

{%- if cookiecutter.use_oauth == "y" %}
OAUTH2_PROVIDER = {
Expand Down
12 changes: 10 additions & 2 deletions {{cookiecutter.project_slug}}/config/settings/production.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,11 @@
# "format": "%(levelname)s %(asctime)s %(module)s "
# "%(process)d %(thread)d %(message)s"
"format": "%(asctime)s [%(name)s:%(lineno)s] %(levelname)s - %(message)s"
}
},
"custom_formatter": {
"format": "[%(levelname)s] %(asctime)s %(module)s %(message)s",
"datefmt": "%Y-%m-%d %I:%M:%S %p",
},
},
"handlers": {
"mail_admins": {
Expand Down Expand Up @@ -328,7 +332,11 @@
# "format": "%(levelname)s %(asctime)s %(module)s "
# "%(process)d %(thread)d %(message)s"
"format": "%(asctime)s [%(name)s:%(lineno)s] %(levelname)s - %(message)s"
}
},
"custom_formatter": {
"format": "[%(levelname)s] %(asctime)s %(module)s %(message)s",
"datefmt": "%Y-%m-%d %I:%M:%S %p",
},
},
"handlers": {
"console": {
Expand Down
2 changes: 1 addition & 1 deletion {{cookiecutter.project_slug}}/requirements/base.txt
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,10 @@ django-auditlog==1.0.0
{%- if cookiecutter.use_oauth == "y" %}
django-oauth-toolkit==2.2.0
{%- endif %}
# faker
{%- if cookiecutter.use_robots == "y" %}
django-robots==5.0
{%- endif %}
# faker

# X Studios / Tim Santor packages
django-extensions-too==0.1.4
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
from django.contrib import admin

# from django_otp.admin import OTPAdminSite


# class CustomAdminSite(OTPAdminSite):
class CustomAdminSite(admin.AdminSite):
site_title = "{{ cookiecutter.project_name }}"
site_header = "{{ cookiecutter.project_name }}"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{%- if cookiecutter.use_celery %}
from celery import shared_task
from django.core import management

Expand All @@ -12,3 +13,4 @@ def delete_expired_tokens():
def delete_expired_sessions():
"""Delete expired sessions"""
management.call_command("clearsessions", verbosity=0)
{%- endif %}
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,9 @@ class MediaS3Storage(S3Boto3Storage):
location = "media"
file_overwrite = False

class ManifestS3Storage(S3ManifestStaticStorage):
class ManifestS3Storage(ForivingManifestStorageMixin, S3ManifestStaticStorage):
location = "static"
default_acl = "public-read"
manifest_strict = False

def hashed_name(self, name, content=None, filename=None):
try:
result = super().hashed_name(name, content, filename)
except ValueError:
# When the file is missing, let's forgive and ignore that.
result = name
return result

{%- elif cookiecutter.cloud_provider == 'GCP' -%}
from storages.backends.gcloud import GoogleCloudStorage
Expand Down Expand Up @@ -64,8 +55,8 @@ class MediaAzureStorage(AzureStorage):
file_overwrite = False
{%- endif %}

{%- if cookiecutter.use_whitenoise == "y" -%}

{% if cookiecutter.use_whitenoise -%}
from whitenoise.storage import CompressedManifestStaticFilesStorage

class StaticRootWhiteNoiseStorage(ForivingManifestStorageMixin, CompressedManifestStaticFilesStorage):
Expand All @@ -76,7 +67,7 @@ class StaticRootWhiteNoiseStorage(ForivingManifestStorageMixin, CompressedManife
COLLECTFAST_STRATEGY = "collectfast.strategies.filesystem.FileSystemStrategy"
"""
pass
{% else %}
{%- else %}

from django.contrib.staticfiles.storage import ManifestStaticFilesStorage

Expand All @@ -88,4 +79,4 @@ class ForgivingManifestStaticFilesStorage(ForivingManifestStorageMixin, Manifest
COLLECTFAST_STRATEGY = "collectfast.strategies.filesystem.FileSystemStrategy"
"""
pass
{% endif %}
{%- endif %}

0 comments on commit 774bdf1

Please sign in to comment.