Введение в Django
Django — это мощный веб-фреймворк с открытым исходным кодом, написанный на языке Python. Он был создан в 2003 году и впервые выпущен в 2005 году. Django следует принципу "включены батарейки" (batteries included), что означает наличие всех необходимых компонентов для создания полноценных веб-приложений без необходимости установки дополнительных пакетов.
Фреймворк базируется на принципе "не повторяй себя" (DRY — Don't Repeat Yourself) и предоставляет разработчикам мощные инструменты для быстрого создания безопасных и масштабируемых веб-приложений.
Архитектура и ключевые особенности Django
MTV-паттерн (Model-Template-View)
Django использует архитектурный паттерн MTV, который является адаптацией классического MVC:
- Model — модель данных, определяющая структуру базы данных
- Template — шаблон для представления данных пользователю
- View — представление, содержащее бизнес-логику приложения
Объектно-реляционное отображение (ORM)
Django ORM позволяет работать с базой данных через Python-классы вместо написания SQL-запросов. Это обеспечивает:
- Абстракцию от конкретной СУБД
- Безопасность от SQL-инъекций
- Простоту миграций схемы базы данных
- Возможность использования различных баз данных
Встроенная административная панель
Django автоматически генерирует интерфейс администратора на основе моделей данных. Это позволяет:
- Быстро создавать CRUD-интерфейсы
- Управлять пользователями и правами доступа
- Выполнять массовые операции с данными
- Настраивать отображение и фильтрацию данных
Система безопасности
Django включает встроенную защиту от основных уязвимостей:
- CSRF-защита — предотвращение межсайтовых атак
- XSS-защита — автоматическое экранирование данных в шаблонах
- SQL-инъекции — параметризованные запросы через ORM
- Clickjacking protection — защита от кликджекинга
- Secure cookies — безопасные куки
- Password hashing — хеширование паролей
Масштабируемость и производительность
Django поддерживает различные способы оптимизации:
- Кеширование на разных уровнях
- Поддержка CDN
- Оптимизация запросов к базе данных
- Асинхронная обработка запросов (начиная с версии 3.1)
Установка и настройка Django
Установка Django
Для установки Django рекомендуется использовать виртуальное окружение:
# Создание виртуального окружения
python -m venv django_env
# Активация окружения (Windows)
django_env\Scripts\activate
# Активация окружения (macOS/Linux)
source django_env/bin/activate
# Установка Django
pip install django
Создание нового проекта
# Создание проекта
django-admin startproject myproject
# Переход в директорию проекта
cd myproject
# Запуск сервера разработки
python manage.py runserver
После выполнения команд приложение будет доступно по адресу: http://127.0.0.1:8000/
Структура проекта Django
После создания проекта вы получите следующую структуру:
myproject/
│
├── manage.py # Интерфейс командной строки
├── myproject/
│ ├── __init__.py # Делает директорию Python-пакетом
│ ├── settings.py # Конфигурация проекта
│ ├── urls.py # Главные маршруты проекта
│ ├── wsgi.py # Точка входа для WSGI-серверов
│ └── asgi.py # Точка входа для ASGI-серверов
Описание основных файлов:
- manage.py — утилита командной строки для управления проектом
- settings.py — содержит все настройки проекта
- urls.py — определяет URL-маршруты приложения
- wsgi.py — конфигурация для развертывания на WSGI-серверах
- asgi.py — конфигурация для асинхронных серверов
Создание и настройка приложений
Создание нового приложения
python manage.py startapp blog
Регистрация приложения
В файле settings.py добавьте новое приложение в INSTALLED_APPS:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'blog', # Ваше приложение
]
Структура Django-приложения
blog/
├── __init__.py
├── admin.py # Настройка админ-панели
├── apps.py # Конфигурация приложения
├── models.py # Модели данных
├── views.py # Представления
├── urls.py # URL-маршруты приложения
├── tests.py # Тесты
├── migrations/ # Миграции базы данных
│ └── __init__.py
├── templates/ # HTML-шаблоны
└── static/ # Статические файлы
Маршрутизация и диспетчеризация URL
Настройка URL-маршрутов
В главном файле urls.py проекта:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('blog/', include('blog.urls')),
path('', include('blog.urls')), # Для главной страницы
]
Создайте файл blog/urls.py:
from django.urls import path
from . import views
app_name = 'blog'
urlpatterns = [
path('', views.index, name='index'),
path('post/<int:post_id>/', views.post_detail, name='post_detail'),
path('create/', views.create_post, name='create_post'),
]
Параметры URL
Django поддерживает различные типы параметров URL:
<int:id>— целое число<str:name>— строка<slug:slug>— строка с дефисами и подчеркиваниями<uuid:id>— UUID<path:path>— любой путь, включая слеши
Работа с моделями и ORM
Создание моделей
Определите модели в файле models.py:
from django.db import models
from django.contrib.auth.models import User
from django.urls import reverse
class Category(models.Model):
name = models.CharField(max_length=100, unique=True)
slug = models.SlugField(max_length=100, unique=True)
description = models.TextField(blank=True)
class Meta:
verbose_name_plural = "Categories"
def __str__(self):
return self.name
class Post(models.Model):
STATUS_CHOICES = [
('draft', 'Draft'),
('published', 'Published'),
]
title = models.CharField(max_length=200)
slug = models.SlugField(max_length=200, unique=True)
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='blog_posts')
content = models.TextField()
category = models.ForeignKey(Category, on_delete=models.CASCADE)
status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='draft')
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['-created']
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('blog:post_detail', args=[self.id])
Типы полей Django
| Поле | Назначение |
|---|---|
CharField(max_length) |
Строка фиксированной длины |
TextField() |
Длинный текст |
IntegerField() |
Целое число |
FloatField() |
Число с плавающей точкой |
BooleanField() |
Логическое значение |
DateField() |
Дата |
DateTimeField() |
Дата и время |
EmailField() |
Email-адрес |
URLField() |
URL-адрес |
SlugField() |
Строка для URL (латиница, цифры, дефисы) |
ImageField() |
Изображение |
FileField() |
Файл |
ForeignKey() |
Связь "многие к одному" |
ManyToManyField() |
Связь "многие ко многим" |
OneToOneField() |
Связь "один к одному" |
Миграции базы данных
# Создание миграций
python manage.py makemigrations
# Применение миграций
python manage.py migrate
# Просмотр SQL-кода миграции
python manage.py sqlmigrate blog 0001
# Откат миграции
python manage.py migrate blog 0001
Работа с QuerySet
# Получение всех объектов
posts = Post.objects.all()
# Фильтрация
published_posts = Post.objects.filter(status='published')
# Исключение
draft_posts = Post.objects.exclude(status='published')
# Получение одного объекта
post = Post.objects.get(id=1)
# Безопасное получение объекта
from django.shortcuts import get_object_or_404
post = get_object_or_404(Post, id=1)
# Создание объекта
post = Post.objects.create(title='New Post', content='Content')
# Обновление
Post.objects.filter(id=1).update(title='Updated Title')
# Удаление
Post.objects.filter(id=1).delete()
Административная панель Django
Регистрация моделей
В файле admin.py:
from django.contrib import admin
from .models import Post, Category
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
list_display = ('title', 'author', 'status', 'created')
list_filter = ('status', 'created', 'category')
search_fields = ('title', 'content')
prepopulated_fields = {'slug': ('title',)}
raw_id_fields = ('author',)
date_hierarchy = 'created'
ordering = ('status', 'created')
@admin.register(Category)
class CategoryAdmin(admin.ModelAdmin):
list_display = ('name', 'slug')
prepopulated_fields = {'slug': ('name',)}
Создание суперпользователя
python manage.py createsuperuser
Административная панель доступна по адресу: http://127.0.0.1:8000/admin/
Представления и обработка HTTP-запросов
Функциональные представления
from django.shortcuts import render, get_object_or_404, redirect
from django.http import HttpResponse, JsonResponse
from django.contrib.auth.decorators import login_required
from .models import Post, Category
def index(request):
posts = Post.objects.filter(status='published')
context = {'posts': posts}
return render(request, 'blog/index.html', context)
def post_detail(request, post_id):
post = get_object_or_404(Post, id=post_id, status='published')
context = {'post': post}
return render(request, 'blog/post_detail.html', context)
@login_required
def create_post(request):
if request.method == 'POST':
# Обработка формы
pass
return render(request, 'blog/create_post.html')
def json_posts(request):
posts = Post.objects.filter(status='published').values('title', 'content')
return JsonResponse(list(posts), safe=False)
Классовые представления
from django.views.generic import ListView, DetailView, CreateView
from django.contrib.auth.mixins import LoginRequiredMixin
class PostListView(ListView):
model = Post
template_name = 'blog/index.html'
context_object_name = 'posts'
paginate_by = 10
def get_queryset(self):
return Post.objects.filter(status='published')
class PostDetailView(DetailView):
model = Post
template_name = 'blog/post_detail.html'
context_object_name = 'post'
class PostCreateView(LoginRequiredMixin, CreateView):
model = Post
fields = ['title', 'content', 'category']
template_name = 'blog/create_post.html'
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
Работа с шаблонами
Создание шаблонов
Создайте директорию templates/blog/ и добавьте файлы шаблонов:
base.html:
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}Мой блог{% endblock %}</title>
{% load static %}
<link rel="stylesheet" href="{% static 'blog/css/style.css' %}">
</head>
<body>
<header>
<nav>
<a href="{% url 'blog:index' %}">Главная</a>
{% if user.is_authenticated %}
<a href="{% url 'blog:create_post' %}">Создать пост</a>
<a href="{% url 'admin:logout' %}">Выход</a>
{% else %}
<a href="{% url 'admin:login' %}">Вход</a>
{% endif %}
</nav>
</header>
<main>
{% block content %}
{% endblock %}
</main>
<footer>
<p>© 2024 Мой блог</p>
</footer>
</body>
</html>
index.html:
{% extends 'blog/base.html' %}
{% block title %}Главная - {{ block.super }}{% endblock %}
{% block content %}
<h1>Последние посты</h1>
{% for post in posts %}
<article>
<h2><a href="{% url 'blog:post_detail' post.id %}">{{ post.title }}</a></h2>
<p>Автор: {{ post.author.username }} | {{ post.created|date:"d.m.Y" }}</p>
<p>{{ post.content|truncatewords:20 }}</p>
</article>
{% empty %}
<p>Постов пока нет.</p>
{% endfor %}
{% if is_paginated %}
<nav>
{% if page_obj.has_previous %}
<a href="?page={{ page_obj.previous_page_number }}">Предыдущая</a>
{% endif %}
Страница {{ page_obj.number }} из {{ page_obj.paginator.num_pages }}
{% if page_obj.has_next %}
<a href="?page={{ page_obj.next_page_number }}">Следующая</a>
{% endif %}
</nav>
{% endif %}
{% endblock %}
Теги и фильтры шаблонов
| Тег/Фильтр | Описание |
|---|---|
{% extends %} |
Наследование шаблонов |
{% block %} |
Определение блока |
{% include %} |
Включение шаблона |
{% for %} |
Цикл |
{% if %} |
Условие |
{% url %} |
Генерация URL |
{% csrf_token %} |
CSRF-токен |
{% load %} |
Загрузка тегов |
| `{{ var | filter }}` |
| `{{ var | date:"Y-m-d" }}` |
| `{{ var | truncatewords:10 }}` |
| `{{ var | safe }}` |
Формы Django
Создание форм
from django import forms
from .models import Post, Category
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['title', 'content', 'category', 'status']
widgets = {
'title': forms.TextInput(attrs={'class': 'form-control'}),
'content': forms.Textarea(attrs={'class': 'form-control', 'rows': 10}),
'category': forms.Select(attrs={'class': 'form-control'}),
'status': forms.Select(attrs={'class': 'form-control'}),
}
def clean_title(self):
title = self.cleaned_data['title']
if len(title) < 5:
raise forms.ValidationError('Заголовок должен содержать минимум 5 символов')
return title
class CommentForm(forms.Form):
name = forms.CharField(max_length=100, widget=forms.TextInput(attrs={'class': 'form-control'}))
email = forms.EmailField(widget=forms.EmailInput(attrs={'class': 'form-control'}))
content = forms.CharField(widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 4}))
Обработка форм в представлениях
def create_post(request):
if request.method == 'POST':
form = PostForm(request.POST)
if form.is_valid():
post = form.save(commit=False)
post.author = request.user
post.save()
return redirect('blog:post_detail', post_id=post.id)
else:
form = PostForm()
return render(request, 'blog/create_post.html', {'form': form})
Работа с статическими файлами и медиа
Настройка статических файлов
В settings.py:
import os
# Статические файлы
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static'),
]
# Медиа файлы
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
Подключение статических файлов в URL
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
# ваши URL-паттерны
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
Сборка статических файлов
python manage.py collectstatic
Система аутентификации и авторизации
Встроенная система аутентификации
Django предоставляет готовую систему аутентификации с возможностями:
- Регистрация и авторизация пользователей
- Управление сессиями
- Разграничение прав доступа
- Группы пользователей и разрешения
Декораторы для ограничения доступа
from django.contrib.auth.decorators import login_required, permission_required
@login_required
def protected_view(request):
return render(request, 'protected.html')
@permission_required('blog.add_post')
def create_post(request):
return render(request, 'create_post.html')
Создание пользовательских форм аутентификации
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
class CustomUserCreationForm(UserCreationForm):
email = forms.EmailField(required=True)
class Meta:
model = User
fields = ('username', 'email', 'password1', 'password2')
def save(self, commit=True):
user = super().save(commit=False)
user.email = self.cleaned_data['email']
if commit:
user.save()
return user
Создание REST API с Django REST Framework
Установка и настройка DRF
pip install djangorestframework
В settings.py:
INSTALLED_APPS = [
# ...
'rest_framework',
# ...
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 20,
}
Создание сериализаторов
from rest_framework import serializers
from .models import Post, Category
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = ['id', 'name', 'slug', 'description']
class PostSerializer(serializers.ModelSerializer):
author = serializers.StringRelatedField(read_only=True)
category = CategorySerializer(read_only=True)
class Meta:
model = Post
fields = ['id', 'title', 'slug', 'author', 'content', 'category', 'status', 'created', 'updated']
read_only_fields = ['author', 'created', 'updated']
API-представления
from rest_framework import viewsets, permissions, status
from rest_framework.decorators import action
from rest_framework.response import Response
class PostViewSet(viewsets.ModelViewSet):
queryset = Post.objects.filter(status='published')
serializer_class = PostSerializer
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
def perform_create(self, serializer):
serializer.save(author=self.request.user)
@action(detail=True, methods=['post'])
def like(self, request, pk=None):
post = self.get_object()
# Логика лайка
return Response({'status': 'liked'})
Middleware и обработка запросов
Создание пользовательского middleware
class SimpleMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# Код, выполняемый перед обработкой request
response = self.get_response(request)
# Код, выполняемый после обработки request
return response
def process_exception(self, request, exception):
# Обработка исключений
pass
Регистрация middleware
В settings.py:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'myapp.middleware.SimpleMiddleware', # Ваш middleware
]
Тестирование Django-приложений
Создание тестов
from django.test import TestCase, Client
from django.contrib.auth.models import User
from django.urls import reverse
from .models import Post, Category
class PostModelTest(TestCase):
def setUp(self):
self.user = User.objects.create_user(
username='testuser',
password='testpass123'
)
self.category = Category.objects.create(
name='Test Category',
slug='test-category'
)
def test_post_creation(self):
post = Post.objects.create(
title='Test Post',
content='Test content',
author=self.user,
category=self.category
)
self.assertEqual(post.title, 'Test Post')
self.assertEqual(str(post), 'Test Post')
def test_post_absolute_url(self):
post = Post.objects.create(
title='Test Post',
content='Test content',
author=self.user,
category=self.category
)
self.assertEqual(post.get_absolute_url(), f'/blog/post/{post.id}/')
class PostViewTest(TestCase):
def setUp(self):
self.client = Client()
self.user = User.objects.create_user(
username='testuser',
password='testpass123'
)
self.category = Category.objects.create(
name='Test Category',
slug='test-category'
)
def test_post_list_view(self):
response = self.client.get(reverse('blog:index'))
self.assertEqual(response.status_code, 200)
def test_post_detail_view(self):
post = Post.objects.create(
title='Test Post',
content='Test content',
author=self.user,
category=self.category,
status='published'
)
response = self.client.get(reverse('blog:post_detail', args=[post.id]))
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'Test Post')
Запуск тестов
# Запуск всех тестов
python manage.py test
# Запуск тестов конкретного приложения
python manage.py test blog
# Запуск с подробным выводом
python manage.py test --verbosity=2
# Запуск с сохранением тестовой БД
python manage.py test --keepdb
Кеширование в Django
Настройка кеширования
В settings.py:
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.redis.RedisCache',
'LOCATION': 'redis://127.0.0.1:6379/1',
}
}
Использование кеша
from django.core.cache import cache
from django.views.decorators.cache import cache_page
# Кеширование в представлениях
@cache_page(60 * 15) # кеш на 15 минут
def slow_view(request):
# медленная операция
return render(request, 'slow_template.html')
# Низкоуровневое кеширование
def get_posts():
posts = cache.get('blog_posts')
if posts is None:
posts = Post.objects.filter(status='published')
cache.set('blog_posts', posts, 60 * 30) # 30 минут
return posts
Основные команды manage.py
| Команда | Описание |
|---|---|
runserver |
Запуск сервера разработки |
startapp <name> |
Создание нового приложения |
makemigrations |
Создание миграций |
migrate |
Применение миграций |
createsuperuser |
Создание суперпользователя |
collectstatic |
Сборка статических файлов |
shell |
Интерактивная оболочка Django |
test |
Запуск тестов |
dbshell |
Консоль базы данных |
flush |
Очистка базы данных |
dumpdata |
Экспорт данных |
loaddata |
Импорт данных |
Методы и функции Django ORM
| Метод | Описание |
|---|---|
objects.all() |
Получение всех объектов |
objects.filter() |
Фильтрация объектов |
objects.exclude() |
Исключение объектов |
objects.get() |
Получение одного объекта |
objects.create() |
Создание объекта |
objects.update() |
Обновление объектов |
objects.delete() |
Удаление объектов |
objects.count() |
Подсчет количества |
objects.exists() |
Проверка существования |
objects.first() |
Первый объект |
objects.last() |
Последний объект |
objects.distinct() |
Уникальные значения |
objects.order_by() |
Сортировка |
objects.select_related() |
Оптимизация JOIN |
objects.prefetch_related() |
Оптимизация связей |
Развертывание Django-проекта
Подготовка к развертыванию
- Создание requirements.txt:
pip freeze > requirements.txt
- Настройка production settings:
# settings/production.py
from .base import *
DEBUG = False
ALLOWED_HOSTS = ['yourdomain.com']
# База данных
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'your_db_name',
'USER': 'your_db_user',
'PASSWORD': 'your_db_password',
'HOST': 'localhost',
'PORT': '5432',
}
}
# Безопасность
SECURE_SSL_REDIRECT = True
SECURE_HSTS_SECONDS = 31536000
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
Варианты развертывания
- Традиционный сервер (Gunicorn + Nginx)
- Контейнеризация (Docker)
- Облачные платформы (Heroku, Railway, Render)
- Облачные провайдеры (AWS, GCP, Azure)
Пример Dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "myproject.wsgi:application"]
Практические примеры применения Django
Корпоративные системы
- CRM и ERP системы
- Внутренние порталы компаний
- Системы документооборота
- HR-системы
Контент-платформы
- Новостные сайты
- Блоги и журналы
- Форумы и социальные сети
- Образовательные платформы
Электронная коммерция
- Интернет-магазины
- Маркетплейсы
- Системы онлайн-бронирования
- Финтех-решения
API и микросервисы
- RESTful API
- GraphQL эндпоинты
- Микросервисная архитектура
- Интеграции с внешними системами
Часто задаваемые вопросы
Что такое Django и для чего он используется?
Django — это высокоуровневый веб-фреймворк для Python, который поощряет быстрое развитие и чистый, прагматичный дизайн. Он используется для создания веб-приложений любой сложности: от простых сайтов до крупных корпоративных систем.
Чем Django отличается от Flask?
Django — это полнофункциональный фреймворк "из коробки", который включает ORM, админ-панель, систему аутентификации и многое другое. Flask — это микрофреймворк, предоставляющий только базовый функционал, остальное добавляется через расширения.
Какие базы данных поддерживает Django?
Django поддерживает PostgreSQL, MySQL, SQLite, Oracle и другие базы данных через соответствующие драйверы. PostgreSQL рекомендуется для production-среды.
Подходит ли Django для создания REST API?
Да, Django отлично подходит для создания REST API, особенно в сочетании с Django REST Framework, который предоставляет мощные инструменты для разработки API.
Поддерживает ли Django асинхронное программирование?
Начиная с версии 3.1, Django поддерживает асинхронные представления и middleware через ASGI. Полная поддержка асинхронности продолжает развиваться.
Как обеспечить безопасность Django-приложения?
Django имеет встроенную защиту от основных уязвимостей (XSS, CSRF, SQL-инъекции). Дополнительно следует использовать HTTPS, регулярно обновлять зависимости, правильно настраивать production-среду и следовать рекомендациям по безопасности.
Можно ли использовать Django для больших проектов?
Да, Django успешно используется в крупных проектах. Instagram, Pinterest, Mozilla, NASA и многие другие крупные компании используют Django для своих веб-приложений.
Настоящее и будущее развития ИИ: классической математики уже недостаточно
Эксперты предупредили о рисках фейковой благотворительности с помощью ИИ
В России разработали универсального ИИ-агента для роботов и индустриальных процессов