πŸπŸš€ ПишСм Π³ΠΈΠ±Ρ€ΠΈΠ΄Π½ΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ для хранСния Π·Π°ΠΌΠ΅Ρ‚ΠΎΠΊ Π½Π° Django, Django Ninja REST Framework ΠΈ Alpine.js

Π˜Π·ΡƒΡ‡Π°Π΅ΠΌ основныС возмоТности Django Ninja, Alpine.js ΠΈ Axios Π² процСссС создания Π²Π΅Π±-прилоТСния для хранСния Π·Π°ΠΌΠ΅Ρ‚ΠΎΠΊ.

Π Π°Π½ΠΎ ΠΈΠ»ΠΈ ΠΏΠΎΠ·Π΄Π½ΠΎ любой Π½Π°Ρ‡ΠΈΠ½Π°ΡŽΡ‰ΠΈΠΉ Django-Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ сталкиваСтся с ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ΠΎΠΌ, для ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ Π½ΡƒΠΆΠ½ΠΎ Ρ‡Π΅Ρ‚ΠΊΠΎΠ΅ Ρ€Π°Π·Π΄Π΅Π»Π΅Π½ΠΈΠ΅ прилоТСния Π½Π° бэкСнд ΠΈ Ρ„Ρ€ΠΎΠ½Ρ‚Π΅Π½Π΄: Π² этом случаС ΡΠ΅Ρ€Π²Π΅Ρ€Π½ΡƒΡŽ Ρ‡Π°ΡΡ‚ΡŒ ΠΏΠΈΡˆΡƒΡ‚ Π½Π° Django REST Framework (DRF) ΠΈΠ»ΠΈ FastAPI, Π° ΠΊΠ»ΠΈΠ΅Π½Ρ‚ΡΠΊΡƒΡŽ – Π½Π° React, Angular ΠΈΠ»ΠΈ Vue. Если Ρ€Π΅Ρ‡ΡŒ ΠΈΠ΄Π΅Ρ‚ ΠΎ высоконагруТСнном сайтС со мноТСством ΠΈΠ½Ρ‚Π΅Ρ€Π°ΠΊΡ‚ΠΈΠ²Π½Ρ‹Ρ… элСмСнтов Π½Π° сторонС ΠΊΠ»ΠΈΠ΅Π½Ρ‚Π° – Ρ‚Π°ΠΊΠΎΠΉ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ Π½Π΅ΠΈΠ·Π±Π΅ΠΆΠ΅Π½. ΠŸΡ€ΠΈ этом Π·Π½Π°Ρ‡ΠΈΡ‚Π΅Π»ΡŒΠ½ΡƒΡŽ Ρ‡Π°ΡΡ‚ΡŒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ, ΠΊΠΎΡ‚ΠΎΡ€ΡƒΡŽ Django прСдоставляСт ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ, придСтся Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π½Π° сторонС Ρ„Ρ€ΠΎΠ½Ρ‚Π΅Π½Π΄Π° – ΠΈ это Π±ΡƒΠ΄Π΅Ρ‚ Π³ΠΎΡ€Π°Π·Π΄ΠΎ слоТнСС.

Но Ссли Π½Π°Π³Ρ€ΡƒΠ·ΠΊΠ° Π½Π° ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ ΡƒΠΌΠ΅Ρ€Π΅Π½Π½ΠΎΠΉ, Π° идСя раздСлСния Π½Π° Ρ„Ρ€ΠΎΠ½Ρ‚Π΅Π½Π΄ ΠΈ бэкСнд Π²ΠΎΠ·Π½ΠΈΠΊΠ»Π° ΠΈΠ·-Π·Π° нСобходимости Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ взаимодСйствиС с Π±Π°Π·ΠΎΠΉ Π΄Π°Π½Π½Ρ‹Ρ… Π±Π΅Π· постоянных ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠΉ страниц – Ρ‚ΠΎ Ρ‚Π°ΠΊΠΎΠΉ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ цСлСсообразнСС Π²ΠΎΠΏΠ»ΠΎΡ‚ΠΈΡ‚ΡŒ Π² Π²ΠΈΠ΄Π΅ Π³ΠΈΠ±Ρ€ΠΈΠ΄Π½ΠΎΠ³ΠΎ прилоТСния. Π“ΠΈΠ±Ρ€ΠΈΠ΄Π½Ρ‹ΠΉ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ позволяСт:

  • максимально ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Β«Π±Π°Ρ‚Π°Ρ€Π΅ΠΉΠΊΠΈΒ» Django – Π² Ρ‚ΠΎΠΌ числС Ρ„ΠΎΡ€ΠΌΡ‹, систСму Π°ΡƒΡ‚Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΈ ΠΈ Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·Π°Ρ†ΠΈΠΈ;
  • Ρ€Π΅Π°Π»ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π°ΡΠΈΠ½Ρ…Ρ€ΠΎΠ½Π½ΡƒΡŽ ΠΏΠ΅Ρ€Π΅Π΄Π°Ρ‡Ρƒ Π΄Π°Π½Π½Ρ‹Ρ… ΠΈ CRUD Π±Π΅Π· ΠΏΠ΅Ρ€Π΅Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ страниц;
  • Π²ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ Π² ΡˆΠ°Π±Π»ΠΎΠ½Ρ‹ Π”ΠΆΠ°Π½Π³ΠΎ Π»ΡŽΠ±Ρ‹Π΅ ΠΈΠ½Ρ‚Π΅Ρ€Π°ΠΊΡ‚ΠΈΠ²Π½Ρ‹Π΅ JS-элСмСнты.

ΠžΠ±Π·ΠΎΡ€ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°

Главная страница Notes – ΠΊΠ°Ρ‚Π΅Π³ΠΎΡ€ΠΈΠΈ Π·Π°ΠΌΠ΅Ρ‚ΠΎΠΊ

ΠœΡ‹ создадим Π³ΠΈΠ±Ρ€ΠΈΠ΄Π½ΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Notes, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ опираСтся Π½Π° Π±Π°Π·ΠΎΠ²ΡƒΡŽ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ Django. Помимо Π”ΠΆΠ°Π½Π³ΠΎ, ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π±ΡƒΠ΄Π΅Ρ‚ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ:

  • Π€Ρ€Π΅ΠΉΠΌΠ²ΠΎΡ€ΠΊ Django Ninja для API ΠΈ CRUD.
  • Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΡƒ Axios – для HTTP-запросов ΠΊ бэкСнду.
  • Π£Π»ΡŒΡ‚Ρ€Π°Π»Π΅Π³ΠΊΠΈΠΉ JS-Ρ„Ρ€Π΅ΠΉΠΌΠ²ΠΎΡ€ΠΊ Alpine.js ΠΈ CSS-Ρ„Ρ€Π΅ΠΉΠΌΠ²ΠΎΡ€ΠΊ Bootstrap – для Ρ„Ρ€ΠΎΠ½Ρ‚Π΅Π½Π΄Π°.
Π—Π°ΠΌΠ΅Ρ‚ΠΊΠΈ Π² ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎΠΉ ΠΊΠ°Ρ‚Π΅Π³ΠΎΡ€ΠΈΠΈ

ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ ΠΎΠ΄ΠΈΠ½ Π±Π°Π·ΠΎΠ²Ρ‹ΠΉ ΠΈ Π΄Π²Π° Π³ΠΈΠ±Ρ€ΠΈΠ΄Π½Ρ‹Ρ… шаблона Django/Alpine.js:

  • base.html – ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΡƒ Axios, Π° Ρ‚Π°ΠΊΠΆΠ΅ Ρ„Ρ€Π΅ΠΉΠΌΠ²ΠΎΡ€ΠΊΠΈ Alpine.js ΠΈ Bootstrap.
  • index.html – Π²Ρ‹Π²ΠΎΠ΄ΠΈΡ‚ всС ΠΊΠ°Ρ‚Π΅Π³ΠΎΡ€ΠΈΠΈ Π·Π°ΠΌΠ΅Ρ‚ΠΎΠΊ. ΠšΠ°Ρ€Ρ‚ΠΎΡ‡ΠΊΠΈ ΠΊΠ°Ρ‚Π΅Π³ΠΎΡ€ΠΈΠΉ Π΄ΠΎΠ±Π°Π²Π»ΡΡŽΡ‚ΡΡ ΠΈ ΡƒΠ΄Π°Π»ΡΡŽΡ‚ΡΡ Π±Π΅Π· ΠΏΠ΅Ρ€Π΅Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ страницы.
  • detail.html – ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ°Π΅Ρ‚ всС Π·Π°ΠΌΠ΅Ρ‚ΠΊΠΈ Π² ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½ΠΎΠΉ ΠΊΠ°Ρ‚Π΅Π³ΠΎΡ€ΠΈΠΈ. ΠšΠ°Ρ€Ρ‚ΠΎΡ‡ΠΊΠΈ Π·Π°ΠΌΠ΅Ρ‚ΠΎΠΊ Π΄ΠΎΠ±Π°Π²Π»ΡΡŽΡ‚ΡΡ ΠΈ ΡƒΠ΄Π°Π»ΡΡŽΡ‚ΡΡ Π±Π΅Π· ΠΏΠ΅Ρ€Π΅Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ, Ρ‚Π°ΠΊΠΈΠΌ ΠΆΠ΅ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ происходит ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ статуса Π’ процСссС Π½Π° Π‘Π΄Π΅Π»Π°Π½ΠΎ.

Π’Π΅ΡΡŒ ΠΊΠΎΠ΄ для ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° находится Π² Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΈ.

Π‘ΠΎΠ»ΡŒΡˆΠ΅ ΠΏΠΎΠ»Π΅Π·Π½Ρ‹Ρ… ΠΌΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π»ΠΎΠ² Π²Ρ‹ Π½Π°ΠΉΠ΄Π΅Ρ‚Π΅ Π½Π° нашСм Ρ‚Π΅Π»Π΅Π³Ρ€Π°ΠΌ-ΠΊΠ°Π½Π°Π»Π΅ Β«Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° питониста»

БэкСнд ΠΈ API

Для Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ API ΠΌΡ‹ Π²ΠΎΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡΡ Π½ΠΎΠ²Ρ‹ΠΌ Ρ„Ρ€Π΅ΠΉΠΌΠ²ΠΎΡ€ΠΊΠΎΠΌ Django Ninja. Π­Ρ‚ΠΎ отличная Π°Π»ΡŒΡ‚Π΅Ρ€Π½Π°Ρ‚ΠΈΠ²Π° Django REST Framework ΠΈ FastAPI, ΠΏΡ€ΠΈΡ‡Π΅ΠΌ ΠΏΠΎ синтаксису Django Ninja Π±Π»ΠΈΠΆΠ΅ ΠΊ послСднСму. Django Ninja Π³ΠΎΡ€Π°Π·Π΄ΠΎ ΠΏΡ€ΠΎΡ‰Π΅ DRF ΠΈ Π½Π°ΠΌΠ½ΠΎΠ³ΠΎ ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½Π΅Π΅.

ВСст ΠΏΡ€ΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ Django Ninja

ЕдинствСнный нСдостаток Django Ninja – ΠΏΠΎΠΊΠ° Ρ‡Ρ‚ΠΎ Ρ„Ρ€Π΅ΠΉΠΌΠ²ΠΎΡ€ΠΊ Π½Π΅ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅Ρ‚ прСдставлСния Π½Π° основС классов, ΠΈ ΠΊΠΎΠ΄ получаСтся довольно ΠΎΠ±ΡŠΠ΅ΠΌΠ½Ρ‹ΠΌ (ΠΏΠΎ ΡΡ€Π°Π²Π½Π΅Π½ΠΈΡŽ с DRF), Π½ΠΎ Π² блиТайшСС врСмя Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΈ ΠΎΠ±Π΅Ρ‰Π°ΡŽΡ‚ Ρ€Π΅ΡˆΠΈΡ‚ΡŒ эту Π·Π°Π΄Π°Ρ‡Ρƒ.

НачнСм Ρ€Π°Π±ΠΎΡ‚Ρƒ с создания Π½ΠΎΠ²ΠΎΠ³ΠΎ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° ΠΈ прилоТСния:

python -m venv Notes\venv
cd notes
venv\scripts\activate
pip install django
pip install django-ninja
django-admin startproject config .
manage.py startapp notes

Π‘ΠΎΠ·Π΄Π°Π΄ΠΈΠΌ Π±Π°Π·Ρƒ Π΄Π°Π½Π½Ρ‹Ρ… ΠΈ ΡƒΡ‡Π΅Ρ‚Π½ΡƒΡŽ запись Π°Π΄ΠΌΠΈΠ½Π°:

manage.py migrate
manage.py createsuperuser

Π‘Π΄Π΅Π»Π°Π΅ΠΌ Π½ΡƒΠΆΠ½Ρ‹Π΅ настройки Π² Ρ„Π°ΠΉΠ»Π΅ config/settings.py:

import os
…
INSTALLED_APPS = [
…
	'notes',
]
…
STATIC_URL = '/static/'
STATIC_ROOT='/'
STATICFILES_DIRS = (os.path.join(BASE_DIR, 'static'),)

Π‘ΠΎΠ·Π΄Π°Π΄ΠΈΠΌ Ρ„Π°ΠΉΠ» notes/urls.py с содСрТимым:

notes/urls.py
from django.urls import path
from . import views
app_name = 'notes'
urlpatterns = [
	path('', views.home, name='home'),
    path('category/<category_id>/', views.category_detail, name='detail'),
]

Π”ΠΎΠ±Π°Π²ΠΈΠΌ Π½ΡƒΠΆΠ½Ρ‹Π΅ ΠΌΠ°Ρ€ΡˆΡ€ΡƒΡ‚Ρ‹ Π² config/urls.py:

config/urls.py
from django.contrib import admin
from django.urls import path, include
from notes.api import api
from django.conf import settings
from django.conf.urls.static import static
 
urlpatterns = [
	path('admin/', admin.site.urls),
	path("api/", api.urls),
	path('', include('notes.urls', namespace="notes")),
]
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

Π‘ΠΎΠ·Π΄Π°Π΄ΠΈΠΌ ΠΌΠΎΠ΄Π΅Π»ΠΈ для Π·Π°ΠΌΠ΅Ρ‚ΠΎΠΊ ΠΈ ΠΊΠ°Ρ‚Π΅Π³ΠΎΡ€ΠΈΠΉ:

notes/models.py
from django.db import models

class Category(models.Model):
    title = models.CharField(max_length=100)
    description = models.CharField(max_length=300)
    created = models.DateTimeField(auto_now_add=True)
   
    class Meta:
    	verbose_name_plural = 'ΠšΠ°Ρ‚Π΅Π³ΠΎΡ€ΠΈΠΈ'
    	ordering = ['created']

    def __str__(self):
        return self.title

class Note(models.Model):
    title = models.CharField(max_length=250)
    category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='notes')
    created = models.DateTimeField(auto_now_add=True)
    completed = models.BooleanField(default=False, blank=True)
    
    class Meta:
    	verbose_name_plural = 'Π—Π°ΠΌΠ΅Ρ‚ΠΊΠΈ'
    	ordering = ['-created']  

    def __str__(self):
        return self.title        

ЗарСгистрируСм ΠΌΠΎΠ΄Π΅Π»ΠΈ Π² admin.py:

admin.py
from django.contrib import admin
from .models import Category, Note
 
admin.site.register(Category)
admin.site.register(Note)

Π€Π°ΠΉΠ» notes/views.py Π΄ΠΎΠ»ΠΆΠ΅Π½ Π²Ρ‹Π³Π»ΡΠ΄Π΅Ρ‚ΡŒ Ρ‚Π°ΠΊ:

notes/views.py
from django.shortcuts import render, get_object_or_404

from .models import Category, Note

def home(request):
    return render(request, 'index.html', {
        'categories': Category.objects.all()
    })


def category_detail(request, category_id):
    category = get_object_or_404(Category, id=category_id)
    return render(request, 'detail.html', {
        'category': category
    })

Π’Π΅ΠΏΠ΅Ρ€ΡŒ Π½ΡƒΠΆΠ½ΠΎ ΠΏΠΎΠ΄Π³ΠΎΡ‚ΠΎΠ²ΠΈΡ‚ΡŒ ΠΈ Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ ΠΌΠΈΠ³Ρ€Π°Ρ†ΠΈΠΈ:

manage.py makemigrations
manage.py migrate

ПослС выполнСния ΠΌΠΈΠ³Ρ€Π°Ρ†ΠΈΠΉ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΡ€ΠΈΡΡ‚ΡƒΠΏΠ°Ρ‚ΡŒ ΠΊ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ΅ API ΠΈ CRUD-ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΉ. Для этого Π½ΡƒΠΆΠ½ΠΎ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ Π΄Π²Π° Ρ„Π°ΠΉΠ»Π° – notes/schemas.py ΠΈ notes/api.py. Π‘Π½Π°Ρ‡Π°Π»Π° займСмся схСмами – ΠΎΠ½ΠΈ Π² Django Ninja Π²Ρ‹ΠΏΠΎΠ»Π½ΡΡŽΡ‚ Ρ‚Π΅ ΠΆΠ΅ самыС Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ, Ρ‡Ρ‚ΠΎ ΠΈ сСриализатор Π² Django REST Framework, Ρ‚ΠΎ Π΅ΡΡ‚ΡŒ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΡΡŽΡ‚, ΠΊΠ°ΠΊΠΈΠ΅ ΠΈΠΌΠ΅Π½Π½ΠΎ Π΄Π°Π½Π½Ρ‹Π΅ ΠΏΠΎΡΡ‚ΡƒΠΏΠ°ΡŽΡ‚ Π² Π±Π°Π·Ρƒ ΠΈ ΠΊΠ°ΠΊΠΈΠ΅ Π·Π°ΠΏΡ€Π°ΡˆΠΈΠ²Π°ΡŽΡ‚ΡΡ. ΠžΠ±Ρ€Π°Ρ‚ΠΈΡ‚Π΅ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅ Π½Π° Ρ€Π°Π·Π½ΠΈΡ†Ρƒ Π² Π½Π°Π±ΠΎΡ€Π°Ρ… Π΄Π°Π½Π½Ρ‹Ρ… ΠΌΠ΅ΠΆΠ΄Ρƒ схСмами NoteIn, NoteOut, NoteUpd, CategoryIn, CategoryOut:

notes/schemas.py
from ninja import Schema, ModelSchema
from datetime import date
from .models import Note


class CategoryIn(Schema):
    title: str
    description: str

class CategoryOut(Schema):
    id: int
    title: str
    description: str    
    created: date
  

class NoteIn(ModelSchema):
    class Config:
        model = Note
        model_fields = ['title', 'category']

class NoteUpd(ModelSchema):
    class Config:
        model = Note
        model_fields = ['id', 'completed']

class NoteOut(ModelSchema):
    class Config:
        model = Note
        model_fields = ['id','title', 'category', 'created', 'completed']

Вся Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ API описана Π² ΠΎΠ΄Π½ΠΎΠΌ Ρ„Π°ΠΉΠ»Π΅ – notes/api.py:

notes/api.py
from datetime import date
from typing import List
from ninja import NinjaAPI, Schema
from django.shortcuts import get_object_or_404
from .models import Note, Category
from .schemas import NoteIn, NoteOut, NoteUpd, CategoryIn, CategoryOut


api = NinjaAPI()


@api.post("/notes", tags=['Π—Π°ΠΌΠ΅Ρ‚ΠΊΠΈ'])
def create_note(request, payload: NoteIn):
    data = payload.dict()
    category = Category.objects.get(id=data['category'])
    del data['category']
    note = Note.objects.create(category=category, **data)
    return {"id": note.id}

@api.post("/category", tags=['ΠšΠ°Ρ‚Π΅Π³ΠΎΡ€ΠΈΠΈ'])
def create_category(request, payload: CategoryIn):
    category = Category.objects.create(**payload.dict())
    return {"id":category.id}    


@api.get("/notes/{note_id}", response=NoteOut, tags=['Π—Π°ΠΌΠ΅Ρ‚ΠΊΠΈ'])
def get_note(request, note_id: int):
    note = get_object_or_404(Note, id=note_id)
    return note

@api.get("/category/{category_id}", response=CategoryOut, tags=['ΠšΠ°Ρ‚Π΅Π³ΠΎΡ€ΠΈΠΈ'])
def get_category(request, category_id: int):
    category = get_object_or_404(Category, id=category_id)
    return category

@api.get("/category", response=List[CategoryOut], tags=['ΠšΠ°Ρ‚Π΅Π³ΠΎΡ€ΠΈΠΈ'])
def list_categories(request):
    categories = Category.objects.all()
    return categories   

@api.get("/notes", response=List[NoteOut], tags=['Π—Π°ΠΌΠ΅Ρ‚ΠΊΠΈ'])
def list_notes(request):
    notes = Note.objects.all()
    return notes


@api.patch("/notes/{note_id}", tags=['Π—Π°ΠΌΠ΅Ρ‚ΠΊΠΈ'])
def update_note(request, note_id: int, payload: NoteUpd):
    note = get_object_or_404(Note, id=note_id)
    for attr, value in payload.dict().items():
        setattr(note, attr, value)
    note.save()
    return {"success": True}

@api.put("/category/{category_id}", tags=['ΠšΠ°Ρ‚Π΅Π³ΠΎΡ€ΠΈΠΈ'])
def update_category(request, category_id: int, payload: CategoryIn):
    note = get_object_or_404(Category, id=category_id)
    for attr, value in payload.dict().items():
        setattr(note, attr, value)
    category.save()
    return {"success": True}

@api.delete("/notes/{note_id}", tags=['Π—Π°ΠΌΠ΅Ρ‚ΠΊΠΈ'])
def delete_note(request, note_id: int):
    note = get_object_or_404(Note, id=note_id)
    note.delete()
    return {"success": True}

@api.delete("/category/{category_id}", tags=['ΠšΠ°Ρ‚Π΅Π³ΠΎΡ€ΠΈΠΈ'])
def delete_category(request, category_id: int):
    category = get_object_or_404(Category, id=category_id)
    category.delete()
    return {"success": True}

Π’Π΅ΠΏΠ΅Ρ€ΡŒ ΠΌΠΎΠΆΠ½ΠΎ Π·Π°ΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ сСрвСр ΠΈ ΠΏΡ€ΠΎΡ‚Π΅ΡΡ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Ρ€Π°Π±ΠΎΡ‚Ρƒ API:

manage.py runserver

ΠŸΠ΅Ρ€Π΅ΠΉΠ΄ΠΈΡ‚Π΅ ΠΏΠΎ ссылкС http://localhost:8000/api/docs – это адрСс Django Ninja API:

Π’Π΅Π±-интСрфСйс Django Ninja API

Π‘ΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ Π½ΠΎΠ²Ρ‹Π΅ ΠΊΠ°Ρ‚Π΅Π³ΠΎΡ€ΠΈΠΈ ΠΈ Π·Π°ΠΌΠ΅Ρ‚ΠΊΠΈ ΠΌΠΎΠΆΠ½ΠΎ прямо Π½Π° этой страницС. Π’Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΡŽ POST Π² Ρ€Π°Π·Π΄Π΅Π»Π΅ ΠšΠ°Ρ‚Π΅Π³ΠΎΡ€ΠΈΠΈ, Π½Π°ΠΆΠΌΠΈΡ‚Π΅ ΠΊΠ½ΠΎΠΏΠΊΡƒ Try it out, Π²Π²Π΅Π΄ΠΈΡ‚Π΅ Π½Π°Π·Π²Π°Π½ΠΈΠ΅ ΠΈ описаниС ΠΊΠ°Ρ‚Π΅Π³ΠΎΡ€ΠΈΠΈ:

Π”ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ Π² Π±Π°Π·Ρƒ Π½ΠΎΠ²ΠΎΠΉ ΠΊΠ°Ρ‚Π΅Π³ΠΎΡ€ΠΈΠΈ

ΠšΠ»ΠΈΠΊΠ½ΠΈΡ‚Π΅ Π½Π° Execute – Π³ΠΎΡ‚ΠΎΠ²ΠΎ, пСрвая катСгория Π΄ΠΎΠ±Π°Π²Π»Π΅Π½Π° Π² Π±Π°Π·Ρƒ Π΄Π°Π½Π½Ρ‹Ρ…:

Π‘Π΅Ρ€Π²Π΅Ρ€ сообщаСт ΠΎΠ± ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎΠΌ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠΈ ΠΊΠ°Ρ‚Π΅Π³ΠΎΡ€ΠΈΠΈ

HTTP-запросы ΠΊ бэкСнду

Π—Π° ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΡƒ запросов ΠΊ бэкСнду ΠΎΡ‚Π²Π΅Ρ‡Π°Π΅Ρ‚ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° Axios, ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½Π½Π°Ρ Π² шаблонС base.html. Axios – это Π°Π»ΡŒΡ‚Π΅Ρ€Π½Π°Ρ‚ΠΈΠ²Π° fetch с Π±ΠΎΠ»Π΅Π΅ друТСствСнным синтаксисом. Код HTTP-запросов располоТСн Π² ΠΊΠΎΠ½Ρ†Π΅ шаблонов index.html ΠΈ detail.html. Π‘ΠΎΠ·Π΄Π°ΠΉΡ‚Π΅ ΠΏΠ°ΠΏΠΊΡƒ notes/templates ΠΈ помСститС Ρ‚ΡƒΠ΄Π° всС Ρ‚Ρ€ΠΈ шаблона. ΠšΡ€ΠΎΠΌΠ΅ Ρ‚ΠΎΠ³ΠΎ, создайтС ΠΏΠ°ΠΏΠΊΡƒ static Π½Π° ΠΎΠ΄Π½ΠΎΠΌ ΡƒΡ€ΠΎΠ²Π½Π΅ с notes ΠΈ config, ΠΈ сохранитС Π² Π½Π΅ΠΉ Ρ„Π°ΠΉΠ» CSS-стилСй.

ΠŸΠ΅Ρ€Π΅ΠΉΠ΄ΠΈΡ‚Π΅ Π½Π° Π³Π»Π°Π²Π½ΡƒΡŽ страницу прилоТСния http://localhost:8000/ ΠΈ протСстируйтС Ρ€Π°Π±ΠΎΡ‚Ρƒ API ΠΈ Axios – Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ ΠΊΠ°Ρ€Ρ‚ΠΎΡ‡ΠΊΠΈ ΠΊΠ°Ρ‚Π΅Π³ΠΎΡ€ΠΈΠΉ ΠΈ Π·Π°ΠΌΠ΅Ρ‚ΠΊΠΈ ΠΌΠΎΠΆΠ½ΠΎ Π΄ΠΎΠ±Π°Π²Π»ΡΡ‚ΡŒ с Ρ„Ρ€ΠΎΠ½Ρ‚Π΅Π½Π΄Π°:

Π”ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ ΠΊΠ°Ρ€Ρ‚ΠΎΡ‡Π΅ΠΊ происходит Π±Π΅Π· ΠΏΠ΅Ρ€Π΅Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ страницы
Бтатус Π·Π°ΠΌΠ΅Ρ‚ΠΊΠΈ измСняСтся ΠΎΠ΄Π½ΠΈΠΌ ΠΊΠ»ΠΈΠΊΠΎΠΌ Π±Π΅Π· ΠΏΠ΅Ρ€Π΅Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ

Π€Ρ€ΠΎΠ½Ρ‚Π΅Π½Π΄

Помимо API ΠΈ Axios Π² Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠΈ элСмСнтов Π±Π΅Π· ΠΏΠ΅Ρ€Π΅Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ страницы участвуСт Ρ„Ρ€Π΅ΠΉΠΌΠ²ΠΎΡ€ΠΊ Alpine.js. Бинтаксис Alpine.js ΠΎΡ‡Π΅Π½ΡŒ ΠΏΠΎΡ…ΠΎΠΆ Π½Π° Vue.js – Π½ΠΎ, Π² ΠΎΡ‚Π»ΠΈΡ‡ΠΈΠ΅ ΠΎΡ‚ Vue, Alpine Π½Π΅ ΠΊΠΎΠ½Ρ„Π»ΠΈΠΊΡ‚ΡƒΠ΅Ρ‚ с Ρ‚Π΅Π³Π°ΠΌΠΈ Django ΠΈ Π½Π΅ Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ Π·Π°ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ ΠΊΠΎΠ΄Π° Π² Ρ‚Π΅Π³ΠΈ {% verbatim %} {% endverbatim %}. По Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ Alpine максимально Π±Π»ΠΈΠ·ΠΎΠΊ ΠΊ jQuery, поэтому Ρ„Ρ€Π΅ΠΉΠΌΠ²ΠΎΡ€ΠΊ ΡƒΠΆΠ΅ окрСстили «соврСмСнным jQueryΒ».

Бинтаксис Alpine.js Π²ΠΎ ΠΌΠ½ΠΎΠ³ΠΎΠΌ Π½Π°ΠΏΠΎΠΌΠΈΠ½Π°Π΅Ρ‚ синтаксис стандартного ΡˆΠ°Π±Π»ΠΎΠ½ΠΈΠ·Π°Ρ‚ΠΎΡ€Π° Django, ΠΈ Ρ€Π°Π·ΠΎΠ±Ρ€Π°Ρ‚ΡŒΡΡ Π² Π½Π΅ΠΌ (Π² ΠΎΡ‚Π»ΠΈΡ‡ΠΈΠ΅ ΠΎΡ‚ ванильного JavaScript) Π½Π΅ составит Π½ΠΈΠΊΠ°ΠΊΠΎΠ³ΠΎ Ρ‚Ρ€ΡƒΠ΄Π°. Π•Ρ‰Π΅ ΠΎΠ΄Π½ΠΎ ΠΎΠ³Ρ€ΠΎΠΌΠ½ΠΎΠ΅ прСимущСство Alpine.js Π·Π°ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ΡΡ Π² Ρ‚ΠΎΠΌ, Ρ‡Ρ‚ΠΎ Π΅Π³ΠΎ Π½Π΅ Π½ΡƒΠΆΠ½ΠΎ Π½ΠΈΠΊΡƒΠ΄Π° ΡƒΡΡ‚Π°Π½Π°Π²Π»ΠΈΠ²Π°Ρ‚ΡŒ ΠΈ Π·Π°ΠΏΡƒΡΠΊΠ°Ρ‚ΡŒ Π½Π° ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½ΠΎΠΌ локальном сСрвСрС (ΠΈ, ΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎ, Π½Π΅ придСтся ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ CORS).

Π‘ΠΎΠ»Π΅Π΅ Ρ‚ΠΎΠ³ΠΎ, Alpine.js Π±Π΅Π· ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ Π΄Π°Π½Π½Ρ‹Π΅ ΠΎΡ‚ ΡˆΠ°Π±Π»ΠΎΠ½ΠΈΠ·Π°Ρ‚ΠΎΡ€Π° Django. ΠžΠ±Ρ€Π°Ρ‚ΠΈΡ‚Π΅ Π²Π½ΠΈΠΌΠ°Π½ΠΈΠ΅ Π½Π° эти Ρ„Ρ€Π°Π³ΠΌΠ΅Π½Ρ‚Ρ‹ Π² index.html, Π³Π΄Π΅ Π² шаблонС ΠΌΠΈΡ€Π½ΠΎ ΡƒΠΆΠΈΠ²Π°ΡŽΡ‚ΡΡ запрос Alpine ΠΈ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½ΠΈΠ΅ Π΄Π°Π½Π½Ρ‹Ρ… ΠΈΠ· бэкСнда Django:

<div x-data="getCategories()">
   <h3 class="text-center mt-5" style="color:#777">всС ΠΊΠ°Ρ‚Π΅Π³ΠΎΡ€ΠΈΠΈ Π·Π°ΠΌΠ΅Ρ‚ΠΎΠΊ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ <span class="fw-bold">{{ request.user.username }}</span></h3>
    <form id="category-form">
    	{% csrf_token %}
	</form>
...
const getCategories = () => {
	return {
    	newCategory: '',
    	newDescription: '',
    	categories: [
        	{% for category in categories %}
        	{ 'title': '{{ category.title }}', 'id': '{{ category.id }}', 'description': '{{ category.description }}' },
        	{% endfor %}
        ]
    }
};

Π’ ΠΊΠΎΠ½Ρ†Π΅ шаблонов index.html ΠΈ detail.html Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° Axios обСспСчиваСт ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΡƒ запросов ΠΊ Django Ninja API. ΠŸΡ€ΠΈ создании Π½ΠΎΠ²ΠΎΠΉ ΠΊΠ°Ρ‚Π΅Π³ΠΎΡ€ΠΈΠΈ Axios ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ ΠΎΡ‚ Alpine Π½Π°Π·Π²Π°Π½ΠΈΠ΅ ΠΈ описаниС (title, description) ΠΈ ΠΏΠ΅Ρ€Π΅Π΄Π°Π΅Ρ‚ API запрос POST:

const addCategory = async (title, description) => {
	try {
	const res = await axios.post('/api/category',
    	{ title, description },
    	{ headers: { 'X-CSRFToken': csrftoken }}
    	);
	location.reload();
  	} catch (e) {
    	console.error(e);
  	}
};

Для удалСния ΠΊΠ°Ρ‚Π΅Π³ΠΎΡ€ΠΈΠΈ Axios ΠΏΠ΅Ρ€Π΅Π΄Π°Π΅Ρ‚ бэкСнду ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠΉ ID – categoryId:

const removeCategory = async categoryId => {
	try {
	const res = await axios.delete('/api/category/' + categoryId,
    	{ headers: { 'X-CSRFToken': csrftoken }}
    	);
	location.reload();
  	} catch (e) {
    	console.error(e);
  	}
};

ПодвСдСм ΠΈΡ‚ΠΎΠ³ΠΈ

Π€Ρ€Π΅ΠΉΠΌΠ²ΠΎΡ€ΠΊ Django Ninja ΠΈ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° Alpine.js появились совсСм Π½Π΅Π΄Π°Π²Π½ΠΎ, Π½ΠΎ ΡƒΠΆΠ΅ успСли произвСсти Ρ„ΡƒΡ€ΠΎΡ€ срСди Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊΠΎΠ²: ΡΠΊΠΎΡ€ΠΎΡΡ‚ΡŒ, Π³ΠΈΠ±ΠΊΠΎΡΡ‚ΡŒ, простота синтаксиса ΠΈ бСсшовная интСграция Π΄Π΅Π»Π°ΡŽΡ‚ ΠΈΡ… ΠΈΠ΄Π΅Π°Π»ΡŒΠ½Ρ‹ΠΌ Π²Ρ‹Π±ΠΎΡ€ΠΎΠΌ для Π³ΠΈΠ±Ρ€ΠΈΠ΄Π½Ρ‹Ρ… Django-ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ΠΎΠ² с ΡƒΠΌΠ΅Ρ€Π΅Π½Π½ΠΎΠΉ Π½Π°Π³Ρ€ΡƒΠ·ΠΊΠΎΠΉ. ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Notes, нСсмотря Π½Π° простоту, позволяСт быстро ΠΈΠ·ΡƒΡ‡ΠΈΡ‚ΡŒ всС основныС возмоТности Django Ninja ΠΈ Alpine.js, Ρ€Π°Π·ΠΎΠ±Ρ€Π°Ρ‚ΡŒΡΡ Π² ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌΠ΅ взаимодСйствия API ΠΈ Axios, ΠΈ ΠΏΡ€ΠΈΡΡ‚ΡƒΠΏΠΈΡ‚ΡŒ ΠΊ Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠ΅ Π±ΠΎΠ»Π΅Π΅ слоТных ΠΏΡ€ΠΎΠ΅ΠΊΡ‚ΠΎΠ². НапоминаСм, Ρ‡Ρ‚ΠΎ вСсь ΠΊΠΎΠ΄ для Notes ΠΌΠΎΠΆΠ½ΠΎ Π²Π·ΡΡ‚ΡŒ Π² Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΈ.

***

ΠœΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π»Ρ‹ ΠΏΠΎ Ρ‚Π΅ΠΌΠ΅

Π›Π£Π§Π¨Π˜Π• БВАВЬИ ПО Π’Π•ΠœΠ•

admin
11 дСкабря 2018

ООП Π½Π° Python: ΠΊΠΎΠ½Ρ†Π΅ΠΏΡ†ΠΈΠΈ, ΠΏΡ€ΠΈΠ½Ρ†ΠΈΠΏΡ‹ ΠΈ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Ρ‹ Ρ€Π΅Π°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ

ΠŸΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ Π½Π° Python допускаСт Ρ€Π°Π·Π»ΠΈΡ‡Π½Ρ‹Π΅ ΠΌΠ΅Ρ‚ΠΎΠ΄ΠΎΠ»ΠΎΠ³ΠΈΠΈ, Π½ΠΎ Π² Π΅Π³ΠΎ основС...
admin
28 июня 2018

3 самых Π²Π°ΠΆΠ½Ρ‹Ρ… сфСры примСнСния Python: возмоТности языка

БущСствуСт мноТСство областСй примСнСния Python, Π½ΠΎ Π² Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Ρ… ΠΎΠ½ особСнно...
admin
13 фСвраля 2017

ΠŸΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ Π½Π° Python: ΠΎΡ‚ Π½ΠΎΠ²ΠΈΡ‡ΠΊΠ° Π΄ΠΎ профСссионала

Пошаговая инструкция для всСх, ΠΊΡ‚ΠΎ Ρ…ΠΎΡ‡Π΅Ρ‚ ΠΈΠ·ΡƒΡ‡ΠΈΡ‚ΡŒΒ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΠΈΡ€ΠΎΠ²Π°Π½ΠΈΠ΅ Π½Π° Python...