DEV Community

Cover image for Django Build Automation
SachinDas246
SachinDas246

Posted on

Django Build Automation

Hello! If you are a person like try to automate django build for production, here is a small script for you. Building Django for production is not a tedious task compared to other frameworks but, there are many elements that can go wrong because we need to configure each of them manually , which can be removed by automating the process. Though some other approaches like using environment variables , docker secrets , or even splitting settings.py into production.py and development.py exist , i felt this approach suits my current project and hope some other person would find this helpful.

This is my current Folder structure

project_name
├── docs
├── .git
├── .gitignore
└── source
    ├── django
        ├── conf
        │   ├── asgi.py
        │   ├── __init__.py
        │   ├── settings.py
        │   ├── urls.py
        │   └── wsgi.py
        ├── manage.py
        └── requirements.txt

Enter fullscreen mode Exit fullscreen mode

1 . Create a file named build.py inside project_name (along with source dir, .git and docs ) and add the following content

import shutil
import os


class Builder:
    def __init__(self,source_dir,build_dir):

        self.source_dir = os.path.abspath(source_dir) if not os.path.isabs(source_dir) else source_dir
        self.build_dir = os.path.abspath(build_dir) if not os.path.isabs(build_dir) else build_dir
        self.ignore_file = os.path.join(os.path.dirname(os.path.abspath(__file__)),'.buildignore')
        self.prebuild_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)),'pre_build')
        print(self.source_dir)
        print(self.build_dir)

    def get_ignore_patterns(self):
        self.ignore_patterns = []
        if os.path.exists(self.ignore_file):
            with open(self.ignore_file, 'r') as buildignore_file:
                self.ignore_patterns = buildignore_file.read().splitlines()      

        print(self.ignore_patterns) 

    def copy_to_build_dir(self):
        shutil.copytree(self.source_dir,self.build_dir,ignore=shutil.ignore_patterns(*self.ignore_patterns))    

    def replace_prebuild(self):
        shutil.copytree(self.prebuild_dir, self.build_dir, dirs_exist_ok=True)

    def build(self):
        self.get_ignore_patterns()
        self.copy_to_build_dir()
        self.replace_prebuild()


builder =Builder('./source','./build') # change the name of dir if needed
builder.build()
Enter fullscreen mode Exit fullscreen mode

You can change the name of the folders as you need in this file.

2 . Create a file name .buildignore. This will act similar to .gitignore , ie you can can mention here the files and dirs you dont need in production. For now you can add the following content and edit as you need.

*.log
*.pot
*.pyc
__pycache__/
.env
db.sqlite3
Enter fullscreen mode Exit fullscreen mode

3 . Create a folder named pre_build and inside this create the files that you need to replace in production. Note you need to follow the same folder structure for the file you need to replace. For instance if you need to replace setting.py for production you should create settings.py in the following path: project_name/pre_build/django/conf/settings.py . Also you can add additional files that will be copied to the respective path in the build dir. In short, the script will copy all the contents from pre_build and replace any content that already exist from the source. You can utilise this to include other files like docker-compose,.env files or even nginx configs etc . Also you can configure your static files (change STATIC_ROOT to a dir inside pre_build).

Now my dir would look like

project_name
├── docs
├── .git
├── .gitignore
├── .buildignore
├── build.py
├── pre_build
│   └── django
│       └── conf
│           └── settings.py
└── source
    └── django
        ├── conf
        │   ├── asgi.py
        │   ├── __init__.py
        │   ├── settings.py
        │   ├── urls.py
        │   └── wsgi.py
        ├── manage.py
        └── requirements.txt
Enter fullscreen mode Exit fullscreen mode

4 . and when you want to build the production run the following

python build.py
Enter fullscreen mode Exit fullscreen mode

Top comments (1)

Collapse
 
sachindas246 profile image
SachinDas246

use this
STATIC_ROOT = join(BASE_DIR,'..','..','pre_build','static')
to set collect the static files to prebuild