Как изменить модель после создания набора представлений моделей?

#django #django-models #django-rest-framework

Вопрос:

Я создаю API с помощью платформы django rest. Но у меня возникает проблема каждый раз, когда я хочу изменить модель, когда я уже создал связанный набор представлений моделей.

Например, у меня есть такая модель:

 class Machine(models.Model):
    name = models.CharField(_('Name'), max_length=150, unique=True)
    provider = models.CharField(_("provider"),max_length=150)
    build_date = models.DateField(_('build date'))
    category = models.ForeignKey("machine.CategoryMachine",
                                 related_name="machine_category",
                                 verbose_name=_('category'),
                                 on_delete=models.CASCADE
                                )
    site = models.ForeignKey(
        "client.Site",
        verbose_name=_("site"),
        related_name="machine_site",
        on_delete=models.CASCADE
    )

    class Meta:
        verbose_name = _("Machine")
        verbose_name_plural = _("Machines")

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse("Fridge_detail", kwargs={"pk": self.pk})
 

И этот набор представлений:

 class MachineViewSet(viewsets.ModelViewSet):
    """
    A simple ViewSet for listing or retrieving machine.
    """
    permission_classes = [permissions.IsAuthenticated]
    
    serializer_class = MachineSerializer
    queryset = cache.get_or_set(
                        'machine_machines_list',
                        Machine.objects.all(),
                        60*60*24*7
                    )
    
    @swagger_auto_schema(responses={200: MachineSerializer})
    def list(self, request):
        serializer_context = {
            'request': request,
        }
        queryset = cache.get_or_set(
            'machine_machines_list',
            Machine.objects.all(),
            60*60*24*7
        )
        serializer = MachineSerializer(queryset, many=True, context=serializer_context)
        return Response(serializer.data)

    @swagger_auto_schema(responses={404: 'data not found', 200: MachineSerializer})
    def retrieve(self, request, pk=None):
        serializer_context = {
            'request': request,
        }
        queryset = Machine.objects.all()
        machine = get_object_or_404(queryset, pk=pk)
        serializer = MachineSerializer(machine, context=serializer_context)
        return Response(serializer.data)
 

Если я хочу добавить поле в свою модель, например, описание. Когда я выполняю команду python manage.py makemigrations
Я получаю ошибку :
django.db.utils.ProgrammingError: column machine_machine.description does not exist

Я должен прокомментировать свой набор представлений, чтобы иметь возможность запускать makemigrations и migrate . Как я могу избежать необходимости каждый раз комментировать наборы представлений, когда я хочу изменить модель?

Комментарии:

1. Можете ли вы поделиться обратной связью?

2. Вы будете кэшировать результаты набора запросов в течение недели?? Ты действительно в этом уверен? Таким образом, вы можете отображать устаревшие данные для пользователей.

3. Я удаляю данные из кэша при изменении результата (например, после добавления объекта…)

Ответ №1:

На ваш взгляд, в вашем классе есть следующая строка:

 queryset = cache.get_or_set(
    'machine_machines_list',
    Machine.objects.all(),
    60*60*24*7
)
 

Поскольку эта строка присутствует в объявлении класса, а не в методе класса, она выполняется при создании / интерпретации класса. Это приводит к тому, что он запускает запрос, так как для его кэширования потребуется выполнить оценку набора запросов (обработка наборов запросов приведет к принудительной оценке). Проблема здесь в том, что ваши модели еще не были перенесены, и ваши запросы не выполняются. Вы можете написать этот код в get_queryset методе, переопределив его, если хотите:

 class MachineViewSet(viewsets.ModelViewSet):
    """
    A simple ViewSet for listing or retrieving machine.
    """
    permission_classes = [permissions.IsAuthenticated]
    
    serializer_class = MachineSerializer
    # Remove below lines
    # queryset = cache.get_or_set(
    #                     'machine_machines_list',
    #                     Machine.objects.all(),
    #                     60*60*24*7
    #                 )
    
    def get_queryset(self):
        return cache.get_or_set(
            'machine_machines_list',
            Machine.objects.all(),
            60*60*24*7
        )
    ...
 

Но эта реализация имеет серьезные недостатки! Вы кэшируете набор запросов в течение недели. В течение этого периода времени может поступить много новых данных, и вы, по сути, будете предоставлять своим пользователям устаревшие данные. Я бы посоветовал вам отказаться от такого рода кэширования. Кроме того, вы, похоже, возвращаете все данные из своего представления, подумайте о какой-то фильтрации, чтобы для таких вещей требовалось меньше памяти.

Комментарии:

1. Спасибо вам за ваш ответ. Это работает очень хорошо. Для недельного кэша я удаляю ключи по мере необходимости, например, после добавления новой машины. Зная, что в месяц будет добавляться/изменяться не более 1 или 2 машин, недельный кэш не кажется слишком плохим.