ОТКРЫТЬ ФАЙЛ С ИНСТРУКЦИЕЙ
ctrl + shift + p
linarik.open
- python -m pip install --upgrade pip (Устанавливаю менеджер пакетов)
- python -m venv .venv (Создаю виртуальное окружение)
- .venv\Scripts\activate (Активируем виртуальное окружение)
- pip install Django (Установка джанго)
- django-admin startproject bobr (Создание админ панели)
- cd bobr (Выбираем папку с проектом)
- python manage.py startapp exam
- прописываем в файле settings: в инсталлед апс прописываем название приложения: 'exam.apps.ExamConfig'
- python manage.py runserver
- python manage.py migrate
- python manage.py createsuperuser
- Дальше в файле models.py указываете код модели
13. После этого нужно создать миграции
python manage.py makemigrations
14. Теперь накатить их
python manage.py migrate
# 📘 Django Models: Краткий гайд по типам данных и связям
## 🔹 Основные типы полей
| Тип поля | Назначение |
| -------------------------- | --------------------------------------- |
| `CharField` | Строка с ограничением по длине |
| `TextField` | Длинный текст |
| `IntegerField` | Целое число |
| `FloatField` | Число с плавающей точкой |
| `BooleanField` | Логическое значение (`True` / `False`) |
| `DateField` | Дата (`YYYY-MM-DD`) |
| `DateTimeField` | Дата и время |
| `EmailField` | E-mail адрес |
| `URLField` | URL |
| `DecimalField` | Десятичное число (точность фиксируется) |
| `FileField` / `ImageField` | Загрузка файлов и изображений |
| `AutoField` | Автоинкрементное поле (обычно `id`) |
---
## 🔗 Связи между моделями
Django поддерживает три типа связей:
### 🔸 One-to-Many (многие к одному)
```python
class Author(models.Model):
name = models.CharField(max_length=100)
class Book(models.Model):
author = models.ForeignKey(Author, on_delete=models.CASCADE)
title = models.CharField(max_length=200)
🔸 One-to-Many (многие ко многим)
class Student(models.Model):
name = models.CharField(max_length=100)
class Course(models.Model):
students = models.ManyToManyField(Student)
title = models.CharField(max_length=200)
##Наглядный пример
импорты в файле модели
`from django.db import models`
`from django.core.exceptions import ValidationError`
class вклады(models.Model):
кодТипаВклада = models.ForeignKey('типВклада', on_delete=models.CASCADE,verbose_name="Тип вклада")
минимальныйСрокВклада = models.IntegerField(verbose_name="минимальный срок вклада (месяцев)")
минимальнаяСуммаВклада = models.FloatField(verbose_name="минимальная сумма вклада")
кодВалюты = models.ForeignKey('курсВалют', on_delete=models.CASCADE,verbose_name="Валюта")
процентнаяСтавка = models.FloatField()
def clean(self):
# Пример валидации на уровне модели
if self.минимальнаяСуммаВклада < 100:
raise ValidationError({'минимальнаяСуммаВклада': 'Минимальная сумма вклада не может быть меньше 100.'})
def __str__(self):
return f"Тип: {self.кодТипаВклада} Мин.Срок: {self.минимальныйСрокВклада} Валюта: {self.кодВалюты} Мин.Сумма: {self.минимальнаяСуммаВклада} Ставка: {self.процентнаяСтавка}%"
class вклады(models.Model) - создаем класс аналогичный нашей таблице
минимальныйСрокВклада = models.IntegerField(verbose_name="минимальный срок вклада (месяцев)") - поле таблицы где после models указываются тип поля
verbose_name - то как поле будет называться при отображении в админке
кодВалюты = models.ForeignKey('курсВалют', on_delete=models.CASCADE,verbose_name="Валюта") - поле с указанием ключа обязательно прописываем каскадное удаление
class Meta:
verbose_name_plural = 'Регистрация вкладов' - прописываем эту штуку внутри класса чтобы изменить отображение названия таблицы
def clean(self):
# Пример валидации на уровне модели
if self.минимальнаяСуммаВклада < 100:
raise ValidationError({'минимальнаяСуммаВклада': 'Минимальная сумма вклада не может быть меньше 100.'})
функция которая позволит написать свою обработку ошибок условие -> сообщение
По умолчанию все поля обязательны
def __str__(self):
return f"{self.ФИО}"
функция для того что бы вместо кода записи выводить какие либо данные вместо ключа
class cотрудники(models.Model):
должность = models.CharField(max_length=100)
ФИО = models.CharField()
оклад = models.FloatField()
вклады = models.ManyToManyField('вклады', through='регистрацияВкладов')
вклады = models.ManyToManyField('вклады', through='регистрацияВкладов') - это связь многие ко многим первым параметром мы указываем с какой таблицей мы связываем текущую, а вторым параметром смежную таблицу в которой есть и те и те ключи
from django.contrib import admin
from .models import клиенты,cотрудники,курсВалют,типВклада,вклады,регистрацияВкладов
*Импортируем все модели из класса models*
@admin.register(клиенты) *Регистрируем модель*
class клиенты(admin.ModelAdmin):
pass
@admin.register(cотрудники)
class cотрудники(admin.ModelAdmin):
list_display = ('ФИО', 'должность', 'оклад') * указываем какие поля должны выводиться*
@admin.register(курсВалют)
class курсВалют(admin.ModelAdmin):
list_display = ('наименование', 'курВалют')
@admin.register(типВклада)
class типВклада(admin.ModelAdmin):
pass
@admin.register(вклады)
class вклады(admin.ModelAdmin):
pass
@admin.register(регистрацияВкладов)
class регистрацияВкладов(admin.ModelAdmin):
pass
код файла админки
НЕ ЗАБЫВАЕМ СОЗДАВАТЬ МИГРАЦИИ python manage.py migrate
И НАКАТЫВАТЬ МИГРАЦИИ python manage.py makemigration
если что то сломалось то удаляем файл с базой данных и удаляем миграции кроме init.py и pycache
#Пример валидации с разными таблицами
class регистрацияВкладов(models.Model):
кодКлиента = models.ForeignKey('клиенты', on_delete=models.CASCADE, verbose_name="Клиент")
кодВклада = models.ForeignKey('вклады', on_delete=models.CASCADE, verbose_name="Вклад")
датаВклада = models.DateField( verbose_name="Дата вклада")
кодСотрудника = models.ForeignKey('cотрудники', on_delete=models.CASCADE, verbose_name="Сотрудник")
сумма = models.FloatField( verbose_name="Сумма")
class Meta:
verbose_name_plural = 'Регистрация вкладов'
def clean(self): # Вызываем метод clean() родительского класса
if self.кодВклада and self.сумма < self.кодВклада.минимальнаяСуммаВклада:
raise ValidationError({'сумма': f'Сумма вклада не может быть меньше минимальной суммы для данного типа вклада ({self.кодВклада.минимальнаяСуммаВклада}).'})
Подробный гайд по запросам в Django ORM
Django ORM (Object-Relational Mapper) предоставляет мощный и удобный способ взаимодействия с базами данных, абстрагируясь от написания SQL-запросов. Вместо этого вы работаете с Python-объектами моделей.
1. Основы QuerySet
Что такое QuerySet?
- QuerySet представляет собой ленивый набор записей из вашей модели. Это означает, что запрос к базе данных не выполняется до тех пор, пока вы не попытаетесь использовать QuerySet (например, при итерации, взятии среза, вызове
len()
и т.д.).
- QuerySet'ы можно создавать, фильтровать, упорядочивать и выполнять над ними различные операции.
Менеджеры:
- Каждая модель Django имеет менеджер по умолчанию, называемый
objects
.
- Именно через менеджер вы создаете начальные QuerySet'ы для вашей модели.
- Пример:
Клиент.objects
(возвращает QuerySet, содержащий все записи из таблицы клиенты
).
2. Фильтрация данных (filter()
, exclude()
)
filter()
:
Используется для отбора записей, которые соответствуют определенным условиям.
Условия передаются как ключевые аргументы, где ключ - имя поля модели, а значение - искомое значение.
Связь полей: Для доступа к полям связанных моделей используется двойное подчеркивание (__
).
Операторы сравнения: Django предоставляет различные операторы сравнения, которые можно использовать с filter()
:
exact
: Точное совпадение (по умолчанию, если не указан оператор).
iexact
: Точное совпадение без учета регистра.
contains
: Содержит подстроку (с учетом регистра).
icontains
: Содержит подстроку (без учета регистра).
startswith
: Начинается с подстроки (с учетом регистра).
istartswith
: Начинается с подстроки (без учета регистра).
endswith
: Заканчивается подстрокой (с учетом регистра).
iendswith
: Заканчивается подстрокой (без учета регистра).
gt
: Больше чем.
gte
: Больше или равно.
lt
: Меньше чем.
lte
: Меньше или равно.
in
: Значение находится в списке.
range
: Значение находится в диапазоне (принимает кортеж или список из двух элементов).
isnull
: Поле равно NULL
(True
) или нет (False
).
regex
: Соответствует регулярному выражению (с учетом регистра).
iregex
: Соответствует регулярному выражению (без учета регистра).
Примеры:
# Получить всех клиентов с именем "Иван"
иваны = Клиент.objects.filter(ФИО='Иван')
# Получить все вклады с минимальной суммой больше 1000
дорогие_вклады = Вклад.objects.filter(минимальнаяСуммаВклада__gt=1000)
# Получить все регистрации вкладов за определенную дату
регистрации_за_дату = РегистрацияВкладов.objects.filter(датаВклада='2025-05-07')
# Получить клиентов, у которых есть вклады типа "Срочный"
клиенты_со_срочными = Клиент.objects.filter(вклады__кодТипаВклада__наименование='Срочный')
# Получить клиентов из городов "Амстердам" или "Роттердам" (используя Q-объекты)
from django.db.models import Q
клиенты_из_городов = Клиент.objects.filter(Q(город='Амстердам') | Q(город='Роттердам'))
exclude()
:
Используется для отбора записей, которые не соответствуют определенным условиям.
Синтаксис аналогичен filter()
.
Пример:
# Получить всех клиентов, кроме тех, кто из города "Амстердам"
не_амстердамцы = Клиент.objects.exclude(город='Амстердам')
3. Получение одной записи (get()
)
4. Упорядочивание результатов (order_by()
)
- Используется для сортировки записей в QuerySet по одному или нескольким полям.
- По умолчанию сортировка выполняется по возрастанию.
- Чтобы отсортировать по убыванию, добавьте префикс
-
перед именем поля.
- Примеры:
# Получить всех клиентов, отсортированных по имени по возрастанию
клиенты_по_имени_возрастание = Клиент.objects.order_by('ФИО')
# Получить все вклады, отсортированные по минимальной сумме по убыванию
вклады_по_сумме_убывание = Вклад.objects.order_by('-минимальнаяСуммаВклада')
# Сортировка по нескольким полям (сначала по городу, затем по имени)
клиенты_по_городу_и_имени = Клиент.objects.order_by('город', 'ФИО')
5. Выбор определенных полей (values()
, values_list()
)
values()
:
Возвращает QuerySet, состоящий из словарей. Каждый словарь представляет запись и содержит только указанные поля.
Если аргументы не переданы, возвращает все поля.
Примеры:
# Получить имена и города всех клиентов в виде словарей
данные_клиентов = Клиент.objects.values('ФИО', 'город')
# Результат: [{'ФИО': 'Иван', 'город': 'Москва'}, {'ФИО': 'Петр', 'город': 'Санкт-Петербург'}, ...]
values_list()
:
Аналогичен values()
, но возвращает QuerySet, состоящий из кортежей (tuples) вместо словарей.
Можно передать flat=True
, чтобы получить список отдельных значений, если выбирается только одно поле.
Примеры:
# Получить имена всех клиентов в виде кортежей
имена_клиентов_кортежи = Клиент.objects.values_list('ФИО')
# Результат: [('Иван',), ('Петр',), ...]
# Получить имена всех клиентов в виде плоского списка
имена_клиентов_список = Клиент.objects.values_list('ФИО', flat=True)
# Результат: ['Иван', 'Петр', ...]
6. Агрегация данных (aggregate()
)
Используется для выполнения агрегирующих функций (например, среднее значение, сумма, количество и т.д.) над всем QuerySet'ом.
Возвращает словарь, содержащий результаты агрегации.
Доступные агрегатные функции: Count
, Sum
, Avg
, Max
, Min
. Их нужно импортировать из django.db.models
.
Примеры:
from django.db.models import Count, Sum, Avg
# Получить общее количество клиентов
общее_количество_клиентов = Клиент.objects.aggregate(количество=Count('id'))
# Результат: {'количество': 100}
# Получить средний оклад всех сотрудников
средний_оклад = Сотрудник.objects.aggregate(средний=Avg('оклад'))
# Результат: {'средний': 50000.0}
# Получить минимальную и максимальную сумму вклада
диапазон_сумм = Вклад.objects.aggregate(мин_сумма=Min('минимальнаяСуммаВклада'), макс_сумма=Max('минимальнаяСуммаВклада'))
# Результат: {'мин_сумма': 100.0, 'макс_сумма': 10000.0}
7. Аннотирование данных (annotate()
)
Используется для добавления временных полей к каждому объекту в QuerySet. Эти поля вычисляются на основе агрегирующих функций или других выражений, связанных с каждым объектом.
Возвращает QuerySet, где каждый объект имеет дополнительный атрибут (или атрибуты) с результатами аннотации.
Примеры:
from django.db.models import Count
# Получить всех клиентов и количество их вкладов
клиенты_с_кол_вкладов = Клиент.objects.annotate(num_vkladov=Count('регистрациявкладов'))
# Теперь каждый объект Клиент в QuerySet имеет атрибут 'num_vkladov'
# Получить типы вкладов и количество зарегистрированных вкладов для каждого типа
типы_вкладов_с_кол_регистраций = ТипВклада.objects.annotate(num_registrations=Count('вклады'))
# Теперь каждый объект ТипВклада имеет атрибут 'num_registrations'
8. Работа со связанными объектами
ForeignKey:
- Для доступа к связанному объекту используется напрямую имя поля ForeignKey.
- Пример:
регистрация.кодКлиента
(получит объект Клиент
, связанный с данной РегистрацияВкладов
).
- Для доступа к атрибутам связанного объекта используется цепочка:
регистрация.кодКлиента.ФИО
.
ManyToMany:
- Django автоматически создает менеджер для доступа к связанным объектам ManyToManyField. По умолчанию имя этого менеджера -
имя_поля_многих_ко_многим_set
.
- Пример:
клиент.вклады_set.all()
(получит QuerySet всех объектов Вклад
, связанных с данным Клиент
).
- Можно использовать методы менеджера:
add()
, remove()
, clear()
.
Обратные связи:
- Если у модели
B
есть ForeignKey на модель A
, то у каждого экземпляра A
автоматически появляется менеджер для доступа к связанным объектам B
. Имя этого менеджера по умолчанию - имя_модели_B_в_нижнем_регистре_set
.
- Пример:
клиент.регистрациявкладов_set.all()
(получит QuerySet всех объектов РегистрацияВкладов
, связанных с данным Клиент
).
- Можно изменить имя обратной связи с помощью аргумента
related_name
в определении ForeignKey или ManyToManyField.
По умолчанию Django выполняет запросы к базе данных по мере необходимости при доступе к связанным объектам (проблема N+1).
Для оптимизации количества запросов используются select_related()
и prefetch_related()
.
select_related()
:
Используется для жадной загрузки связанных объектов через ForeignKey и OneToOneField с помощью SQL-JOIN'ов.
Рекомендуется использовать, когда вы знаете, что будете часто обращаться к этим связанным объектам.
Пример:
# Загрузить информацию о типе вклада и валюте вместе с каждым вкладом
вклады_с_связями = Вклад.objects.select_related('кодТипаВклада', 'кодВалюты').all()
prefetch_related()
:
Используется для жадной загрузки связанных объектов через ManyToManyField и обратных ForeignKey.
Выполняет отдельные запросы для каждой связи и кэширует результаты.
Подходит для связей "многие-ко-многим" и обратных внешних ключей.
Пример:
# Загрузить все вклады для каждого клиента одним дополнительным запросом
клиенты_с_вкладами = Клиент.objects.prefetch_related('вклады').all()
10. Выполнение необработанных SQL-запросов
Хотя Django ORM покрывает большинство случаев использования, иногда может потребоваться выполнение необработанных SQL-запросов.
Это можно сделать с помощью django.db.connection
.
Пример:
from django.db import connection
with connection.cursor() as cursor:
cursor.execute("SELECT * FROM exam_клиенты WHERE город = %s", ['Амстердам'])
rows = cursor.fetchall()
for row in rows:
print(row)
Рекомендации:
- Старайтесь максимально использовать возможности Django ORM, чтобы обеспечить переносимость кода между разными базами данных.
- Используйте
select_related()
и prefetch_related()
для оптимизации производительности при работе со связанными объектами.
- Понимайте ленивую природу QuerySet'ов, чтобы избежать неожиданных запросов к базе данных.
- Обращайтесь к официальной документации Django для более подробной информации и примеров.
Как создать такой запрос и привязать его к админке
создай в файле админ панели новую сущность
@action отвчает за событие которое может быть у модели в админке, его можно применить для получения информации о каком либо элементе или использовать для фильтрации.
```
from django.contrib import admin
from django.db.models import Count
from .models import клиенты, cотрудники, курсВалют, типВклада, вклады, регистрацияВкладов
from django.urls import reverse
from django.http import HttpResponseRedirect
@admin.action(description='Показать самого богатого вкладчика (по количеству вкладов)')
def найти_клиента_с_макс_вкладами(modeladmin, request, queryset):
клиент_с_макс_вкладами = клиенты.objects.annotate(num_vkladov=Count('регистрациявкладов')).order_by('-num_vkladov').first()
if клиент_с_макс_вкладами:
url = reverse('admin:exam_клиенты_changelist') + f'?id={клиент_с_макс_вкладами.id}'
return HttpResponseRedirect(url)
else:
modeladmin.message_user(request, "Нет зарегистрированных клиентов.")
@admin.action(description='Показать клиентов, в чьем ФИО есть буква "а"')
def показать_клиентов_с_буквой_а(modeladmin, request, queryset):
url = reverse('admin:exam_клиенты_changelist') + '?ФИО__icontains=а'
return HttpResponseRedirect(url)
@admin.action(description='Показать всех клиентов')
def показать_всех_клиентов(modeladmin, request, queryset):
url = reverse('admin:exam_клиенты_changelist')
return HttpResponseRedirect(url)
@admin.register(клиенты)
class КлиентыAdmin(admin.ModelAdmin):
list_display = ('ФИО',)
actions = [найти_клиента_с_макс_вкладами,показать_клиентов_с_буквой_а,показать_всех_клиентов]
```
1. Создание таблиц
CREATE TABLE Клиенты (
ID INT PRIMARY KEY IDENTITY(1,1) NOT NULL,
Фамилия VARCHAR(25) NOT NULL,
Имя VARCHAR(25) NOT NULL,
Отчество VARCHAR(25)
);
Изменение поля
ALTER TABLE Должности
ALTER COLUMN Название VARCHAR(50);
Удаление поля
ALTER TABLE Таблица
DROP COLUMN Название_поля;
Удаление связи
ALTER TABLE ТипыВкладов
DROP CONSTRAINT FK__ТипыВклад__ID_Ва__3B75D760;
Добавление связи
ALTER TABLE ТипыВкладов
ADD CONSTRAINT ID_Валюта FOREIGN KEY (ID_Валюта) REFERENCES Валюта(ID) ON DELETE CASCADE;
Вставка данных
INSERT INTO Клиенты (Фамилия, Имя, Отчество) VALUES
('Иван', 'Петрович', 'Кузнецов'),
('Мария', 'Алексеевна', 'Попова'),
('Алексей', 'Владимирович', 'Соколов');
Создание DB класса -
internal class DB
{
public string ConnectionString()
{
return @"Data Source=TURYGIN\MSSQLSERVER01;Initial Catalog=УчётВкладов;Integrated Security=True;";
}
public SqlDataAdapter queryException(string query)
{
try
{
SqlConnection connection = new SqlConnection(ConnectionString());
connection.Open();
SqlDataAdapter dataAdapter = new SqlDataAdapter(query, connection);
dataAdapter.SelectCommand.ExecuteNonQuery();
return dataAdapter;
}
catch (Exception ex)
{
MessageBox.Show($"Ошибка - {ex.Message}", "Ошибка");
return null;
}
}
}
Добавление, удаление, редактирование данный в Windows Form
private void AddButton_Click(object sender, EventArgs e)
{
var add = $"insert into ТипыВкладов(Наименование, МинСуммаВклада, ID_Валюта, ПроцентСтавка, МинСрокВклада) values ('{NameBox.Text}', '{MinSumBox.Text}', '{IDValBox.Text}', '{StavkaBox.Text}', '{MinSrokBox.Text}')";
if(dB.queryException(add) != null)
{
RefreshDataGrid();
MessageBox.Show("Данный добавлены успешно!", "Успех");
}
}
private void RefreshButton_Click_1(object sender, EventArgs e)
{
RefreshDataGrid();
}
private void RefreshDataGrid()
{
this.типыВкладовTableAdapter.Fill(this.учётВкладовDataSet.ТипыВкладов);
}
private void EditButton_Click_1(object sender, EventArgs e)
{
var edit = $"update ТипыВкладов set Наименование = '{EdinNameBox.Text}', МинСуммаВклада = '{EditMinSumBox.Text}', ID_Валюта = '{EditIDValBox.Text}', ПроцентСтавка = '{EditProsBox.Text}', МинСрокВклада = '{EditMinSrokBox.Text}' where ID = {EditIDBox.Text}";
if(dB.queryException(edit) != null)
{
RefreshDataGrid();
MessageBox.Show("Данные успешно изменены!", "Успех");
}
}
private void DelButton_Click(object sender, EventArgs e)
{
var del = $"delete ТипыВкладов where ID = {DelBox.Text}";
if(dB.queryException(del) != null)
{
RefreshDataGrid();
MessageBox.Show("Данные успешно удалены!", "Успех");
}
}
}