1

I'm working on an app where a user can select a category, which will return a random selection from that category. The main functionality I'm trying to implement is once an item is selected, it can no longer be randomly selected in session.

For example, we have 3 categories of photos: landscape, urban, and portraits, each with 5 photos. A user selects urban, is then redirected to a details page with a random photo from urban category. He can either refresh the page or click a button to get a new photo from that category. When that category is out of new photos, he is redirected home.

I am able to get my random item from the selected category through converting a queryset to a list, but the data isn't persisting. On every refresh the list I have resets, thus a previously selected photo can come up again, ignoring the the fact that I removed the item from the list after it was selected.

Here's the views.py with the function responsible for this:

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})

The functionality I'm looking for is (where each number is an object/item in list):

  • User selects urban category:
    • urban has the following items: [1, 2, 3, 4, 5]
    • random [3] selected from urban
    • urban now has [1, 2, 4, 5]
  • User refreshes:
    • random [4] selected
    • urban now has [1, 2, 5]
  • User refreshes:
    • random [2] selected
    • urban now has [1, 5]
  • User refreshes:
    • random [5] selected
    • urban now has [1]
  • User refreshes:
    • random [1] selected
    • urban now has []
  • User is redirected home

I believe my problem lies in having to configure either sessions or cookies to have the data persist in an anonymous session. Eventually I will be adding a Users module so each user will have their browsing history saved but for now I want it to work just as an anonymous user.

I've tried adding SESSION_SAVE_EVERY_REQUEST = True to settings.py and placing request.session.modified = True in my views.py, though I doubt I'm implementing them properly. I've read some SO questions on sessions and cookies but wasn't able to find something to work with my issue. The Django Sessions Doc seemed interesting but overwhelming. I'm not sure where to begin trying to experiment with wiring the sessions aspect together.

I am wondering if there's an easy/Pythonic way to achieve having my web app give me a non-repeating item from a list until none are left within the session.

halfer
  • 19,824
  • 17
  • 99
  • 186
Ricky
  • 11
  • 1

1 Answers1

1

Your issue is that your variable is not carried over from one request to the next. The best way to do this would be to use request.session = ... to set a variable, and then check it later and perform actions. Here is an example that you can expand on to make it to your liking:

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 & 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', {})
Hybrid
  • 6,741
  • 3
  • 25
  • 45
  • 1
    Thanks for the quick response. This sounds like what I'm looking for. I'm going to implement something similar tonight and update you. Much appreciated, Hybrid. – Ricky Mar 28 '19 at 13:43
  • I've updated the view to reflect the above changes. Now I keep getting a 'str' object has no attribute 'session' error. Is there a specific way to activate the session or assign it? I've checked my settings.py and Middleware and everything is default to Django 2.1 and working normally. – Ricky Mar 30 '19 at 16:01