DeepLearning Blog

Джанго - разрабатывает свой модуль с нуля

Published Dec. 17, 2025, 10:38 a.m. by a.glazyrin
image

1. Структура проекта

todo_django_app/          # Корень пакета
├── todo_app/             # Основной пакет
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── migrations/
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   ├── urls.py
│   └── views.py
├── setup.py              # Для установки через pip
├── README.md
├── LICENSE
├── MANIFEST.in          # Включает дополнительные файлы
└── requirements.txt

2. Основные файлы

todo_app/models.py

from django.db import models
from django.contrib.auth.models import User

class Todo(models.Model):
    """Модель задачи"""
    title = models.CharField(max_length=200, verbose_name="Заголовок")
    description = models.TextField(blank=True, verbose_name="Описание")
    completed = models.BooleanField(default=False, verbose_name="Выполнено")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="Создано")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="Обновлено")
    user = models.ForeignKey(
        User, 
        on_delete=models.CASCADE, 
        related_name='todos',
        verbose_name="Пользователь"
    )

    class Meta:
        verbose_name = "Задача"
        verbose_name_plural = "Задачи"
        ordering = ['-created_at']

    def __str__(self):
        return self.title

todo_app/admin.py

from django.contrib import admin
from .models import Todo

@admin.register(Todo)
class TodoAdmin(admin.ModelAdmin):
    list_display = ('title', 'user', 'completed', 'created_at')
    list_filter = ('completed', 'created_at')
    search_fields = ('title', 'description')
    date_hierarchy = 'created_at'
    readonly_fields = ('created_at', 'updated_at')

todo_app/views.py

from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from .models import Todo

@login_required
def todo_list(request):
    """Список задач пользователя"""
    todos = Todo.objects.filter(user=request.user)
    return render(request, 'todo_app/todo_list.html', {'todos': todos})

@login_required
def todo_detail(request, pk):
    """Детали задачи"""
    todo = get_object_or_404(Todo, pk=pk, user=request.user)
    return render(request, 'todo_app/todo_detail.html', {'todo': todo})

@login_required
def todo_create(request):
    """Создание новой задачи"""
    if request.method == 'POST':
        title = request.POST.get('title')
        description = request.POST.get('description', '')

        if title:
            Todo.objects.create(
                title=title,
                description=description,
                user=request.user
            )
            messages.success(request, 'Задача создана!')
            return redirect('todo_app:list')

    return render(request, 'todo_app/todo_form.html')

@login_required
def todo_update(request, pk):
    """Обновление задачи"""
    todo = get_object_or_404(Todo, pk=pk, user=request.user)

    if request.method == 'POST':
        todo.title = request.POST.get('title', todo.title)
        todo.description = request.POST.get('description', todo.description)
        todo.completed = 'completed' in request.POST
        todo.save()

        messages.success(request, 'Задача обновлена!')
        return redirect('todo_app:list')

    return render(request, 'todo_app/todo_form.html', {'todo': todo})

@login_required
def todo_delete(request, pk):
    """Удаление задачи"""
    todo = get_object_or_404(Todo, pk=pk, user=request.user)

    if request.method == 'POST':
        todo.delete()
        messages.success(request, 'Задача удалена!')
        return redirect('todo_app:list')

    return render(request, 'todo_app/todo_confirm_delete.html', {'todo': todo})

todo_app/urls.py

from django.urls import path
from . import views

app_name = 'todo_app'

urlpatterns = [
    path('', views.todo_list, name='list'),
    path('create/', views.todo_create, name='create'),
    path('<int:pk>/', views.todo_detail, name='detail'),
    path('<int:pk>/update/', views.todo_update, name='update'),
    path('<int:pk>/delete/', views.todo_delete, name='delete'),
]

todo_app/apps.py

from django.apps import AppConfig

class TodoAppConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'todo_app'
    verbose_name = "Менеджер задач"

3. Шаблоны (необязательно, но полезно)

Создадим директорию templates/todo_app/ внутри приложения:

todo_app/
├── templates/
│   └── todo_app/
│       ├── todo_list.html
│       ├── todo_detail.html
│       ├── todo_form.html
│       └── todo_confirm_delete.html

todo_app/templates/todo_app/todo_list.html (пример):

<!DOCTYPE html>
<html>
<head>
    <title>Мои задачи</title>
</head>
<body>
    <h1>Мои задачи</h1>
    <a href="{% url 'todo_app:create' %}">Создать задачу</a>

    <ul>
        {% for todo in todos %}
            <li>
                <input type="checkbox" {% if todo.completed %}checked{% endif %} disabled>
                <a href="{% url 'todo_app:detail' todo.pk %}">{{ todo.title }}</a>
                <small>{{ todo.created_at|date:"d.m.Y H:i" }}</small>
                <a href="{% url 'todo_app:update' todo.pk %}">✏️</a>
                <a href="{% url 'todo_app:delete' todo.pk %}">🗑️</a>
            </li>
        {% empty %}
            <li>Нет задач. <a href="{% url 'todo_app:create' %}">Создать первую?</a></li>
        {% endfor %}
    </ul>
</body>
</html>

4. setup.py - самый важный файл для установки

from setuptools import setup, find_packages
import os

# Чтение README
with open("README.md", "r", encoding="utf-8") as fh:
    long_description = fh.read()

# Чтение требований
with open("requirements.txt", "r", encoding="utf-8") as fh:
    requirements = fh.read().splitlines()

setup(
    name="django-todo-app",  # Имя пакета на PyPI
    version="0.1.0",  # Версия
    author="Ваше Имя",
    author_email="your.email@example.com",
    description="Простое Django приложение для управления задачами",
    long_description=long_description,
    long_description_content_type="text/markdown",
    url="https://github.com/yourusername/django-todo-app",

    # Находим все пакеты
    packages=find_packages(),

    # Указываем, что это Django приложение
    include_package_data=True,

    # Классификаторы для PyPI
    classifiers=[
        "Development Status :: 4 - Beta",
        "Environment :: Web Environment",
        "Framework :: Django",
        "Framework :: Django :: 3.2",
        "Framework :: Django :: 4.0",
        "Intended Audience :: Developers",
        "License :: OSI Approved :: MIT License",
        "Operating System :: OS Independent",
        "Programming Language :: Python",
        "Programming Language :: Python :: 3",
        "Programming Language :: Python :: 3.8",
        "Programming Language :: Python :: 3.9",
        "Programming Language :: Python :: 3.10",
        "Topic :: Internet :: WWW/HTTP",
        "Topic :: Internet :: WWW/HTTP :: Dynamic Content",
    ],

    # Зависимости
    install_requires=requirements,

    # Дополнительные зависимости для разработки
    extras_require={
        "dev": [
            "pytest>=6.0",
            "pytest-django",
            "black",
            "flake8",
        ],
    },

    # Python версия
    python_requires=">=3.8",

    # Ключевые слова для поиска
    keywords="django, todo, tasks, productivity",

    # Проект поддерживает установку через pip
    zip_safe=False,

    # Чтобы можно было импортировать как django-todo-app
    entry_points={
        'console_scripts': [],
    },
)

5. MANIFEST.in - для включения дополнительных файлов

include LICENSE
include README.md
include requirements.txt
recursive-include todo_app/templates *
recursive-include todo_app/static *
recursive-include todo_app/locale *

6. requirements.txt

Django>=3.2,<5.0

7. README.md

# Django Todo App

Простое Django приложение для управления задачами.

## Установка

```bash
pip install django-todo-app

Настройка

  1. Добавьте 'todo_app' в INSTALLED_APPS:
# settings.py
INSTALLED_APPS = [
    ...,
    'todo_app',
]
  1. Выполните миграции:
python manage.py migrate
  1. Добавьте URL в ваш проект:
# urls.py проекта
from django.urls import path, include

urlpatterns = [
    ...,
    path('todos/', include('todo_app.urls', namespace='todo_app')),
]
  1. Создайте суперпользователя для доступа к админке:
python manage.py createsuperuser

Использование

После установки перейдите по адресу /todos/ для работы с задачами.

Лицензия

MIT

## **8. `LICENSE`** (MIT лицензия)

```text
MIT License

Copyright (c) 2024 Ваше Имя

Permission is hereby granted...

9. Как использовать/тестировать локально

Установка в режиме разработки:

# В директории todo_django_app/
pip install -e .

Создание дистрибутива:

python setup.py sdist bdist_wheel

Загрузка на PyPI (TestPyPI для тестирования):

# Установите twine если нет
pip install twine

# Загрузите на TestPyPI
twine upload --repository testpypi dist/*

# Загрузите на PyPI
twine upload dist/*

10. Как другой разработчик установит ваш пакет

# Из PyPI
pip install django-todo-app

# Или напрямую из GitHub
pip install git+https://github.com/yourusername/django-todo-app.git

# Или определенную версию
pip install django-todo-app==0.1.0

11. Пример использования в другом Django проекте

# settings.py другого проекта
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    # Установленный пакет
    'todo_app',
]

# urls.py
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('todos/', include('todo_app.urls', namespace='todo_app')),
    path('accounts/', include('django.contrib.auth.urls')),
]

12. Добавим фикстуры для тестовых данных

todo_app/fixtures/initial_data.json (опционально):

[
  {
    "model": "todo_app.todo",
    "pk": 1,
    "fields": {
      "title": "Пример задачи",
      "description": "Это пример задачи",
      "completed": false,
      "created_at": "2024-01-01T10:00:00Z",
      "updated_at": "2024-01-01T10:00:00Z",
      "user": 1
    }
  }
]

13. Добавим тесты

todo_app/tests.py:

from django.test import TestCase
from django.contrib.auth.models import User
from django.urls import reverse
from .models import Todo

class TodoModelTest(TestCase):
    def setUp(self):
        self.user = User.objects.create_user(
            username='testuser',
            password='testpass123'
        )
        self.todo = Todo.objects.create(
            title='Test Todo',
            description='Test Description',
            user=self.user
        )

    def test_todo_creation(self):
        self.assertEqual(self.todo.title, 'Test Todo')
        self.assertEqual(self.todo.user.username, 'testuser')
        self.assertFalse(self.todo.completed)

    def test_todo_str(self):
        self.assertEqual(str(self.todo), 'Test Todo')

class TodoViewTest(TestCase):
    def setUp(self):
        self.user = User.objects.create_user(
            username='testuser',
            password='testpass123'
        )
        self.client.login(username='testuser', password='testpass123')

    def test_todo_list_view(self):
        response = self.client.get(reverse('todo_app:list'))
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'todo_app/todo_list.html')

Итог:

  1. setup.py — главный файл для установки через pip
  2. __init__.py — делает директорию Python пакетом
  3. Стандартная структура Django app — models, views, urls, admin
  4. MANIFEST.in — включает дополнительные файлы (шаблоны, статику)
  5. Документация — README.md, LICENSE

Чтобы установить ваш модуль:

# Локальная разработка
pip install -e /path/to/todo_django_app

# Из архива
pip install todo_django_app-0.1.0.tar.gz

# Из PyPI
pip install django-todo-app

Такой модуль можно:
- Установить в любой Django проект
- Распространять через PyPI
- Использовать как зависимость в других проектах
- Версионировать и обновлять

0.0
0 оценок
5★
0
4★
0
3★
0
2★
0
1★
0

Оставить отзыв

Нажмите на звезду для оценки от 1 до 5
Необязательно. Используется только для связи
0/2000

Комментарии

Все С ответами Проверенные Только 4-5★