Рубрики
Без рубрики

Подгонка приложения Django в один файл

Автор оригинала: Arun Ravindran.

Ранее на этой неделе Энтони, студент французского экономического университета, хотел поговорить со мной через Zoom о моих уроках по трассировщику лучей. Он и его друг были новичками в Python, но после просмотра моих видеороликов были рады реализовать собственный трассировщик лучей. Один из вопросов, который возник в ходе беседы, был: «Можем ли мы поместить все классы в один файл вместо того, чтобы разбивать его на отдельные файлы для каждого класса?». Я сказал: «Конечно», и заметил волну облегчения на их лицах. На самом деле, объяснил я, моя предыдущая реализация была собрана в одном файле, а затем разбита на части для улучшения педагогики.

Но очарование всего проекта в одном файле убедительно. Я помню, как несколько лет назад видел веб-приложение Sinatra, содержащее все приложение и ресурсы, такие как шаблоны HTML и CSS, в одном файле. Представление всех компонентов в одном файле дало полный общий обзор проекта путем простой прокрутки вверх и вниз.

Обычно на этом этапе кто-то предлагает микрофреймворк. Но не все так просто.

Микрофреймворк

Microframeworks использует минималистичный подход, опуская определенные компоненты или направляя вас к нескольким рекомендуемым компонентам. Например, Bottle содержит базовые возможности обработки форм, но не имеет защиты от CSRF или clickjacking .

Таким образом, обычно используется другая библиотека, например bottle-utils-csrf . Это оставляет задачу интеграции разработчику. Это не для крошечных веб-фреймворков. Мне нравится эта идея (особенно «Бутылка», которая, на мой взгляд, очень симпатичная). Но для общедоступных сайтов я предпочитаю безопасность и удобство Django.

Так что у меня возникает соблазн попробовать этот однофайловый трюк в Django. Попробуем сделать нетривиальное веб-приложение с формами, шаблонами и изображениями. Как можно сделать что-то подобное?

Примечание: если вы предпочитаете смотреть видеоверсию, нажмите на видео ниже:

Приложения Django в одном файле

Минимальный

Начнем с малого, создав минимальное приложение Hello World в Django. Некоторым разработчикам Django может показаться забавным, что мы не начнем с команды startproject . На самом деле, для работы Django вовсе не обязательно. Вся эта начальная структура каталогов и такие файлы, как settings.py, предназначены для вашего удобства.

Сначала создайте простой файл с именем app.py со следующим:

import sys

from django.conf import settings
from django.urls import path
from django.http import HttpResponse

settings.configure(
	DEBUGTrue,  # For debugging
	SECRET_KEY"a-bad-secret",  # Insecure! change this
	ROOT_URLCONF__name__,
)


def home(request):
	return HttpResponse("Welcome!")


urlpatterns  [
	path("", home),
]

if __name__  "__main__":
	from django.core.management import execute_from_command_line

	execute_from_command_line(sys.argv)

Да, это все, что вам нужно. Есть некоторые плохие практики, такие как жесткое кодирование секретного ключа (легко исправляемое). Но чистая элегантность всего, что едва ли помещено на экран, весьма полезна.

Команда для запуска этого файла: python app.py runserver 8080

Теперь мы пропустим пару шагов (они есть в видео) и перейдем к простой целевой странице “Скоро в продаже”.

Скоро приложение

Идея страницы, которая скоро появится, состоит в том, чтобы оценить интерес к продукту до того, как он будет выпущен. Такие страницы должны иметь четкий призыв к действию (CTA), например, запрашивать вашу электронную почту. В идеале он должен иметь минимальное трение и при этом собирать всю необходимую информацию.

Посмотрим на мой обновленный app.py:

import os
import sys

from django.conf import settings
from django.urls import path
from django.http import HttpResponse, HttpResponseRedirect
from django.core.wsgi import get_wsgi_application
from django.template import RequestContext, Template
from django import forms

CSV_LIST  "thelist.csv"

settings.configure(
	DEBUG(os.environ.get("DEBUG", "")  "1"),
	ALLOWED_HOSTS["*"],  # Disable host header validation
	ROOT_URLCONF__name__,
	SECRET_KEYos.environ.get("SECRET_KEY", "a-bad-secret"),
	TEMPLATES[{"BACKEND": "django.template.backends.django.DjangoTemplates"}],
	MIDDLEWARE_CLASSES(
    	"django.middleware.common.CommonMiddleware",
    	"django.middleware.csrf.CsrfViewMiddleware",
    	"django.middleware.clickjacking.XFrameOptionsMiddleware",
	),
)


class EnlistForm(forms.Form):
	email  forms.EmailField(
    	requiredTrue,
    	labelFalse,
    	widgetforms.EmailInput(attrs{"placeholder": "Email"}),
	)
	referrer  forms.CharField(requiredFalse, widgetforms.HiddenInput())


def home(request):
	if request.method  "POST":
    	form  EnlistForm(request.POST)
    	if form.is_valid():
        	email  form.cleaned_data["email"]
        	referrer  form.cleaned_data["referrer"]
        	ip  request.META.get("REMOTE_ADDR")
        	print(f"Got email of {email}")
        	with open(CSV_LIST, "a") as csv:
            	csv.write(f"{email},{referrer},{ip}\n")
        	return HttpResponseRedirect("/thanks/")
	else:
    	form  EnlistForm(initial{"referrer": request.META.get("HTTP_REFERER")})
	context  RequestContext(
    	request, {"content": "Sign up for early access", "form": form}
	)
	return HttpResponse(MAIN_HTML.render(context))


def thanks(request):
	context  RequestContext(
    	request,
    	{"content": "Thank you for signing up. We will contact you!", "form": None},
	)
	return HttpResponse(MAIN_HTML.render(context))


urlpatterns  [
	path("", home),
	path("thanks/", thanks),
]

app  get_wsgi_application()


MAIN_HTML  Template(
	"""

  
	Coming Soon | Flying Cars
	
	
  
  
	

All Your Traffic Problems Solved!

Feel the future with affordable levitating cars.

{{ content }} {% if form %}
{% csrf_token %} {{ form.non_field_errors }} {{ form.email.errors }} {{ form.referrer }} {{ form.referrer.errors }} {{ form.email }}
{% endif %}
""" ) if __name__ "__main__": from django.core.management import execute_from_command_line execute_from_command_line(sys.argv)

За исключением отсутствия отдельных файлов, большая часть кода должна быть знакома разработчику Django. Существует большой HTML-шаблон (включая два изображения SVG), встроенный в виде строки.

Обратите внимание, что я не использую ORM здесь. Django, похоже, для этого нуждается в структуре каталогов (если только кто-нибудь из читателей не покажет мне, как это сделать в одном файле).

Надеюсь, это показывает, насколько минимальным может быть Django. Возможно, вы сможете использовать свой любимый фреймворк в тех местах, которые, по вашему мнению, невозможны.