Полный models.py — Library Project
Финальная версия после прохождения всех 15 задач практикума.
Импорты и константы
from django.db import models
from django.core.validators import MinValueValidator, MaxValueValidator
from django.utils import timezone
# --- Choices ---
GENDER_CHOICES = [
('Male', 'Мужской'),
('Female', 'Женский'),
('Other', 'Другой'),
]
ROLE_CHOICES = [
('Admin', 'Администратор'),
('Staff', 'Сотрудник'),
('Reader', 'Читатель'),
]
GENRE_CHOICES = [
('Fiction', 'Художественная'),
('Non-Fiction', 'Документальная'),
('Science Fiction', 'Научная фантастика'),
('Fantasy', 'Фэнтези'),
('Mystery', 'Детектив'),
('Biography', 'Биография'),
]
Модель Author
class Author(models.Model):
first_name = models.CharField(max_length=100, verbose_name="Имя")
last_name = models.CharField(max_length=100, verbose_name="Фамилия")
birth_date = models.DateField(verbose_name="Дата рождения")
profile = models.URLField(null=True, blank=True, verbose_name="Ссылка на профиль")
deleted = models.BooleanField(
default=False,
verbose_name="Удалён ли автор",
help_text="Если False - автор активен. Если True - автора больше нет в списке доступных"
)
rating = models.IntegerField(
default=1,
validators=[MinValueValidator(1), MaxValueValidator(10)],
verbose_name="Рейтинг автора"
)
def __str__(self):
# Задача 14: имя и инициал фамилии
return f"{self.first_name} {self.last_name[0]}."
class Meta:
verbose_name = "Автор"
verbose_name_plural = "Авторы"
Модель AuthorDetail (OneToOne)
class AuthorDetail(models.Model):
# OneToOne: у каждого автора — одна запись с деталями
author = models.OneToOneField(Author, on_delete=models.CASCADE, related_name='details')
biography = models.TextField()
birth_city = models.CharField(max_length=50)
gender = models.CharField(max_length=50, choices=GENDER_CHOICES)
def __str__(self):
return f"Детали: {self.author}"
class Meta:
verbose_name = "Детали автора"
verbose_name_plural = "Детали авторов"
Модель Category и Library
class Category(models.Model):
name = models.CharField(max_length=30, unique=True)
def __str__(self):
return self.name
class Meta:
verbose_name = "Категория"
verbose_name_plural = "Категории"
class Library(models.Model):
name = models.CharField(max_length=100)
location = models.CharField(max_length=200)
site = models.URLField(null=True, blank=True)
def __str__(self):
return self.name
class Meta:
verbose_name = "Библиотека"
verbose_name_plural = "Библиотеки"
Модель Member
class Member(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
email = models.EmailField(unique=True)
gender = models.CharField(max_length=50, choices=GENDER_CHOICES)
birth_date = models.DateField()
age = models.IntegerField(validators=[MinValueValidator(6), MaxValueValidator(120)])
role = models.CharField(max_length=20, choices=ROLE_CHOICES)
active = models.BooleanField(default=True)
# ManyToMany: участник может состоять в нескольких библиотеках
libraries = models.ManyToManyField('Library', related_name='members')
def __str__(self):
return f"{self.first_name} {self.last_name} ({self.role})"
class Meta:
verbose_name = "Участник"
verbose_name_plural = "Участники"
Модель Book (центральная)
class Book(models.Model):
title = models.CharField(max_length=100)
# ForeignKey на Author: при удалении автора книга остаётся (SET_NULL)
author_id = models.ForeignKey(Author, null=True, on_delete=models.SET_NULL)
publishing_date = models.DateField()
summary = models.TextField(null=True, blank=True)
genre = models.CharField(max_length=50, null=True, choices=GENRE_CHOICES)
page_count = models.IntegerField(
null=True, blank=True,
validators=[MaxValueValidator(10000)]
)
# ForeignKey на Category (один ко многим)
category = models.ForeignKey(
Category, null=True, on_delete=models.SET_NULL, related_name='books'
)
# ManyToMany с Library: книга может быть в нескольких библиотеках
libraries = models.ManyToManyField(Library, related_name='books')
# ForeignKey на Member (заменил Publisher в задаче 9)
publisher_id = models.ForeignKey(Member, null=True, on_delete=models.CASCADE)
@property
def rating(self):
"""Средний рейтинг по всем отзывам (задача 12)."""
reviews = self.reviews.all()
total_reviews = reviews.count()
if total_reviews == 0:
return 0
total_rating = sum(review.rating for review in reviews)
return round(total_rating / total_reviews, 2)
def __str__(self):
return self.title
class Meta:
verbose_name = "Книга"
verbose_name_plural = "Книги"
Модели Borrow и Review
class Borrow(models.Model):
member = models.ForeignKey(Member, on_delete=models.CASCADE, related_name='borrows')
book = models.ForeignKey(Book, on_delete=models.CASCADE, related_name='borrows')
library = models.ForeignKey(Library, on_delete=models.CASCADE, related_name='borrows')
borrow_date = models.DateField()
return_date = models.DateField()
returned = models.BooleanField(default=False)
def is_overdue(self):
"""Проверить просрочку возврата."""
if self.returned:
return False
return self.return_date < timezone.now().date()
def __str__(self):
return f"{self.member} → {self.book}"
class Meta:
verbose_name = "Выдача книги"
verbose_name_plural = "Выдачи книг"
class Review(models.Model):
book = models.ForeignKey(Book, on_delete=models.CASCADE, related_name='reviews')
reviewer = models.ForeignKey(Member, on_delete=models.CASCADE, related_name='reviews')
rating = models.FloatField()
description = models.TextField()
def __str__(self):
return f"Отзыв {self.reviewer} на {self.book}: {self.rating}"
class Meta:
verbose_name = "Отзыв"
verbose_name_plural = "Отзывы"
Модели Posts, Event, EventParticipant
class Posts(models.Model):
# unique_for_date: заголовок уникален в рамках одного дня
title = models.CharField(max_length=255, unique_for_date='created_at')
body = models.TextField()
author = models.ForeignKey(Member, on_delete=models.CASCADE, related_name='posts')
moderated = models.BooleanField(default=False)
library = models.ForeignKey(Library, on_delete=models.CASCADE, related_name='posts')
created_at = models.DateField()
updated_at = models.DateField(auto_now=True) # обновляется автоматически
def __str__(self):
return self.title
class Meta:
verbose_name = "Пост"
verbose_name_plural = "Посты"
class Event(models.Model):
title = models.CharField(max_length=255)
description = models.TextField()
date = models.DateField()
library = models.ForeignKey(Library, on_delete=models.CASCADE, related_name='events')
books = models.ManyToManyField(Book, related_name='events')
def __str__(self):
return self.title
class Meta:
verbose_name = "Событие"
verbose_name_plural = "События"
class EventParticipant(models.Model):
event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name='participants')
member = models.ManyToManyField(Member, related_name='event_participations')
registration_date = models.DateField(default=timezone.now)
def __str__(self):
return f"Участник события {self.event}"
class Meta:
verbose_name = "Участник события"
verbose_name_plural = "Участники событий"
Работа в shell
# Запуск shell
python manage.py shell
# Создать автора
from library.models import Author
a = Author.objects.create(
first_name="Leo", last_name="Tolstoy", birth_date="1828-09-09"
)
# Создать библиотеку
from library.models import Library
lib = Library.objects.create(name="Центральная", location="Москва, ул. Ленина 1")
# Создать книгу и добавить в библиотеку
from library.models import Book
book = Book.objects.create(title="Война и мир", author_id=a, publishing_date="1869-01-01")
book.libraries.add(lib)
# Получить все книги библиотеки
lib.books.all()
# Получить все библиотеки книги
book.libraries.all()