# Django 101
###### tags: `code` `Python` `website`
---
## Reference
:::info
- [Main Reference](https://www.learncodewithmike.com/search/label/Django%E6%95%99%E5%AD%B8%E7%B3%BB%E5%88%97?updated-max=2020-04-16T20:54:00%2B08:00&max-results=20&start=6&by-date=false)
- [Installation](https://www.learncodewithmike.com/2020/03/django-install.html)
- [Django 30 days](https://ithelp.ithome.com.tw/articles/10199515)
:::
---
## Environment Setting

Django integrates many apps into a website architecture
:::success
- "\_\_init\_\_.py": used to represent the directory is a package
- "asgi.py": asynchronous server gateway interface, provide asynchronization related function
- "settings.py": project configuration
- "urls.py": define the url of each app
- "wsgi.py": web server gateway interface, provide the interface between server and Django website
- "manage.py": manage the whole project, e.g. start up local server, connect with database, establish app, etc
:::
### Installation
```shell=
sudo apt-get install python-pip # install package manager first
pip install django # and you can specify the version like "pip install django==3.0.3"
```
### Running
```shell=
django-admin startproject <project> <directory> # e.g. django-admin startproject jojo_project .
python manage.py runserver
```
> if it deosn't work, try instruction "python3 -m django startproject cheese ."
> "python3 manage.py runserver"
- and then access it on local via browser
---
## Main
:::info
- [architecture](https://www.youtube.com/watch?v=u4XIMTOsxJk)
:::
- Django MTV mode

### App Establishment
:::info
- [reference](https://www.learncodewithmike.com/2020/03/django-create-app.html)
:::
:::success
- "migrations": records the procedure of synchronization between database and models.py
- "admin.py": used to define or customize the indication on Django backstage of the app
- "apps.py": the app configuration
- "models.py": define the app field in the database
- "tests.py": automatic testing script
- "views.py": receives the request from browser, after handling, response back to the browser
:::
```shell=
python3 manage.py startapp <app name> # create the app
```
- set "settings.json" in main folder into the following statement
- create new "urls.py" on app "posts" directory
```python=
from django.urls import path
from . import views # import the file "views" from the current directory
urlpatterns = [
path('jojo-test1', views.index, name = "Index")
]
```
- modify "urls.py" in main folder to the following statement
```python=
from django.contrib import admin
from django.urls import path, include # import function "include"
urlpatterns = [
path('admin/', admin.site.urls),
path('posts/', include('posts.urls')) # add the url of new app
]
```
- modify the "views.py" in app folder
```python=
from django.shortcuts import render
from django.http.response import HttpResponse
# Create your views here.
def index(request):
return HttpResponse("jojowei test1")
```
- access the main page
- access the new app page
### Django Migration
:::info
- [reference](https://www.learncodewithmike.com/2020/03/django-model-migration.html)
:::
Django use ORM (Object Relational Mapping) technology to implement the object concept
- to establish the data of attraction, location (one) to post (many)
- modify the "models.py" in app folder to the following statement
```python=
from django.db import models
from django.utils import timezone
# attraction id
class Location(models.Model):
name = models.CharField(max_length=255) # the name of attraction
# the post of attraction
class Post(models.Model):
subject = models.CharField(max_length=255) # title
content = models.CharField(max_length=255) # content
author = models.CharField(max_length=20) # poster
create_date = models.DateField(default=timezone.now) # post time
location = models.ForeignKey(Location, on_delete=models.CASCADE) # the location of attraction
# "on_delete=models.CASCADE" means if attraction is deleted, post will be deleted, too
```
- the field class need to inherit class "Model" to execute CRUD operation
- data type in module "models"
- CharField
- IntegerField
- FloatField
- DateField
- ImageField
- import the directory of the app configuration class in "settings.json" of main folder
```json=
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'posts.apps.PostsConfig'
]
```
- Django ++Migration++, is a file, used to synchronize class in "models.py" and database
- so if we modify "models.py", we have to run the following instruction
```shell=
python3 manage.py makemigrations
```
- we can observe the change on directory "posts/migrations/0001_initial.py"
- after definition, we can synchronize class "models" with the database
```shell=
python3 manage.py migrate
```
- if you want to observe the SQL instruction while migration
```shell=
python3 manage.py sqlmigrate <app name> <file code of migration> # e.g. python3 manage.py sqlmigrate posts 0001
```
### SQLite
a light database, used in few number data environment, and we can check the status via [SQLite Browser](https://sqlitebrowser.org/dl/)
```shell=
sudo apt-get install sqlitebrowser
sqlitebrowser # open the app
```
- and you can watch these field
### Django Administration
- register a super user first
```shell=
python3 manage.py createsuperuser
# user id: jojowei
# mail: lin.xiao.wei60105@gmail.com
# password: wei
```
- enter the administration through "ip addr/admin"
```shell=
python3 manage.py runserver # run the server first
```
- customize the administration via "admin.py" in app folder
- customize the field indication
```python=
from django.contrib import admin
from .models import Location, Post
class LocationAdmin(admin.ModelAdmin): # inherited from class "ModelAdmin"
list_display = ('id', 'name') # method overriding
class PostAdmin(admin.ModelAdmin):
list_display = ('subject', 'content', 'author', 'location')
# as if we don't want the specific field in form list
fields = ('subject', 'content', 'author', 'location') # method overriding
# method 2: "exclude = ('create_date',)"
# register the field to administration
admin.site.register(Location, LocationAdmin) # register inheritance class
admin.site.register(Post, PostAdmin)
```
- modify "models.py" in app folderc to the following statement
```python=
class Location(models.Model):
name = models.CharField(max_length=255)
def __str__(self):
return self.name # magic method overriding
```
### Django Template
:::info
- [reference](https://www.learncodewithmike.com/2020/03/django-template.html)
:::
- open "views.py", and import class "Post" from "models.py"
- select the data we want, and respond template (render()) to "html"
```python=
from django.shortcuts import render
from django.http import HttpResponse
from .models import Post
def index(request):
posts = Post.objects.all() # select all
posts_taichung = Post.objects.filter(location="taichung") # select the specific field object
posts_id1 = Post.objects.get(id=1) # select the specific id object
return render(request, "posts/index.html", {"posts": posts})
```
- build another directory for template to avoid conflict of namespace
- index.html

- you can access the form on browser
### Django Template with Bootstrap
:::info
- [reference](https://www.learncodewithmike.com/2020/03/django-bootstrap.html)
:::
- install package we need
```shell=
pip install requests
```
- [open data from PIXNET API](https://developer.pixnet.pro/#!/doc/pixnetApi/mainpageBlogCategories)
- open "views.py" in app folder
```python=
from django.shortcuts import render
import requests
def index(request):
response = requests.get("https://emma.pixnet.cc/mainpage/blog/categories/hot/28") # 28 is domestic travel
articles = response.json()["articles"] # transfer data into json object, and access "article" field
return render(request, "posts/index.html", {"articles": articles})
```
- define a base template which consists of website name, navbar, etc, and combines them into a page
- create a new directory for base template
- ["base.html" with bootstrap](https://getbootstrap.com/docs/5.1/getting-started/introduction/#starter-template)`, and BootStrap is a popular CSS framework`
```htmlembedded=
<html lang="en">
<head>
<!-- Required meta tags -->
<!-- Bootstrap CSS -->
<link crossorigin="anonymous" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" rel="stylesheet"></link>
<title>NTUST-cheese</title>
</head>
<body>
<div class="container">
{% block content %}
{% endblock %}
</div>
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script crossorigin="anonymous" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" src="https://code.jquery.com/jquery-3.4.1.slim.min.js"></script>
<script crossorigin="anonymous" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"></script>
<script crossorigin="anonymous" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"></script>
</body>
</html>
```
- modify "settings.json" in main folder`remember to import "os"`
```json=
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(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',
],
},
},
]
```
- "index.html" in template folder from app
- extends base template, and it only places block code
- [component --> card](https://getbootstrap.com/docs/4.4/components/card/)
- base on this example

```javascript=
<div class="card" style="width: 18rem;">
<img src="..." class="card-img-top" alt="...">
<div class="card-body">
<h5 class="card-title">Card title</h5>
<p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
<a href="#" class="btn btn-primary">Go somewhere</a>
</div>
</div>
```
- implements bootstrap code on index.html
```htmlembedded=
{% extends 'base.html' %}
{% block content %}
<div class="row">
{% for article in articles %}
<div class="col-lg-4">
<div class="card" style="width: 18rem;">
<img alt="..." class="card-img-top" src="{{ article.thumb }}" />
<div class="card-body">
<h5 class="card-title">{{ article.user.display_name }}</h5>
<p class="card-text">{{ article.title }} . . .</p>
<a class="btn btn-primary" href="{{ article.link }}">content</a>
</div>
</div>
</div>
{% endfor %}
</div>
{% endblock %}
```
- specify the size of images
```htmlembedded=
<img alt="..." class="card-img-top" src="{{ article.thumb }}" style="height: 12rem; width: 18rem;" />
```
- specify the text number of article
```htmlembedded=
<div class="card-text">{{ article.title|slice:"0:25" }} . . .</div>
```
- add spacing between every article list
```htmlembedded=
<div class="card mt-4" style="width: 18rem;"></div>
```
- result
```htmlembedded=
{% extends 'base.html' %}
{% block content %}
<div class="row">
{% for article in articles %}
<div class="col-lg-4">
<div class="card mt-4" style="width: 18rem;">
<img alt="..." class="card-img-top" src="{{ article.thumb }}" style="height: 12rem; width: 18rem;"/>
<div class="card-body">
<h5 class="card-title">{{ article.user.display_name }}</h5>
<p class="card-text">{{ article.title|slice:"0:25" }} . . .</p>
<a class="btn btn-primary" href="{{ article.link }}">content</a>
</div>
</div>
</div>
{% endfor %}
</div>
{% endblock %}
```
### Django ModelForm with CRUD
:::info
- [reference](https://www.learncodewithmike.com/2020/03/django-modelform.html)
- [github](https://github.com/mikeku1116/django-urexpenses)
- [data migration](https://hackmd.io/w7HPnUFiQzqpfARVEH3A9Q?view#Django-Migration)
:::
the theme is bookkeeping website
- open "models.py" in app folder and create data field like this
```python=
from django.db import models
class Expense(models.Model):
name = models.CharField(max_length=255) # name
price = models.IntegerField() # cost
```
```shell=
# remember to update
python3 manage.py makemigrations
python3 manage.py migrate
```
- modify "admin.py" in app folder
```python=
from django.contrib import admin
from .models import Expense
class ExpenseAdmin(admin.ModelAdmin): # inherited from class "ModelAdmin"
list_display = ('name', 'price') # method overriding
# register the field to administration
admin.site.register(Expense, ExpenseAdmin) # register inheritance class
```
- create a file "forms.py" inherited from class ModelForm
```python=
from django import forms
from .models import Expense
class ExpenseModelForm(forms.ModelForm):
class Meta:
model = Expense
# fields = ('name', 'price')
fields = '__all__' # indicates all field characters
# other characters like widgets (apply CSS class of bootstrap's form properties), labels
widgets = {
'name': forms.TextInput(attrs={'class': 'form-control'}),
'price': forms.NumberInput(attrs={'class': 'form-control'})
}
labels = {
'name': 'item',
'price': 'cost'
}
```
- in general, there are two http method, GET and POST, and the default mode is GET
- http method of form with "views.py" in app folder
```python=
from django.shortcuts import render
from .forms import ExpenseModelForm
def index(request):
form = ExpenseModelForm()
context = {
'form': form
}
return render(request, 'expenses/index.html', context)
```
- create a new "index.html" in app templates for "forms.py"
- label "action" in "form" is to send the target URL
- "csrf_token" is Django security mechanism for form authentication
- version 1
```htmlembedded=
{% extends 'base.html' %}
{% block content %}
<form action="" method="POST">
{% csrf_token %}
<div class="form-group">
<div class="form-group col-md-6">
{{ form }}
<input class="btn btn-success" type="submit" value="submission" />
</div>
</div>
</form>
{% endblock %}
```
- version 2 (more flexible)
```htmlembedded=
{% extends 'base.html' %}
{% block content %}
<form action="" method="POST">
{% csrf_token %}
<div class="form-row">
<div class="form-group col-md-6">
<label>{{ form.name.label }}</label>
{{ form.name }}
</div>
<div class="form-group col-md-4">
<label>{{ form.price.label }}</label>
{{ form.price }}
</div>
<div class="form-group col-md-2">
<input class="btn btn-success" style="margin-top: 30px;" type="submit" value="submission" />
</div>
</div>
</form>
{% endblock %}
```
- use Django ModelForm to new data operating
- POST data to database via "views.py" in app folder
- to add data indication below the form on html page
```python=
from django.shortcuts import render, redirect
from .models import Expense
from .forms import ExpenseModelForm
def index(request):
expenses = Expense.objects.all() # query the all datas
form = ExpenseModelForm()
if request.method == "POST":
form = ExpenseModelForm(request.POST)
if form.is_valid(): # check whether the form is valid or not
form.save()
# return redirect("/posts/jojo-test1") # redirect to specific page
context = {
'expenses': expenses,
'form': form
}
return render(request, 'expenses/index.html', context)
```
- back to "index.html" in "expenses" template, new a function of all data indication
```htmlembedded=
{% extends 'base.html' %}
{% block content %}
<form action="" method="POST">
{% csrf_token %}
<div class="form-row">
<div class="form-group col-md-6">
<label>{{ form.name.label }}</label>
{{ form.name }}
</div>
<div class="form-group col-md-4">
<label>{{ form.price.label }}</label>
{{ form.price }}
</div>
<div class="form-group col-md-2">
<input type="submit" class="btn btn-success" style="margin-top:30px;" value="submission">
</div>
</div>
</form>
<table class="table table-bordered table-striped">
<thead class="thead-dark">
<tr>
<th>item</th>
<th>cost</th>
<th></th>
</tr>
</thead>
<tbody>
{% for expense in expenses %}
<tr>
<td>{{ expense.name }}</td>
<td>{{ expense.price }}</td>
<td>
<a href="#" class="btn btn-info">modification</a>
<a href="#" class="btn btn-danger">deletion</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
```
- Django URL Reference
- when we modify the data, we must know the primary key(PK) of data, and transmit PK to "view function" via URL
- modify "urls.py" in app folder
- define the data type first, and then naming after the colon
```python=
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='Index'),
path('update/<str:pk>', views.update, name='Update'),
path('delete/<str:pk>', views.delete, name='Delete')
]
```
- modify "urls.py" in main folder to the following statement
```python=
from django.contrib import admin
from django.urls import path, include # import function "include"
urlpatterns = [
path('admin/', admin.site.urls),
path('expenses/', include('posts.urls')) # add the url of new app
]
```
- back to "expenses" template index.html
- specify the URL name via Django url template syntax, according to urls.py and corresponding to specific view function
- modify ++the buttons++ to the following statement
```htmlembedded=
<a href="{% url 'Update' expense.id %}" class="btn btn-info">modification</a>
<a href="{% url 'Delete' expense.id %}" class="btn btn-danger">deletion</a>
```
- create a new view function "update" and "delete" at "views.py" in app folder
```python=
def update(request, pk):
expense = Expense.objects.get(id=pk)
form = ExpenseModelForm(instance=expense) # sepcify the "keyword argument" in Django ModelForm instance to get the form data object to initiate the form
if request.method == 'POST':
form = ExpenseModelForm(request.POST, instance=expense)
if form.is_valid():
form.save()
return redirect('/expenses') # refirect the page
context = {
'form': form
}
return render(request, 'expenses/update.html', context)
def delete(request, pk):
expense = Expense.objects.get(id=pk)
if request.method == "POST":
expense.delete()
return redirect('/expenses') # back to main page
context = {
'expense': expense
}
return render(request, 'expenses/delete.html', context)
```
- new a "update.html" in app templates
```htmlembedded=
{% extends 'base.html' %}
{% block content %}
<form action="" method="POST">
{% csrf_token %}
<div class="form-group">
<div class="form-group col-md-6">
{{ form }}
<input class="btn btn-success" type="submit" value="update" />
</div>
</div>
</form>
{% endblock %}
```
- new a "delete.html" in app templates
```htmlembedded=
{% extends 'base.html' %}
{% block content %}
<h3>ensure that delete {{ expense.name }}?</h3>
<form action="" method="POST">
{% csrf_token %}
<input class="btn btn-success" type="submit" value="Yes" />
<a class="btn btn-warning" href="{% url 'Index' %}">Cancel</a>
</form>
{% endblock %}
```
- access it at "127.0.0.1:8000/expenses"
### Django UserCreationForm (for register)
:::info
- [reference](https://www.learncodewithmike.com/2020/04/django-authentication-and-usercreationform.html)
:::
- actually, "UserCreationForm" related models are established defaultly, and we can use it to implement register function
- "views.py" in app folder
```python=
from django.shortcuts import render
from django.contrib.auth.forms import UserCreationForm
# main page
def index(request):
return render(request, 'accounts/index.html')
# register
def sign_up(request):
form = UserCreationForm()
context = {
'form': form
}
return render(request, 'accounts/register.html', context)
```
- "index.html" in new templates "account" in app folder
```htmlembedded=
<!-- for test -->
{% extends 'base.html' %}
{% block content %}
<div class="jumbotron mt-3">
<h1>Django AuthDev HomPage</h1>
<p class="lead">This example is a quick demo to illustrate how django authentication works.</p>
<a class="btn btn-lg btn-primary" href="{% url 'Logout' %}" role="button">logout »</a>
</div>
{% endblock %}
```
- "register.html” in new templates “account” in app folder
```htmlembedded=
{% extends 'base.html' %}
{% block content %}
<!-- main screen -->
<h1>AuthDev</h1>
<div class="jumbotron mt-3">
<h3>Register</h3>
<form action="" method="POST">
{% csrf_token %}
{{ form }}
<br/>
<input class="btn btn-success" type="submit" value="submit" />
</form>
</div>
{% endblock %}
```
- modify "urls.py" in main folder to the following statement
```python=
from django.contrib import admin
from django.urls import path, include # import function "include"
urlpatterns = [
path('admin/', admin.site.urls),
path('accounts/', include('posts.urls')) # add the url of new app
]
```
- modify "urls.py" in app folder to the following statement
```python=
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='Index'),
path('register', views.sign_up, name='Register')
]
```
- outcome
- all of the forms are "Django UserCreationForm" built-in indication
- there are many verification message, they will dispear when we customize "UserCreationForm"
- customize "Django UserCreationForm"
- "forms.py" in app folder
```python=
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
class RegisterForm(UserCreationForm):
username = forms.CharField(
label="Account",
widget=forms.TextInput(attrs={'class': 'form-control'})
)
email = forms.EmailField(
label="GMail",
widget=forms.EmailInput(attrs={'class': 'form-control'})
)
password1 = forms.CharField(
label="Password",
widget=forms.PasswordInput(attrs={'class': 'form-control'})
)
password2 = forms.CharField(
label="Password Assurance",
widget=forms.PasswordInput(attrs={'class': 'form-control'})
)
class Meta:
model = User
fields = ('username', 'email', 'password1', 'password2')
```
- "views.py" in app folder
```python=
from django.shortcuts import render, redirect
from django.contrib.auth.forms import UserCreationForm
from .forms import RegisterForm
# main page
def index(request):
return render(request, 'accounts/index.html')
# register
def sign_up(request):
form = RegisterForm()
if request.method == "POST":
form = RegisterForm(request.POST)
if form.is_valid():
form.save()
redirect('/accounts/') # redirect page
context = {
'form': form
}
return render(request, 'accounts/register.html', context)
```
- outcome

- use "Django Form" to implement login function
- comparison
- ModelForm needs data model
- Form is regular form, don't need to create data model
- "forms.py" in app folder
```python=
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
class RegisterForm(UserCreationForm):
username = forms.CharField(
label="Account",
widget=forms.TextInput(attrs={'class': 'form-control'})
)
email = forms.EmailField(
label="GMail",
widget=forms.EmailInput(attrs={'class': 'form-control'})
)
password1 = forms.CharField(
label="Password",
widget=forms.PasswordInput(attrs={'class': 'form-control'})
)
password2 = forms.CharField(
label="Password Assurance",
widget=forms.PasswordInput(attrs={'class': 'form-control'})
)
class Meta:
model = User
fields = ('username', 'email', 'password1', 'password2')
class LoginForm(forms.Form):
username = forms.CharField(
label="Account",
widget=forms.TextInput(attrs={'class': 'form-control'})
)
password = forms.CharField(
label="Password",
widget=forms.PasswordInput(attrs={'class': 'form-control'})
)
```
- "views.py" in app folder
- if we want to implement "login_required", we must [clear the cookie first](https://stackoverflow.com/questions/26698154/django-login-required-not-redirecting)
```python=
from django.shortcuts import render, redirect
from django.contrib.auth.forms import UserCreationForm
from .forms import RegisterForm
from .forms import LoginForm
# for authentication
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required
# main page with authentication
@login_required(login_url="Login")
def index(request):
return render(request, 'accounts/index.html')
# register
def sign_up(request):
form = RegisterForm()
if request.method == "POST":
form = RegisterForm(request.POST)
if form.is_valid():
form.save()
return redirect('/accounts/login') # redirect page
context = {
'form': form
}
return render(request, 'accounts/register.html', context)
# log in
def sign_in(request):
form = LoginForm()
# user authentication
if request.method == "POST":
username = request.POST.get("username")
password = request.POST.get("password")
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
return redirect('/accounts') # redirect to main page
context = {
'form': form
}
return render(request, 'accounts/login.html', context)
# log out
def log_out(request):
logout(request)
return redirect('/accounts/login') # redirect to login page
```
- "login.html" in app template
```python=
{% extends 'base.html' %}
{% block content %}
<h1>AuthDev</h1>
<h3>Login</h3>
<div class="jumbotron bg-secondary text-white">
<form action="" method="POST">
{% csrf_token %}
{{ form }}
<br>
<input class="btn btn-dark btn-block" type="submit" value="login" />
<p>Do not have an account yet? <a href="{% url 'Register' %}" style="color:white;">Register</a></p>
</form>
</div>
{% endblock %}
```
- "urls.py" in app folder
```python=
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='Index'),
path('register', views.sign_up, name='Register'),
path('login', views.sign_in, name='Login'),
path('logout', views.log_out, name='Logout')
]
```
---
## Django on Heroku
:::info
- [reference](https://www.learncodewithmike.com/2020/04/django-heroku.html)
- [debug 1](https://www.zoearthmoon.net/blog/program/item/2592.html)
- [debug 2](https://segmentfault.com/q/1010000010016708)
- [fast deployment](https://blog.typeart.cc/%E4%BD%88%E7%BD%B2django%E5%88%B0heroku/)
- [official document](https://devcenter.heroku.com/articles/django-app-configuration)
:::
- [sign up first](https://dashboard.heroku.com/)
- [install Heroku CLI](https://devcenter.heroku.com/articles/heroku-cli)
- install git tool
- install "gunicorn" package
```shell=
pip install gunicorn
```
- create file "runtime.txt"
```shell=
python-3.8.10
```
- create file "requirements.txt" to place the required package
```python=
django_heroku
django
gunicorn
whitenoise
dj_database_url
requests
```
- or use this command to solve
```shell=
pip freeze > requirements.txt
```
- create file "Procfile" in project directory
- like this statement
```shell=
web: gunicorn <project name>.wsgi
```
- there are some static file like "javascript", "CSS", images needed to be deployed, so we need to create a "static" folder to place the static file
- create "static" folder
- new the following statement in "settings.py" in main folder
```python=
import django_heroku # the top of the file
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
django_heroku.settings(locals()) # the bottom of the file
```
- run this instruction to collect static file
```python=
python manage.py collectstatic
```
- install "whitenoise" to deploy static file
```shell=
pip install whitenoise
```
- add "WhiteNoiseMiddleware" statement into "settings.py" in main folder and folloew the statement below
```python=
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware',
'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',
]
```
- and then start deploying via Heroku CLI
```shell=
heroku login # connect with remote
heroku create <app_name> # create the app on heroku
```
- add the URL configuration to "settings.py" in main folder
```python=
ALLOWED_HOSTS = [
'ntust-cheese-login.herokuapp.com/'
]
```
- go to main directory
```shell=
git init
git add . # if there is any modification, just implement from this step
git commit -m "message"
heroku buildpacks:set heroku/python # select default language
heroku git:remote -a <app_name> # switch Heroku Git Repo
git push heroku master # push to Heroku Git Repo
heroku ps:scale web=1 # set the number of host
heroku open # open the website
heroku logs --tail # check out the logs
```
- [finally, remember to add super user and migrate](https://www.itread01.com/content/1546240897.html)
```shell=
heroku run python manage.py makemigrations
heroku run python manage.py migrate
heroku run python manage.py createsuperuser
# user: jojowei
# mail: lin.xiao.wei60105@gmail.com
# password: wei
```
---
## Issue
:::danger
:::