Как я могу вернуть новый неповторяющийся элемент из списка в Django, сохраняя при этом отслеживание предыдущих элементов?

#django #session #random #django-queryset #data-persistence

#django #сессия #Случайный #django-набор запросов #сохранение данных

Вопрос:

Я работаю над приложением, в котором пользователь может выбрать категорию, которая вернет случайный выбор из этой категории. Основная функциональность, которую я пытаюсь реализовать, заключается в том, что после выбора элемента он больше не может быть выбран случайным образом в сеансе.

Например, у нас есть 3 категории фотографий: пейзажные, городские и портретные, в каждой по 5 фотографий. Пользователь выбирает urban, затем перенаправляется на страницу сведений со случайной фотографией из категории urban. Он может либо обновить страницу, либо нажать кнопку, чтобы получить новую фотографию из этой категории. Когда в этой категории заканчиваются новые фотографии, он перенаправляется домой.

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

Вот views.py с функцией, ответственной за это:

 def randomPhoto(request, pk, **kwargs):

    # queryset to get all photos from selected category
    gallery = list(Photos.objects.filter(id=pk)
    .values_list("partof__category", flat=True))

    # select random photo from list
    last = len(gallery) -1
    randomInt = random.randint(0, last)
    randomPic = gallery[randomInt]

    gallery.remove(randomPic)

    if len(gallery) == 0:
        return render(request, 'gallery/category_select.html')

        photoDetails = {
        'category' : Category.objects.get(id=pk),
        'author' : Author.objects.get(tookin__category=randomPic),
        'uploadedPhoto' : 'http://localhost:8000/media/'   
    str(Photo.objects.get(category=randomPic).photoUpload),
        'randomPic' : randomPic,
        }

        return render(request, 'gallery/random_photo.html', {'photoDetails': photoDetails})
  

Функциональность, которую я ищу (где каждое число является объектом / элементом в списке):

  • Пользователь выбирает городскую категорию:
    • urban содержит следующие элементы: [1, 2, 3, 4, 5]
    • случайный [3], выбранный из urban
    • у urban теперь есть [1, 2, 4, 5]
  • Пользователь обновляет:
    • выбрано случайным образом [4]
    • у urban теперь есть [1, 2, 5]
  • Пользователь обновляет:
    • выбрано случайным образом [2]
    • у urban теперь есть [1, 5]
  • Пользователь обновляет:
    • выбранный случайным образом [5]
    • у urban теперь есть [1]
  • Пользователь обновляет:
    • выбрано случайным образом [1]
    • у urban теперь есть []
  • Пользователь перенаправляется домой

Я полагаю, что моя проблема заключается в необходимости настраивать сеансы или файлы cookie, чтобы данные сохранялись в анонимном сеансе. В конечном итоге я добавлю модуль Users, чтобы у каждого пользователя сохранялась история посещенных страниц, но пока я хочу, чтобы он работал просто как анонимный пользователь.

Я пробовал добавлять SESSION_SAVE_EVERY_REQUEST = True в settings.py и помещать request.session.modified = True в свой views.py , хотя сомневаюсь, что правильно их реализую. Я прочитал несколько вопросов SO о сеансах и файлах cookie, но не смог найти что-либо для решения моей проблемы. Документ о сеансах Django показался интересным, но подавляющим. Я не уверен, с чего начать, пытаясь поэкспериментировать с объединением аспектов сессий.

Мне интересно, есть ли простой / Pythonic способ добиться того, чтобы мое веб-приложение выдавало мне неповторяющийся элемент из списка, пока в сеансе не останется ни одного.

Ответ №1:

Ваша проблема в том, что ваша переменная не переносится из одного запроса в следующий. Лучшим способом сделать это было бы использовать request.session = ... для установки переменной, а затем проверить ее позже и выполнить действия. Вот пример, который вы можете расширить, чтобы сделать его по своему вкусу:

 import random
from django.shortcuts import redirect

class TestView(View):
    def get(self, request, *args, **kwargs):

        gallery = request.session.get('gallery', None)
        if (type(gallery) is list) and (len(gallery) == 0):  # When list is empty, clear session amp; then redirect
            del request.session['gallery']
            request.session.modified = True
            return redirect('<your_redirect_url>')
        if gallery is None:  # If first visit to page, create gallery list
            gallery = list(models.Photos.objects.all().values_list("partof__category", flat=True))

        # select random photo from list
        last = len(gallery) -1
        randomInt = random.randint(0, last)
        randomPic = gallery[randomInt]
        gallery.remove(randomPic)

        request.session['gallery'] = gallery

        return render(request, 'test.html', {})
  

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

1. Спасибо за быстрый ответ. Это похоже на то, что я ищу. Я собираюсь реализовать нечто подобное сегодня вечером и обновить вас. Большое спасибо, Hybrid.

2. Я обновил представление, чтобы отразить вышеуказанные изменения. Теперь я продолжаю получать ошибку ‘str’ объект не имеет атрибута ‘session’. Есть ли конкретный способ активировать сеанс или назначить его? Я проверил свой settings.py и промежуточное программное обеспечение, и все остальное по умолчанию установлено в Django 2.1 и работает нормально.