Marek Gibney

Web App From Scratch

I think it would be nice to have an overview of how to get from zero to a working web application via all the popular frameworks like Django, Flask, Laravel, Symfony ...

The idea is to have a self explanatory shell script for each framework, which turns a fresh Debian installation into a running web application with routing, templates and user accounts.

The reason for the shell script format is that often when I read documentations or tutorials about a technology, I wish it was just a list of commands and not a textual description which tells you which programs to open, which files to edit, where to save them etc.

I set up a repo for the scripts here .

Below is the Django script, nicely colorized:

# ====================== # From Debian to Web App # ====================== # This page contains a list of terminal commands that # create a Django web application with routing, templates # and user accounts. # # You can start from a fresh debian installation. Or with a # fresh debian container: # # docker run -v $(pwd):/var/www --rm -it -p 80:80 debian:11-slim # # You can copy+paste each command to see the application take # shape or copy the whole page and paste it in one go. # ====================== # Let's configure Debian # ====================== # Do not show dialogs during the upgrade export DEBIAN_FRONTEND=noninteractive # Update the packages apt update -y && apt upgrade -y # ==================== # Let's install Django # ==================== cd /var/www apt install -y python3-django django-admin startproject mysite cd mysite python3 manage.py migrate # ==================== # Let's install Apache # ==================== apt install -y apache2 apt install -y libapache2-mod-wsgi-py3 cat << 'EOF' > /etc/apache2/sites-enabled/000-default.conf ServerName mysite.local WSGIPythonPath /var/www/mysite <VirtualHost *:80> WSGIScriptAlias / /var/www/mysite/mysite/wsgi.py <Directory /var/www/mysite/mysite> <Files wsgi.py> Require all granted </Files> </Directory> </VirtualHost>
EOF
service apache2 start # Yay, we have a working Django instance! read -p 'Django is live at 127.0.0.1! Hit enter to continue.' # =================== # Let's use templates # =================== # mysite/ in mysite/ is the code dir in Django cd mysite mkdir templates cat << 'EOF' > templates/index.html <h1>Hello World</h1>
EOF
cat << 'EOF' > views.py from django.shortcuts import render def index(request): return render(request, 'index.html')
EOF
cat << 'EOF' > urls.py from django.contrib import admin from django.urls import path from . import views urlpatterns = [ path('admin/', admin.site.urls), path('', views.index, name='index'), ]
EOF
cat << 'EOF' >> settings.py INSTALLED_APPS += ['mysite']
EOF
service apache2 restart # Yay, we have static site! read -p 'Serving a static site! Hit enter to continue.' # ========================= # Let's use a base template # ========================= # Let's create a base template cat << 'EOF' > templates/base.html <!DOCTYPE html> <html> <head> <title>Hello World</title> <style> body {background: #60a060} </style> </head> <body>{% block content %}{% endblock %}</body> </html>
EOF
# And use it for the index page: cat << 'EOF' > templates/index.html {% extends "base.html" %} {% block content %} <h1>Hello World</h1> {% endblock %}
EOF
service apache2 restart # Yay, we have a working base template! read -p 'The base template is live! Hit enter to continue.' # ======================= # Let's add user accounts # ======================= cd .. # Create a new app called User for Auth django-admin startapp user cat << 'EOF' >> mysite/settings.py INSTALLED_APPS += ['user']
EOF
mkdir mysite/templates/user # Apply Auth model migrations to db python3 manage.py makemigrations python3 manage.py migrate # Create a User Registration Form # Extends the UserCreationForm cat << 'EOF' > user/forms.py from django import forms from django.contrib.auth.models import User from django.contrib.auth.forms import UserCreationForm class UserRegisterForm(UserCreationForm): email = forms.EmailField() class Meta: model= User fields = ['username', 'email', 'password1', 'password2']
EOF
# Create some basic views for registration cat << 'EOF' > user/views.py from django.shortcuts import render, redirect from .forms import UserRegisterForm def index(request): return render(request, 'user/index.html') def register(request): if request.method == 'POST': form = UserRegisterForm(request.POST) if form.is_valid(): form.save() username = form.cleaned_data.get('username') return redirect('login') else: form = UserRegisterForm() return render(request, 'user/register.html', {'form': form})
EOF
# Create the URL mappings of Auth cat << 'EOF' > user/urls.py from django.urls import path, include from django.contrib.auth import views as auth_views from user import views as user_views urlpatterns = [ path('', user_views.index, name='auth'), path('register/', user_views.register, name='register'), path('login/', auth_views.LoginView.as_view(template_name='user/login.html'), name='login'), path('logout/',auth_views.LogoutView.as_view(template_name='user/logout.html'), name='logout'), ]
EOF
cat << 'EOF' > mysite/urls.py from django.contrib import admin from django.urls import path, include from . import views urlpatterns = [ path('admin/', admin.site.urls), path('', views.index, name='index'), path('auth/', include('user.urls')), ]
EOF
# Create Templates for Authorization cat << 'EOF' > mysite/templates/user/index.html {% extends 'base.html' %} {% block content %} <a href="{% url 'register' %}"><button>Register</button></a> <a href="{% url 'login' %}"><button>Login</button></a> {% endblock %}
EOF
cat << 'EOF' > mysite/templates/user/register.html {% extends 'base.html' %} {% block content %} <form method="POST"> {% csrf_token %} {{ form.as_p }} <button type="submit">Sign Up</button> </form> <p> Already have an Account? <a href="{% url 'login' %}"><button>Log In</button></a> </p> {% endblock %}
EOF
cat << 'EOF' > mysite/templates/user/login.html {% extends 'base.html' %} {% block content %} <form method="POST"> {% csrf_token %} {{ form.as_p }} <button type="submit">Log In</button> </form> <p> Don't have an Account? <a href="{% url 'register' %}"><button>Register</button></a> </p> {% endblock %}
EOF
cat << 'EOF' > mysite/templates/user/logout.html {% extends 'base.html' %} {% block content %} <p> Don't have an account? <a href="{% url 'register' %}"><button>Register</button></a> </p> <p> Already have an Account?<a href="{% url 'login' %}"><button>Login</button></a> </p> {% endblock %}
EOF
# Create a Login redirect URL route cat << 'EOF' >> mysite/settings.py LOGIN_REDIRECT_URL = 'index'
EOF
cat << 'EOF' > mysite/templates/index.html {% extends "base.html" %} {% block content %} {% if user.is_authenticated %} <h1>Hello, {{ user.username }}!</h1> <h3>You are logged in as {{ user.username }} </h3> <a href="{% url 'logout' %}"><button>Logout</button></a> {% else %} <h1>Hello, World!</h1> <a href="{% url 'auth' %}"><button>Authorize</button></a> {% endif %} {% endblock %}
EOF
chown www-data:www-data . chown www-data:www-data db.sqlite3 service apache2 restart # Yay, we have user accounts! read -p 'User accounts are live! Hit enter to continue.'

Last update: 2022-11-23