Изменение информации в панели администрирования Django

Рейтинг: 1Ответов: 1Опубликовано: 15.04.2023

Я новичок в программировании и пишу свой пет-проект. Я пишу код для изменения репутации пользователя при взятии книги в аренду. Вот ключевой код из модели

class BooksRent(models.Model):
    """Модель выдачи книг.
    ||
    Book lending model."""

    book = models.ForeignKey(
        Books,
        verbose_name='Книга',
        help_text='Укажите Книгу',
        on_delete=models.SET_NULL,
        null=True,
        related_name='rents'
    )
    reader = models.ForeignKey(
        Readers,
        verbose_name='Читатель',
        help_text='Укажите Читателя',
        on_delete=models.SET_NULL,
        null=True
    )
    rented_at = models.DateTimeField(
        verbose_name='Дата выдачи книги',
        help_text='Укажите дату выдачи книги читателю',
        # auto_now_add=True
    )
    returned_at = models.DateTimeField(
        null=True,
        blank=True,
        verbose_name='Дата возврата книги',
        help_text='Укажите дату возврата книги читателем',
    )

    class Meta():
        ordering = ('reader',)
        verbose_name = 'Книгу в аренде'
        verbose_name_plural = 'Книги в аренде'

    def __str__(self):
        return f"{self.reader.username} взял {self.book.title}"

    def is_late(self):
        if not self.returned_at:
            return False
        rental_duration = self.returned_at - self.rented_at
        return rental_duration.days > 10

    def save(self, *args, **kwargs):
        # проверяем, возвращена ли книга вовремя
        if self.returned_at:
            is_returned_on_time = self.is_late()
        if is_returned_on_time:
            self.reader.reputation += 1
        else:
            self.reader.reputation -= 1
        self.reader.save()
        super().save(*args, **kwargs)

Так же есть метод в представлении:

  class RentLateReturnViewSet(viewsets.ModelViewSet):
    """Аренда/Возврат книги.
    ||
    Book rental/return viewset.
    """

    pagination_class = PageNumberPagination
    permission_classes = (IsAdminModeratorOrSuperUser, )
    queryset = BooksRent.objects.all()
    serializer_class = BooksRentSerializer

    def list(self, request):
        """Запрет доступа к списку арендованных книг для всех,
           кроме администраторов,
           модераторов и суперпользователей. """

        if not request.user.is_superuser and not request.user.is_staff:
            raise PermissionDenied
        return super().list(request)

    def post(self, request):
        data = request.data
        book_id = data.get('book_id')
        reader_id = data.get('reader_id')
        rented_at = data.get('rented_at')
        returned_at = data.get('returned_at')
        book = get_object_or_404(Books, id=book_id)
        # Ищем аренду, соответствующую переданным данным
        # Создаем запись об аренде
        rent = BooksRent.objects.create(
            book=book, reader_id=reader_id,
            rented_at=rented_at, returned_at=returned_at
        )
        if not rent:
            return Response(status=status.HTTP_404_NOT_FOUND)
        # Проверяем, была ли книга возвращена вовремя
        if rent.is_late():
            rent.reader.reputation -= 1
        else:
            rent.reader.reputation += 1
        rent.reader.save()
        rent.returned_at = timezone.now()
        rent.save()
        return Response(status=status.HTTP_200_OK)

На всякий случай прикладываю модель пользователя/читателя

class Readers(AbstractUser):
"""Модель Юзера/Читателя/Посетителя библиотеки.
||
Library User/Reader/Visitor Model.
"""

USER_ROLE = 'reader'
MODERATOR_ROLE = 'moderator'
ADMIN_ROLE = 'admin'
ROLE_CHOICES = (
    (USER_ROLE, 'reader'),
    (MODERATOR_ROLE, 'moderator'),
    (ADMIN_ROLE, 'admin')
)
username = models.CharField(
    verbose_name='Username',
    max_length=100,
    unique=True,
    validators=(UnicodeUsernameValidator(), ),
    help_text='Введите username пользователя'
)
first_name = models.CharField(
    verbose_name='Имя читателя',
    max_length=50,
    help_text='Введите Имя'
)
last_name = models.CharField(
    verbose_name='Фамилия читателя',
    max_length=50,
    help_text='Введите Фамилию'
)
email = models.EmailField(
    unique=True,
    verbose_name='email читателя',
    help_text='Введите электронную почту'
)
phone_number = PhoneNumberField(
    unique=True,
    null=False,
    blank=False,
)
reputation = models.IntegerField(
    default=10,
    verbose_name='Рейтинг Читателя'
)
role = models.CharField(
    max_length=max((len(item) for _, item in ROLE_CHOICES)),
    choices=ROLE_CHOICES,
    default=USER_ROLE,
    verbose_name='Пользовательская роль',
    help_text='Выберите роль пользователя'
)

class Meta:
    ordering = ('username', )
    verbose_name = 'Читатель'
    verbose_name_plural = 'Читатели'

def __str__(self):
    return self.username

@property
def is_moderator(self):
    """True для пользователей с правами модератора. """

    return self.role == Readers.MODERATOR_ROLE

@property
def is_admin(self):
    """True для пользователей с правами админа и суперпользователей. """

    return (
        self.role == Readers.ADMIN_ROLE
        or self.is_staff
        or self.is_superuser
    )

Для теста диапазон дней в аренде книги указан как 10. Тестируя код в админке django я указываю дату взятия книгу и дату возврата так, чтобы срок аренды превышал 10 дней, соответственно репутация пользователя должна понизиться на 1. Но этого не происходит. В админке я захожу в читателей и вижу, что репутация не изменилась. В чем может быть дело?

u.p.d. начал кидать запросы на API. Объект аренды создается, но репутация не меняется.

Метод подсчета репутации пытался выполнить как в модели так и в представлении. Админка выдачи

Админка читателя. Репутация не изменилась Как видно из кода и скриншотов, дефолтное значение репутации, как было 10 так и осталось, увы репутация не изменилась. З.Ы. данные пользователя тестовые и не имеют реального пользователя.

Ответы

▲ 0Принят

В этом месте не сохраняете читателя:

    def save(self, *args, **kwargs):
    # проверяем, возвращена ли книга вовремя
    if self.returned_at:
        is_returned_on_time = self.is_late()
        if is_returned_on_time:
            self.reader.reputation += 1
        else:
            self.reader.reputation -= 1
        self.reader.save()
    super().save(*args, **kwargs)

Также непонятно зачем вообще этот кусок??

    # Проверяем, была ли книга возвращена вовремя
    if rent.is_late():
        rent.reader.reputation -= 1
    else:
        rent.reader.reputation += 1
    rent.reader.save()
    rent.returned_at = timezone.now()
    rent.save()

Проверка будет проходить при вызове метода save() модели BooksRent при записи даты возврата.