Настройка моделей базы данных и создание JSON API в Django

Создание структуры данных (моделей) и написание логики выгрузки (представлений) — это сердце любого бэкенд-приложения. Именно здесь мы создаем таблицы, которые потом будут видны в админке Django, и учим сервер отдавать чистый текст (JSON) для мобильного приложения.
Ниже приложена подробная пошаговая инструкция для файлов models.py и views.py. Она оформлена как методическое руководство, по которому будет очень удобно учить ребят!

📑 Методическое руководство: Настройка моделей базы данных и создание JSON API в Django

Цель: Описать структуру экскурсионных маршрутов и точек в коде Python, зарегистрировать их в панели администратора и настроить веб-страницу (API), которая выдает данные для мобильного приложения.

🏗️ Часть 1. Создание структуры таблиц в guide/models.py

В Django таблицы базы данных описываются в виде классов на Python. Нам понадобятся две связанные между собой таблицы: Маршруты (Route) и Точки маршрута (Point).
Откройте файл guide/models.py в PyCharm и вставьте следующий код:
from django.db import models

class Route(models.Model):
    """Модель экскурсионного маршрута (например, Купеческий Галич)"""
    title = models.CharField(max_length=200, verbose_name="Название маршрута")
    # Картинки будут автоматически загружаться в папку media/routes_images/
    image = models.ImageField(upload_files="routes_images/", verbose_name="Главное изображение", blank=True, null=True)
    description = models.TextField(verbose_name="Описание маршрута")

    class Meta:
        verbose_name = "Маршрут"
        verbose_name_plural = "Маршруты"

    def __str__(self):
        return self.title


class Point(models.Model):
    """Модель конкретной исторической точки, привязанной к маршруту"""
    # Связь «Один ко многим»: к одному маршруту можно привязать много точек
    route = models.ForeignKey(Route, on_delete=models.CASCADE, related_name="points", verbose_name="Маршрут")
    title = models.CharField(max_length=200, verbose_name="Название точки")
    image = models.ImageField(upload_files="points_images/", verbose_name="Фотография точки", blank=True, null=True)
    short_desc = models.CharField(max_length=300, verbose_name="Краткое описание (для списка)")
    full_desc = models.TextField(verbose_name="Полное историческое описание")
    # Координаты храним строкой вида: 58.3792,42.3486
    coordinates = models.CharField(max_length=50, verbose_name="Координаты (Широта,Долгота)", help_text="Например: 58.3792,42.3486")

    class Meta:
        verbose_name = "Точка маршрута"
        verbose_name_plural = "Точки маршрута"

    def __str__(self):
        return f"{self.route.title} — {self.title}"

🎛️ Часть 2. Регистрация таблиц в админке guide/admin.py

Чтобы созданные таблицы появились в виде красивых графических вкладок в интернет-админке Django, их нужно обязательно зарегистрировать.
Откройте файл guide/admin.py и вставьте туда этот код:
from django.contrib import admin
from .models import Route, Point

# Настраиваем отображение точек прямо внутри карточки маршрута для удобства (Inlines)
class PointInline(admin.TabularInline):
    model = Point
    extra = 1 # Сколько пустых строк для новых точек показывать сразу

@admin.register(Route)
class RouteAdmin(admin.ModelAdmin):
    list_display = ('id', 'title', 'description_short')
    inlines = [PointInline] # Встраиваем точки внутрь маршрута

    def description_short(self, obj):
        # Показываем в общем списке только первые 50 символов описания
        return obj.description[:50] + "..." if len(obj.description) > 50 else obj.description
    description_short.short_description = "Краткое описание"

@admin.register(Point)
class PointAdmin(admin.ModelAdmin):
    list_display = ('title', 'route', 'coordinates')
    list_filter = ('route',) # Добавляем удобную фильтрацию по маршрутам в правой панели

🌐 Часть 3. Создание выгрузки JSON-данных в guide/views.py

Мобильный телефон не умеет читать обычные веб-страницы так, как это делает человек. Ему нужен структурированный текст в формате JSON. Мы напишем функцию, которая берет данные из MySQL и превращает их в текст, принудительно прописывая безопасный протокол https:// для картинок.
Откройте файл guide/views.py и замените его содержимое на этот код:
from django.http import JsonResponse
from .models import Route

def get_routes_api(request):
    """Функция-обработчик (API), которая отдает данные для мобильного приложения"""
    # prefetch_related('points') мгновенно вытаскивает все связанные точки, чтобы сервер работал быстро
    routes = Route.objects.prefetch_related('points').all()
    data = []
    
    # Жестко фиксируем ваш рабочий интернет-домен со встроенным SSL-сертификатом
    domain = "https://infostarting.ru"
    
    for route in routes:
        # Собираем данные самого маршрута
        route_data = {
            "id": str(route.id),
            "title": route.title,
            "image": domain + route.image.url if route.image else "",
            "description": route.description,
            "points": []
        }
        
        # Собираем список всех точек, привязанных к этому маршруту
        for pt in route.points.all():
            route_data["points"].append({
                "id": f"{route.id}_{pt.id}",
                "title": pt.title,
                "image": domain + pt.image.url if pt.image else "",
                "short_desc": pt.short_desc,
                "full_desc": pt.full_desc,
                "coordinates": pt.coordinates
            })
            
        data.append(route_data)
        
    # safe=False позволяет отдавать обычный список, 
    # json_dumps_params={'ensure_ascii': False} сохраняет русские буквы красивыми, а не в виде кодов \u0410
    return JsonResponse(data, safe=False, json_dumps_params={'ensure_ascii': False})

🔗 Часть 4. Настройка ссылок адресов в site1/urls.py

Чтобы сервер понял, по какому именно интернет-адресу нужно запускать нашу функцию выгрузки JSON, пропишем путь в главном файле диспетчера ссылок проекта.
Откройте файл site1/urls.py и приведите его к следующему виду:
from django.contrib import admin
from django.urls import path
from django.conf import settings
from django.conf.urls.static import static
from guide.views import get_routes_api # Импортируем нашу функцию из views.py

urlpatterns = [
    # Путь к панели управления
    path('admin/', admin.site.urls),
    
    # Наш точный интернет-путь для мобильного приложения Flet!
    path('api/routes/', get_routes_api),
]

# Важное системное правило: разрешаем Django раздавать загруженные пользователем картинки экскурсий
if settings.DEBUG == False:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
    urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

🗄️ Часть 5. Применение изменений на сервере (Миграции)

Всякий раз, когда вы или ребята меняете или создаете файлы models.py, нужно обязательно дать Django команду обновить таблицы внутри самой базы данных MySQL.
Откройте вашу SSH-консоль хостинга Timeweb (или терминал PyCharm, если тестируете локально) и введите две команды:
# 1. Django сравнивает код в models.py с текущей базой и создает файл-чертеж изменений
python manage.py makemigrations

# 2. Django применяет этот чертеж и физически перестраивает таблицы в MySQL
python manage.py migrate

🎓 Совет для преподавателя: на что обратить внимание ребят

  1. ForeignKey (Внешний ключ): Объясните ребятам, что строка route = models.ForeignKey(...) — это как невидимая ниточка. Мы не пишем для каждой точки маршрут заново, мы просто указываем ссылку на существующий маршрут. Если удалить маршрут, Django благодаря правилу on_delete=models.CASCADE автоматически и аккуратно удалит все связанные с ним точки, чтобы в базе не оставалось «мусора».
  2. Формат JSON: Покажите ребятам результат работы страницы https://infostarting.ru. Объясните, что фигурные скобки {} — это карточка объекта, а квадратные [] — это список таких карточек. Мобильный телефон расшифровывает этот текст построчно сверху вниз.
Сохраняйте эту памятку! Когда вы будете готовы перейти ко второй части — инструкции по созданию кода мобильного приложения Flet со всей версткой, кнопками и беспроводной отладкой через QR-код, дайте знать, и я подготовлю такое же красивое и понятным языком написанное руководство!


Last modified: Sunday, 27 September 2026, 12:34 PM