dhtmlxGantt с Python

Это руководство объясняет, как настроить диаграмму Ганта с использованием Python в рамках Django 4 и RESTful API для сервера.

Если вас интересуют другие серверные интеграции, существуют учебные пособия для различных платформ:

Полный исходный код для этого урока доступен на GitHub.

Предварительные требования

Убедитесь, что Django установлен на вашей системе. Если нет, вы можете следовать этим руководствам:

Шаг 1. Настройка проекта

Начните с создания нового проекта Django. В папке вашего проекта выполните команду:

django-admin startproject gantt_rest_python

Вы можете либо переместить содержимое папки gantt_rest_python в текущую папку, либо перейти в нее:

cd gantt_rest_python

Чтобы проверить, что настройка работает, запустите сервер:

python manage.py runserver

Посетите http://localhost:8000 в вашем браузере. Вы должны увидеть стандартную приветственную страницу Django:

start_page

Шаг 2. Добавление Gantt на страницу

Далее создайте новое приложение Django для компонента Gantt:

python manage.py startapp gantt

Установите необходимые пакеты REST-фреймворка:

pip install djangorestframework
pip install djangorestframework-jsonapi

Внутри папки gantt создайте директории static и templates. Скопируйте содержимое папки codebase из пакета Gantt в директорию static и переименуйте ее в gantt для ясности.

Теперь создайте файл с именем index.html в каталоге templates/gantt и добавьте следующий код:

gantt/templates/gantt/index.html

<html>
    <head>
        {% load static %}
        <script src="{% static "gantt/dhtmlxgantt.js" %}" type="text/javascript">
        </script>
        <link rel="stylesheet" href="{% static "gantt/dhtmlxgantt.css" %}" />
    </head>
    <body>
        <div id="gantt_here" style='width:100%; height:500px;'>
        </div>
        <script>
        gantt.config.date_format = "%Y-%m-%d %H:%i";
 
        gantt.config.open_tree_initially = true;
        gantt.init("gantt_here");
        </script>
    </body>
</html>

Теперь ваша структура папок должна выглядеть следующим образом:

folder_structure

В файле views.py, расположенном в папке gantt, добавьте следующий код:

gantt/views.py

from django.shortcuts import render
 
def index(request):
    return render(request, 'gantt/index.html')

Далее настройте маршрутизацию. Создайте файл с именем urls.py в папке gantt и включите следующий код:

gantt/urls.py

from django.urls import include, re_path
from . import views
from rest_framework.urlpatterns import format_suffix_patterns
 
urlpatterns = [
    re_path(r'^$', views.index, name='index'),
]
urlpatterns = format_suffix_patterns(urlpatterns)

Затем обновите файл urls.py в папке проекта gantt_rest_python, чтобы включить новое приложение:

gantt_rest_python/urls.py

from django.urls import include, re_path
from django.contrib import admin
 
urlpatterns = [
    re_path(r'', include('gantt.urls')),
]

Настройте пути для директорий templates и static в файле settings.py в папке gantt_rest_python. Добавьте эту строку в начале:

gantt_rest_python/settings.py

import os

Найдите массив TEMPLATES и замените 'DIRS': [] на:

'DIRS': [os.path.join(BASE_DIR, 'gantt/templates')],

Добавьте следующую строку в конец файла:

STATICFILES_DIRS = [os.path.join(BASE_DIR, "gantt/static")]

Теперь запустите сервер:

python manage.py runserver

Если все настроено правильно, вы должны увидеть страницу с пустой диаграммой Ганта:

init_gantt

Шаг 3. Загрузка данных

Чтобы загрузить данные, обновите файл settings.py. Добавьте 'rest_framework' и 'gantt.apps.GanttConfig' в массив INSTALLED_APPS, а также настройте REST_FRAMEWORK:

gantt_rest_python/settings.py

INSTALLED_APPS = [
    'gantt.apps.GanttConfig',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
]
 
REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.AllowAny',),
    'PAGE_SIZE': 10
}

Отключите параметр USE_TZ, чтобы соответствовать DHTMLX Gantt, который использует абсолютные даты:

USE_TZ = False

Определите модели Task и Link в gantt/models.py:

gantt/models.py

from django.db import models
 
class Task(models.Model):
    id = models.AutoField(primary_key=True, editable=False)
    text = models.CharField(blank=True, max_length=100)
    start_date = models.DateTimeField()
    end_date = models.DateTimeField()
    duration = models.IntegerField()
    progress = models.FloatField()
    parent = models.CharField(max_length=100)
 
class Link(models.Model):
    id = models.AutoField(primary_key=True, editable=False)
    source = models.CharField(max_length=100)
    target = models.CharField(max_length=100)
    type = models.CharField(max_length=100)
    lag = models.IntegerField(blank=True, default=0)

Создайте миграции и примените их:

python manage.py makemigrations gantt
python manage.py migrate

Чтобы добавить некоторые образцы данных, откройте оболочку Python:

python manage.py shell

Используйте следующие команды, чтобы добавить задачи и связи:

from gantt.models import Task, Link
 
Add tasks
===================
t1 = Task(id="10", text="Project #1", start_date="2025-04-01 00:00", end_date="2025-04-03 00:00", duration=2, progress=0.5, parent="0")
t1.save()
Repeat for other tasks...
===================
 
Add links
===================
l1 = Link(id="1", source="1", target="2", type="0", lag=0)
l1.save()
Repeat for other links...
===================

Чтобы подтвердить, выполните:

Task.objects.all()
Link.objects.all()

Вы должны увидеть добавленные задачи и связи.

Далее, создайте файл с именем serializers.py в папке gantt, чтобы обработать сериализацию:

gantt/serializers.py

from .models import Task, Link
from rest_framework import serializers
 
class TaskSerializer(serializers.ModelSerializer):
    start_date = serializers.DateTimeField(format='%Y-%m-%d %H:%M')
    end_date = serializers.DateTimeField(format='%Y-%m-%d %H:%M')
 
    class Meta:
        model = Task
        fields = ('id','text','start_date','end_date','duration','progress','parent')
 
class LinkSerializer(serializers.ModelSerializer):
    class Meta:
        model = Link
        fields = ('id', 'source', 'target', 'type', 'lag')

Обновите файл views.py, чтобы включить метод для возврата данных:

gantt/views.py

from django.shortcuts import render
from .models import Task, Link
from gantt.serializers import TaskSerializer, LinkSerializer
from rest_framework.decorators import api_view
from rest_framework.response import Response
 
def index(request):
    return render(request, 'gantt/index.html')
 
@api_view(['GET'])
def data_list(request, offset):
    tasks = Task.objects.all()
    links = Link.objects.all()
    taskData = TaskSerializer(tasks, many=True)
    linkData = LinkSerializer(links, many=True)
    return Response({
        "tasks": taskData.data,
        "links": linkData.data
    })

Добавьте новый маршрут в gantt/urls.py:

gantt/urls.py

from django.urls import include, re_path
from . import views
 
urlpatterns = [
    re_path(r'^$', views.index, name='index'),
    re_path(r'^data/(.*)$', views.data_list),
]

Наконец, обновите index.html для загрузки данных:

gantt/templates/gantt/index.html

gantt.load("/data/", "json");

Перезапустите сервер, и теперь вы должны увидеть диаграмму Ганта, заполненную задачами и связями.

gantt

Шаг 4. Сохранение изменений

Чтобы разрешить сохранение изменений, добавьте методы для обработки POST, PUT и DELETE запросов в views.py. Полный фрагмент кода приведен выше.

Обновите маршруты в gantt/urls.py, чтобы включить пути для этих действий.

Наконец, включите Data Processor в index.html, чтобы обрабатывать эти обновления:

gantt/templates/gantt/index.html

var dp = new gantt.dataProcessor("/data/");
dp.init(gantt);
dp.setTransactionMode("REST");

С этой настройкой вы можете добавлять, обновлять и удалять задачи и связи. Изменения будут сохраняться после перезагрузки страницы.

saving_changes

Хранение порядка задач

Чтобы управлять вертикальным порядком задач, вы можете следовать шагам, описанным в оригинальном руководстве. Это включает добавление свойства sort_order, включение изменения порядка и сохранение порядка в базе данных.

Безопасность приложения

Хотя Gantt обрабатывает фронтенд, безопасность бэкенда (например, предотвращение SQL-инъекций, XSS и CSRF атак) остается за разработчиком. Обратитесь к этой статье для более подробной информации.

Устранение неполадок

Если задачи и связи не отображаются на странице, ознакомьтесь с руководством по устранению неполадок: Устранение проблем с интеграцией бэкенда.

Что дальше

Ваша диаграмма Ганта готова к использованию. Полный код доступен на GitHub. Ознакомьтесь с дополнительными руководствами и учебными пособиями для других фреймворков бэкенда.

К началу