Tutorial: Configurando um ambiente virtual, instalando o Django, criando um aplicativo, configurando uma rota, instalando o CKEditor, criando um modelo e executando migrações no Django

Passo 1: Cria o ambiente virtual

py -m venv venv
.\venv\Scripts\activate
py -m pip install --upgrade pip

Passo 2: Instalar o Django e outras dependências

pip install django django-ckeditor python-slugify Pillow python-dotenv logandprint pymemcache python-decouple

Passo 3: Criar um projeto e um aplicativo

O nome do projeto será project e o nome do aplicativo será website:

django-admin startproject project .
mkdir media
mkdir templates
mkdir static
mkdir static/css
mkdir static/js
mkdir static/img
mkdir static/fonts
mkdir logs
django-admin startapp website

Passo 4: Alterar as configurações do projeto no arquivo project/settings.py

  1. Abra o arquivo project/settings.py e altere o seguinte:
import os
import logandprint
from decouple import config

O código acima irá importar os módulos os, logandprint e o método config da biblioteca decouple para carregar as variáveis de ambiente do arquivo .env. Cada vez que você alterar o arquivo .env será necessário reiniciar o servidor.

DEBUG = config('DEBUG', default=False, cast=bool)
DEBUG=True
ALLOWED_HOSTS=127.0.0.1,website.com
URLSITE=http://127.0.0.1/
ALLOWED_HOSTS = config('ALLOWED_HOSTS').split(',')
INSTALLED_APPS = [
    ...
    'ckeditor',
    'ckeditor_uploader',
    'website',
    ...
]
TEMPLATES = [
    {
        ...
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        ...
    },
]
LANGUAGE_CODE = 'pt-br'
TIME_ZONE = 'America/Sao_Paulo'
USE_L10N = True
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

CKEDITOR_UPLOAD_PATH = 'uploads/'

CKEDITOR_CONFIGS = {
    'default': {
        'toolbar': 'full',
        'height': 300,
        'width': 940,
    },
}

# URL do site com barra no final
URLSITE = config('URLSITE')
log = logandprint
log.setLogFile(os.path.join(BASE_DIR, 'logs/app.log'))
log.debugMode(DEBUG)

Você poderá usar o comando log.write para escrever no console e no arquivo app.log que será criado no diretório app:

log.write('Iniciando o servidor...')

Passo 5: Crie um model para o aplicativo website

  1. Abra o arquivo website/models.py e cria uma classe que conterá a estrutura do modelo:
from django.db import models
from ckeditor.fields import RichTextField
from ckeditor_uploader.fields import RichTextUploadingField
from django.contrib.auth.models import User
from slugify import slugify

# Create your models here.
class Pagina(models.Model):
    titulo = models.CharField(max_length=200)
    slug = models.SlugField(max_length=250, unique=True, null=True, blank=True)
    descricao = models.CharField(max_length=300)
    imagem = models.ImageField(upload_to='uploads/', null=True, blank=True)
    conteudo = RichTextUploadingField()
    anotacoes = models.CharField(max_length=500, blank=True)
    ativa = models.BooleanField(default=True)
    visitas = models.IntegerField(default=0, editable=False)
    data = models.DateTimeField(auto_now_add=True)
    autor = models.ForeignKey(User, on_delete=models.PROTECT, null=True, blank=True)

    def __str__(self):
        return self.titulo

    def save(self, *args, **kwargs):
        if not self.slug:
            self.slug = slugify(self.titulo)
        super().save(*args, **kwargs)
  1. Adicionando o aplicativo website no painel de administração do Django, abra o arquivo website/admin.py e adicione o seguinte código:
from django.contrib import admin

# Register your models here.
from .models import Pagina

admin.site.register(Pagina)

Passo 5: Configurar as rotas

  1. Abra o arquivo project/urls.py e adicione o código abaixo, isso irá configurar o CKEditor e o acesso à pasta media, a linha re_path(r'^ckeditor/', include('ckeditor_uploader.urls')), serve para adicionar as rota do CKEditor e o comando + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) no final da lista urlpatterns serve para adicionar a rota da pasta media:
from django.contrib import admin
from django.urls import path
from django.urls import re_path
from django.urls import include
from django.conf import settings
from django.views.static import serve
from django.conf.urls.static import static

urlpatterns = [
    # Administrador
    path('admin/', admin.site.urls),
    # ckeditor e pasta media
    re_path(r'^ckeditor/', include('ckeditor_uploader.urls')),
    # website
    path('', include('website.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
  1. Criar uma rota para o aplicativo website

Abra/Crie o arquivo website/urls.py e adicione o seguinte código:

from django.urls import path
from . import views

urlpatterns = [
    path('', views.home, name='home'),
]

Passo 6: Criar uma view

  1. Abra/crie o arquivo website/views.py e adicione o seguinte código:
from django.shortcuts import render

def home(request):
    return render(request, 'home.html')
  1. Crie um arquivo chamado home.html no diretório templates e adicione o seguinte código:
<!DOCTYPE html>
<html lang="pt-br">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
  <h1>Home</h1>
</body>
</html>

Passo 7: Execute as migrações, crie um superusuário e execute o servidor

Lembre-se sempre de executar os comandos abaixo dentro do ambiente virtual.

  1. Execute as migrações:
.\venv\Scripts\activate
py manage.py makemigrations website
py manage.py makemigrations
py manage.py migrate
  1. Crie um superusuário:
py manage.py createsuperuser
  1. Execute o servidor:
py manage.py runserver

Agora você já pode acessar o endereço http://127.0.0.1:8000/ para ver a página inicial do seu aplicativo e http://127.0.0.1:8000/admin/ para acessar o painel de administração.

Dica: Alterando um model

Após fazer alterações em um model, para que as alterações sejam aplicadas no banco de dados, é necessário executar o seguinte comando:

py manage.py makemigrations website
py manage.py makemigrations
py manage.py migrate

Super Dica: Automatizando o processo de migrações e execução do servidor

Crie um arqruivo chamado run.ps1 e adicione o seguinte código:

param($arg1, $arg2)

if ($arg1 -eq "help") {
    $helpText = @"
Usage: run.ps1 [command] [port]

Description:
    Start the server and optionally open the site or administration in the browser.

Arguments:
    command: Specify the command to execute.
        open: Open the site and administration in the browser.
        open-site: Open the site in the browser.
        open-admin: Open the administration in the browser.
    port: Port to run the server.

Examples:
    run.ps1 open-site 8000
    run.ps1 8000 open-site

"@
    Write-Host $helpText
    exit
}

Write-Host "`n"
Write-Host "Starting virtual environment" -ForegroundColor Blue
$cmd = ".\venv\Scripts\activate"
Write-Host $cmd
$output = Invoke-Expression $cmd 2>&1
if (!$output) {
    Write-Host "Virtual environment activated" -ForegroundColor Green
} else {
    Write-Host $output
    Write-Host "`nAn error occurred while activating virtual environment`n" -ForegroundColor Red
    exit
}

Write-Host "`n"
Write-Host "Making migrations" -ForegroundColor Blue
$cmd = "py manage.py makemigrations"
Write-Host $cmd
$output = Invoke-Expression $cmd 2>&1
if ($output -match "Traceback") {
    Write-Host $output
    Write-Host "`nAn error occurred while making migrations`n" -ForegroundColor Red
    exit
} else {
    Write-Host $output
    Write-Host "Successfully generated migrations!" -ForegroundColor Green
}

Write-Host "`n"
Write-Host "Migrating" -ForegroundColor Blue
$cmd = "py manage.py migrate"
Write-Host $cmd
$output = Invoke-Expression $cmd 2>&1
if ($output -match "Traceback") {
    Write-Host $output
    Write-Host "`nAn error occurred while migrating`n" -ForegroundColor Red
    exit
} else {
    Write-Host $output
    Write-Host "Migration performed successfully!" -ForegroundColor Green
}

Write-Host "`n"
Write-Host "Checking if there is a superuser" -ForegroundColor Blue
$cmd = "py manage.py shell -c `"from django.contrib.auth.models import User; print(User.objects.filter(is_superuser=True).exists())`""
Write-Host $cmd
$output = Invoke-Expression $cmd 2>&1
if ($output -eq "False") {
    Write-Host "`nCreating superuser`n" -ForegroundColor Green
    $cmd = "py manage.py createsuperuser"
    Write-Host $cmd
    $output = Invoke-Expression $cmd 2>&1
    Write-Host $output
    if ($output -match "Traceback") {
        Write-Host $output
        Write-Host "`nAn error occurred while creating superuser`n" -ForegroundColor Red
        exit
    } else {
        Write-Host $output
        Write-Host "Superuser created successfully!" -ForegroundColor Green
    }
} elseif ($output -match "Traceback") {
    Write-Host $output
    Write-Host "`nAn error occurred while checking if there is a superuser`n" -ForegroundColor Red
    exit
} else {
    Write-Host $output
    Write-Host "Superuser already exists!" -ForegroundColor Green
}

# Dealing with parameters

function IsNumeric($value) {
    return $value -as [int] -is [int]
}

$port = 8000
$command = $null

if ($arg1 -ne $null) {
    if (IsNumeric($arg1)) {
        $port = $arg1
    } else {
        $command = $arg1
    }
}

if ($arg2 -ne $null) {
    if (IsNumeric($arg2)) {
        $port = $arg2
    } else {
        $command = $arg2
    }
}

Write-Host "`n"
if ($command -ne $null) {
    switch ($command) {
        "open" {
            Write-Host "`nOpening site and administration`n" -ForegroundColor Green
            Start-Process "http://127.0.0.1:$port/"
            Start-Process "http://127.0.0.1:$port/admin/"
        }
        "open-site" {
            Write-Host "`nOpening site`n" -ForegroundColor Green
            Start-Process "http://127.0.0.1:$port/"
        }
        "open-admin" {
            Write-Host "`nOpening administration`n" -ForegroundColor Green
            Start-Process "http://127.0.0.1:$port/admin/"
        }
        Default {
            Write-Host "`nUnknown command $command `n" -ForegroundColor Red
        }
    }
}

Write-Host "`n"
Write-Host "Starting server" -ForegroundColor Blue
py manage.py runserver $port

Agora você pode executar o comando .\run.ps1 para executar as migrações e o servidor.