Django: Bagaimana mengatur pengaturan pengembangan dan produksi?

129

Saya telah mengembangkan aplikasi dasar. Sekarang pada tahap penerapan, menjadi jelas bahwa saya membutuhkan pengaturan lokal dan pengaturan produksi.

Akan sangat menyenangkan mengetahui hal-hal berikut:

  • Cara terbaik menangani pengaturan pengembangan dan produksi.
  • Bagaimana menyimpan aplikasi seperti django-debug-toolbar hanya di lingkungan pengembangan.
  • Kiat dan praktik terbaik lainnya untuk pengaturan pengembangan dan penerapan.
Kristian Roebuck
sumber

Jawaban:

109

The DJANGO_SETTINGS_MODULEvariabel lingkungan kontrol yang pengaturan file Django akan memuat.

Oleh karena itu, Anda membuat file konfigurasi terpisah untuk lingkungan Anda masing-masing (perhatikan bahwa file tersebut tentu saja dapat dari import *file "pengaturan bersama" yang terpisah), dan digunakan DJANGO_SETTINGS_MODULEuntuk mengontrol mana yang akan digunakan.

Begini caranya:

Seperti dicatat dalam dokumentasi Django:

Nilai DJANGO_SETTINGS_MODULE harus dalam sintaks jalur Python, misalnya mysite.settings. Perhatikan bahwa modul pengaturan harus berada di jalur pencarian impor Python.

Jadi, anggaplah Anda membuat myapp/production_settings.pydan myapp/test_settings.pydi repositori sumber Anda.

Dalam hal ini, Anda masing-masing akan mengatur DJANGO_SETTINGS_MODULE=myapp.production_settingsuntuk menggunakan yang pertama dan DJANGO_SETTINGS_MODULE=myapp.test_settingsyang terakhir.


Mulai saat ini, masalahnya bermuara pada pengaturan DJANGO_SETTINGS_MODULEvariabel lingkungan.

Setting DJANGO_SETTINGS_MODULEmenggunakan script atau shell

Anda kemudian dapat menggunakan script bootstrap atau manajer proses untuk memuat pengaturan yang benar (dengan menetapkan lingkungan), atau hanya menjalankannya dari shell Anda sebelum memulai Django: export DJANGO_SETTINGS_MODULE=myapp.production_settings.

Perhatikan bahwa Anda dapat menjalankan ekspor ini kapan saja dari shell - tidak perlu berada di Anda .bashrcatau apa pun.

Pengaturan DJANGO_SETTINGS_MODULEmenggunakan Manajer Proses

Jika Anda tidak suka menulis skrip bootstrap yang mengatur lingkungan (dan ada alasan bagus untuk merasa seperti itu!), Saya akan merekomendasikan menggunakan manajer proses:


Terakhir, perhatikan bahwa Anda dapat memanfaatkan PYTHONPATHvariabel untuk menyimpan pengaturan di lokasi yang sama sekali berbeda (mis. Di server produksi, menyimpannya di /etc/). Ini memungkinkan untuk memisahkan konfigurasi dari file aplikasi. Anda mungkin menginginkannya atau tidak, itu tergantung pada bagaimana aplikasi Anda terstruktur.

Thomas Orozco
sumber
7
Untuk memperjelas, karena settings.pyfile tersebut disimpan SiteName/settings.pysecara default, jika Anda menempatkan file pengaturan alternatif Anda di direktori yang sama, baris yang ditambahkan ke bin / aktifkan akan membaca DJANGO_SETTINGS_MODULE="SiteName.test_settings"Jika tidak, jawaban yang sangat baik!
alexbhandari
2
Secara kebetulan apakah Anda mengetahui tutorial tentang bagaimana melakukan ini selangkah demi selangkah, saya baru mengenal Django dan tidak tahu di mana harus mengatur DJANGO_SETTINGS_MODULE atau PYTHONPATH
Jesus Almaral - Hackaprende
Solusi ini tampaknya tidak berlaku untuk sebuah conda env. Tidak ada bin / aktifkan di conda env.
Pouya Yousefi
1
@PouyaYousefi: Anda sama sekali tidak perlu menggunakan virtualenv untuk menggunakan jawaban ini. Jawabannya benar-benar bermuara pada dua langkah: a) gunakan file pengaturan terpisah dan b) gunakan DJANGO_SETTINGS_MODULEuntuk memilih yang ingin Anda gunakan. Memodifikasi bin/activate adalah salah satu untuk melakukan yang terakhir (TBH, saya tidak lagi berpikir ini adalah ide yang bagus, jadi saya mengeluarkannya), tetapi itu bukan satu-satunya.
Thomas Orozco
Ini juga berguna Jika Anda menggunakan Django dalam edisi komunitas pycharm dan Anda perlu menjalankan pengujian unit pada baris perintah dan komunitas pycharm dengan benar. Asumsikan Anda hanya membuat satu file konfigurasi sederhana di myapp / settings.py di repositori sumber Anda. Dalam hal ini, Anda akan menyetel "DJANGO_SETTINGS_MODULE = myapp.settings" di menu RUN / Edit variabel Konfigurasi / Lingkungan untuk menggunakannya untuk menjalankan kasus uji.
F.Tamy
58

Secara default gunakan pengaturan produksi, tetapi buat file yang disebut settings_dev.pydalam folder yang sama dengan settings.pyfile Anda . Tambahkan penggantian di sana, seperti DEBUG=True.

Di komputer yang akan digunakan untuk pengembangan, tambahkan ini ke ~/.bashrcfile Anda :

export DJANGO_DEVELOPMENT=true

Di bagian bawah settings.pyfile Anda , tambahkan yang berikut ini.

# Override production variables if DJANGO_DEVELOPMENT env variable is set
if os.environ.get('DJANGO_DEVELOPMENT'):
    from settings_dev import *  # or specific overrides

(Perhatikan bahwa mengimpor *umumnya harus dihindari dengan Python)

Secara default, server produksi tidak akan menimpa apa pun. Selesai!

Dibandingkan dengan jawaban lainnya, yang satu ini lebih sederhana karena tidak memerlukan pemutakhiran PYTHONPATH, atau pengaturan DJANGO_SETTINGS_MODULEyang hanya memungkinkan Anda untuk bekerja pada satu proyek django dalam satu waktu.

cs01
sumber
8
bagaimana ini bukan jawaban yang benar? JADI benar-benar berantakan saat ini. Ty cs01
codyc4321
if os.environ.get('DJANGO_DEVELOPMENT', 'true')juga bekerja. Saya menyebutkan ini hanya karena is not truemetode di atas gagal mengimpor untuk saya pada Python 3.6.
brt
1
@brt ini adalah ide yang buruk: ini akan selalu menggunakan DEVpengaturan Anda yang akan membocorkan data pribadi di server publik. Anda benar-benar hanya ingin memeriksa apakah DJANGO_DEVELOPMENTvariabel lingkungan ada (yaitu is not None).
cs01
Terima kasih atas infonya, @ cs01. Saya menyadari saya melakukan sesuatu yang salah ketika saya meledakkan situs saya dengan pemuatan pengaturan yang salah, tetapi saya tidak yakin mengapa settings_dev.pymemuat di server.
brt
2
@ cs01 Saya akan melangkah lebih jauh untuk memastikannya ada dan benar, hanya dengan menyerahkan is not Nonecek. Juga os.getenvmerupakan singkatan
Tjorriemorrie
35

Saya biasanya memiliki satu file pengaturan per lingkungan, dan file pengaturan bersama:

/myproject/
  settings.production.py
  settings.development.py
  shared_settings.py

Setiap file lingkungan saya memiliki:

try:
    from shared_settings import *
except ImportError:
    pass

Ini memungkinkan saya untuk mengganti pengaturan bersama jika perlu (dengan menambahkan modifikasi di bawah bait itu).

Saya kemudian memilih file pengaturan mana yang akan digunakan dengan menghubungkannya ke settings.py:

ln -s settings.development.py settings.py
Daniel Watkins
sumber
2
Bagaimana Anda menangani larangan pep8 import *? Apakah Anda menonaktifkan pemeriksaan itu? Saya telah membungkus impor ini exec()tetapi kemudian saya tidak dapat memiliki persyaratan pada variabel yang tidak ditentukan dalam file ini, saya juga tidak dapat mengubah INSTALLED_APPSvariabel karena "tidak ditentukan"
Mikhail
11
Kami tidak menyaring file pengaturan kami, karena mereka sebenarnya bukan kode sebanyak konfigurasi yang diekspresikan dalam Python.
Daniel Watkins
17

Ini adalah bagaimana saya melakukannya dalam 6 langkah mudah:

  1. Buat folder di dalam direktori proyek Anda dan beri nama settings.

    Struktur proyek:

    myproject/
           myapp1/
           myapp2/              
           myproject/
                  settings/
  2. Buat empat file python bagian dalam settingsdirektori yaitu __init__.py, base.py, dev.pydanprod.py

    File pengaturan:

    settings/
         __init__.py
         base.py
         prod.py
         dev.py 
  3. Buka __init__.pydan isi dengan konten berikut:

    init .py:

    from .base import *
    # you need to set "myproject = 'prod'" as an environment variable
    # in your OS (on which your website is hosted)
    if os.environ['myproject'] == 'prod':
       from .prod import *
    else:
       from .dev import *
  4. Buka base.pydan isi dengan semua pengaturan umum (yang akan digunakan baik dalam produksi maupun pengembangan.) Misalnya:

    base.py:

    import os
    ...
    INSTALLED_APPS = [...]
    MIDDLEWARE = [...]
    TEMPLATES = [{...}]
    ...
    STATIC_URL = '/static/'
    STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
    MEDIA_ROOT = os.path.join(BASE_DIR, '/path/')
    MEDIA_URL = '/path/'
  5. Buka dev.pydan sertakan hal-hal yang khusus untuk pengembangan misalnya:

    dev.py:

    DEBUG = True
    ALLOWED_HOSTS = ['localhost']
    ...
  6. Buka prod.pydan sertakan hal-hal yang khusus produksi misalnya:

    prod.py:

    DEBUG = False
    ALLOWED_HOSTS = ['www.example.com']
    LOGGING = [...]
    ...
Ahtisham
sumber
10

Buat banyak settings*.pyfile, ekstrapolasi variabel yang perlu diubah per lingkungan. Kemudian di akhir settings.pyfile master Anda :

try:
  from settings_dev import *
except ImportError:
  pass

Anda menyimpan settings_*file terpisah untuk setiap tahap.

Di bagian atas settings_dev.pyfile Anda , tambahkan ini:

import sys
globals().update(vars(sys.modules['settings']))

Untuk mengimpor variabel yang perlu Anda ubah.

Entri wiki ini memiliki lebih banyak ide tentang cara membagi pengaturan Anda.

Burhan Khalid
sumber
Terima kasih Burham! Saat menerapkan aplikasi, saya hanya perlu menghapus file settings_dev untuk melihat pengaturan penerapan saya beraksi?
Kristian Roebuck
Ya, atau ganti impor dengansettings_prod.py
Burhan Khalid
1
Mengedit file master settings.py pada penerapan berarti itu akan bentrok dengan kontrol versi, jadi itu belum tentu cara terbaik untuk maju. Saya akan mengatakan bahwa opsi Thomas Orozco adalah yang terbaik - Anda dapat mengatur DJANGO_SETTINGS_MODULE di skrip pascaktivasi virtualenv Anda atau di pengaturan gunicorn atau mod_wsgi Anda
Steve Jalim
1
Mungkin harus disebutkan, bahwa Anda tidak pernah menambahkan kontrol sumber ke file khusus tahap. Saya berasumsi bahwa dipahami bahwa Anda tidak akan memaksakan pengaturan yang khusus untuk tahap proyek.
Burhan Khalid
Jika Anda menggunakan virtualenv, biasanya defaultnya adalah setelan {{project_name}}. Jadi 'pengaturan' tidak akan menjadi kunci di sys.modules. Ini akan menjadi 'myproject.settings' (atau apapun nama proyek Anda). Anda dapat menggunakan modname = "%s.settings" % ".".join(__name__.split('.')[:-1])untuk mendapatkan nama modul lengkap dan kemudian globals().update(vars(sys.modules[modname])). Saya menemukan itu bekerja dengan baik untuk saya. Tentu saja mengabaikan sedikit tentang secara programatik menentukan nama modul yang mendukung string mungkin akan berfungsi dalam banyak kasus juga.
Eric
9

Saya menggunakan konfigurasi-django yang mengagumkan , dan semua pengaturan disimpan di settings.py:

from configurations import Configuration

class Base(Configuration):
    # all the base settings here...
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    ...

class Develop(Base):
    # development settings here...
    DEBUG = True 
    ...

class Production(Base):
    # production settings here...
    DEBUG = False

Untuk mengkonfigurasi proyek Django saya hanya mengikuti dokumen .

Riccardo Leschiutta
sumber
7

Inilah pendekatan yang kami gunakan:

  • sebuah settingsmodul untuk pengaturan dibagi menjadi beberapa file untuk dibaca;
  • sebuah .env.jsonfile toko kredensial dan parameter yang kita ingin dikecualikan dari repositori git kami, atau yang spesifik lingkungan;
  • sebuah env.pyberkas untuk membaca .env.jsonberkas

Mempertimbangkan struktur berikut:

...
.env.json           # the file containing all specific credentials and parameters
.gitignore          # the .gitignore file to exclude `.env.json`
project_name/       # project dir (the one which django-admin.py creates)
  accounts/         # project's apps
    __init__.py
    ...
  ...
  env.py            # the file to load credentials
  settings/
    __init__.py     # main settings file
    database.py     # database conf
    storage.py      # storage conf
    ...
venv                # virtualenv
...

Dengan .env.jsonsuka:

{
    "debug": false,
    "allowed_hosts": ["mydomain.com"],
    "django_secret_key": "my_very_long_secret_key",
    "db_password": "my_db_password",
    "db_name": "my_db_name",
    "db_user": "my_db_user",
    "db_host": "my_db_host",
}

Dan project_name/env.py:

<!-- language: lang-python -->
import json
import os


def get_credentials():
    env_file_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    with open(os.path.join(env_file_dir, '.env.json'), 'r') as f:
        creds = json.loads(f.read())
    return creds


credentials = get_credentials()

Kami dapat memiliki pengaturan berikut:

<!-- language: lang-py -->
# project_name/settings/__init__.py
from project_name.env import credentials
from project_name.settings.database import *
from project_name.settings.storage import *
...

SECRET_KEY = credentials.get('django_secret_key')

DEBUG = credentials.get('debug')

ALLOWED_HOSTS = credentials.get('allowed_hosts', [])

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    ...
]

if DEBUG:
    INSTALLED_APPS += ['debug_toolbar']

...

# project_name/settings/database.py
from project_name.env import credentials

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': credentials.get('db_name', ''),
        'USER': credentials.get('db_user', ''),
        'HOST': credentials.get('db_host', ''),
        'PASSWORD': credentials.get('db_password', ''),
        'PORT': '5432',
    }
}

manfaat dari solusi ini adalah:

  • kredensial dan konfigurasi khusus pengguna untuk pengembangan lokal tanpa mengubah repositori git;
  • konfigurasi khusus lingkungan , Anda dapat memiliki misalnya tiga lingkungan berbeda dengan tiga berbeda .env.jsonseperti dev, stagging dan produksi;
  • kredensial tidak ada di repositori

Saya harap ini membantu, beri tahu saya jika Anda melihat peringatan dengan solusi ini.

Charlesthk
sumber
dengan asumsi di mana envharus mengganti dev, proddll? Apa yang ada di settings.pyfile lama ? Ada apa storage.pydan database.py?
dbinott
Hai @dbinott, Anda dapat dengan mudah memperbarui env.pyfile sehingga Anda dapat memilih, dengan variabel lingkungan, file mana yang akan dimuat
Charlesthk
Misalnya: conf = os.environ.get ('CONF', '') file_ = f ".env. {Conf} .json"
Charlesthk
Mengapa Anda json sebagai lawan dari jenis data python asli?
serangan udara
4

Saya menggunakan struktur file folloring:

project/
   ...
   settings/
   settings/common.py
   settings/local.py
   settings/prod.py
   settings/__init__.py -> local.py

Begitu __init__.pyjuga dengan link (ln di unix atau mklink di windows) ke local.pyatau bisa juga prod.pyagar konfigurasi di project.settingsmodul masih bersih dan teratur, dan jika ingin menggunakan konfigurasi tertentu anda bisa menggunakan variabel environment DJANGO_SETTINGS_MODULEuntukproject.settings.prod jika perlu untuk menjalankan perintah untuk lingkungan produksi.

Di file prod.pydan local.py:

from .shared import *

DATABASE = {
    ...
}

dan shared.pyfile tersebut tetap global tanpa konfigurasi khusus.

Felipe Buccioni
sumber
3

membangun jawaban cs01:

jika Anda mengalami masalah dengan variabel lingkungan, tetapkan nilainya ke string (misalnya saya lakukan DJANGO_DEVELOPMENT="true").

Saya juga mengubah alur kerja file cs01 sebagai berikut:

#settings.py
import os
if os.environ.get('DJANGO_DEVELOPMENT') is not None:
    from settings_dev import * 
else:
    from settings_production import *
#settings_dev.py
development settings go here
#settings_production.py
production settings go here

Dengan cara ini, Django tidak harus membaca keseluruhan berkas pengaturan sebelum menjalankan berkas pengaturan yang sesuai. Solusi ini berguna jika file produksi Anda membutuhkan barang yang hanya ada di server produksi Anda.

Catatan: di Python 3, file yang diimpor perlu .ditambahkan (mis. from .settings_dev import *)

Brian Lee
sumber
1

Jika Anda ingin menyimpan 1 file pengaturan, dan sistem operasi pengembangan Anda berbeda dari sistem operasi produksi Anda, Anda dapat meletakkan ini di bagian bawah settings.py:

from sys import platform
if platform == "linux" or platform == "linux2":
    # linux
    # some special setting here for when I'm on my prod server
elif platform == "darwin":
    # OS X
    # some special setting here for when I'm developing on my mac
elif platform == "win32":
    # Windows...
    # some special setting here for when I'm developing on my pc

Baca lebih lanjut: Bagaimana cara memeriksa sistem operasi dengan Python?

Pengguna
sumber
1

Ini sepertinya telah dijawab, namun metode yang saya gunakan sebagai kombinasi dengan kontrol versi adalah sebagai berikut:

Siapkan file env.py di direktori yang sama dengan pengaturan di lingkungan pengembangan lokal saya yang juga saya tambahkan ke .gitignore:

env.py:

#!usr/bin/python

DJANGO_ENV = True
ALLOWED_HOSTS = ['127.0.0.1', 'dev.mywebsite.com']

.gitignore:

mywebsite/env.py

settings.py:

if os.path.exists(os.getcwd() + '/env.py'):
    #env.py is excluded using the .gitignore file - when moving to production we can automatically set debug mode to off:
    from env import *
else:
    DJANGO_ENV = False

DEBUG = DJANGO_ENV

Saya baru saja menemukan ini berfungsi dan jauh lebih elegan - dengan env.py mudah untuk melihat variabel lingkungan lokal kita dan kita dapat menangani semua ini tanpa beberapa file settings.py atau sejenisnya. Metode ini memungkinkan semua jenis variabel lingkungan lokal untuk digunakan yang tidak ingin kita atur di server produksi kita. Memanfaatkan .gitignore melalui kontrol versi, kami juga menjaga agar semuanya tetap terintegrasi dengan mulus.


sumber
Solusi paling sederhana. Seseorang juga dapat mendefinisikan semua yang ada di Configkelas di dalam env.pyfile. Kemudian alih-alih sebuah import *, modul dapat diimpor oleh from env import Config. Dengan cara ini Anda juga tidak perlu menggunakan if os.pathcheck yang membuat semuanya lebih sederhana.
Siddharth Pant
0

Gunakan settings.pyuntuk produksi. Di direktori yang sama buat settings_dev.pyuntuk menimpa.

# settings_dev.py

from .settings import * 

DEBUG = False

Pada mesin dev jalankan aplikasi Django Anda dengan:

DJANGO_SETTINGS_MODULE=<your_app_name>.settings_dev python3 manage.py runserver

Di mesin prod, jalankan seolah-olah Anda baru saja punya settings.pydan tidak ada yang lain

KEUNTUNGAN

  1. settings.py (digunakan untuk produksi) benar-benar agnostik terhadap fakta bahwa lingkungan lain bahkan ada.
  2. Untuk melihat perbedaan antara prod dan dev Anda hanya melihat ke satu lokasi - settings_dev.py. Tidak perlu mengumpulkan konfigurasi yang tersebar di seluruh settings_prod.py, settings_dev.pydansettings_shared.py .
  3. Jika seseorang menambahkan pengaturan ke konfigurasi prod Anda setelah memecahkan masalah produksi, Anda dapat yakin bahwa itu akan muncul di konfigurasi dev Anda juga (kecuali diganti secara eksplisit). Dengan demikian, perbedaan antara file konfigurasi yang berbeda akan diminimalkan.
Alex Yursha
sumber
0

Untuk masalah pengaturan file, saya memilih untuk menyalin

Project
   |---__init__.py   [ write code to copy setting file from subdir to current dir]
   |---settings.py  (do not commit this file to git)
   |---setting1_dir
   |         |--  settings.py
   |---setting2_dir
   |         |--  settings.py

Ketika Anda menjalankan django, __init__py akan dijalankan. Saat ini, settings.py in setting1_dirakan menggantikansettings.py in Project .

Bagaimana memilih env yang berbeda?

  • memodifikasi __init__.py secara langsung.
  • buat file bash untuk dimodifikasi __init__.py .
  • modifikasi env di linux, dan kemudian biarkan __init__.pymembaca variabel ini.

Mengapa menggunakan cara ini?

Karena saya tidak suka begitu banyak file dalam direktori yang sama, terlalu banyak file akan membingungkan mitra lain dan tidak terlalu baik untuk IDE. (IDE tidak dapat menemukan file apa yang kita gunakan)

Jika Anda tidak ingin melihat semua detail ini, Anda dapat membagi proyek menjadi dua bagian.

  1. buat alat kecil Anda seperti Spring Initializr, hanya untuk menyiapkan proyek Anda. (lakukan seperti menyalin file)
  2. kode proyek Anda
kyakya
sumber
0

Saya menggunakan file app.yaml yang berbeda untuk mengubah konfigurasi antar lingkungan di mesin aplikasi cloud Google.

Anda dapat menggunakan ini untuk membuat koneksi proxy di perintah terminal Anda:

./cloud_sql_proxy -instances=<INSTANCE_CONNECTION_NAME>=tcp:1433

https://cloud.google.com/sql/docs/sqlserver/connect-admin-proxy#macos-64-bit

File: app.yaml

# [START django_app]
service: development
runtime: python37

env_variables:
  DJANGO_DB_HOST: '/cloudsql/myproject:myregion:myinstance'
  DJANGO_DEBUG: True

handlers:
# This configures Google App Engine to serve the files in the app's static
# directory.
- url: /static
  static_dir: static/

# This handler routes all requests not caught above to your main app. It is
# required when static routes are defined, but can be omitted (along with
# the entire handlers section) when there are no static files defined.
- url: /.*
  script: auto
# [END django_app]
Rodrigo Grossi
sumber
-1

Ini adalah solusi saya, dengan lingkungan yang berbeda untuk dev, test dan prod

import socket

[...]

DEV_PC = 'PC059'
host_name = socket.gethostname()

if host_name == DEV_PC:
   #do something
   pass
elif [...]
Massimo Variolo
sumber