Django - Автозаполнение поиска выбрасывает ошибку для зарегистрированных пользователей?

Я делаю некоторые обновления в части автозаполнения функциональности поиска в моем приложении, и по какой-то причине я получаю ошибку для вышедших из системы пользователей, которая говорит TypeError: Field 'id' expected a number but got <SimpleLazyObject: <django.contrib.auth.models.AnonymousUser object at 0x1088a5e20>>.

Это происходит только для пользователей, вышедших из системы. Когда пользователь вошел в систему, автозаполнение работает, как и было задумано, поэтому я знаю, что я что-то упускаю, но я просто не знаю что.

Что нужно изменить, чтобы решить эту проблему?

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

Сделал несколько заметок в моем views.py коде из того, что я тестировал, и добавил JavaScript в функцию поиска на всякий случай.

Ниже приведены скриншоты того, что отображается для пользователей, вышедших из системы и вошедших в нее.

Снимок экрана залогиненного пользователя enter image description here

Снимок экрана входа enter image description here

Ниже приведен мой код.

Любая помощь будет принята с радостью!

Всех благ!

models.py

class Game_Info(models.Model):
    id = models.IntegerField(primary_key=True, unique=True, blank=True, editable=False)
    game_title = models.CharField(max_length=100, null=True)
    game_rank = models.IntegerField(default=1)
    game_image = models.ImageField(default='default.png', upload_to='game_covers', null=True, blank=True)


class User_Info(models.Model):
    id = models.IntegerField(primary_key=True, blank=True)
    image = models.ImageField(default='/profile_pics/default.png', upload_to='profile_pics', null=True, blank=True)
    user = models.OneToOneField(settings.AUTH_USER_MODEL,blank=True, null=True, on_delete=models.CASCADE)
    rank = models.IntegerField(default=1)   

views.py

def search_results_view(request):
    if request.headers.get('x-requested-with') == 'XMLHttpRequest': 
        res = None
        game = request.POST.get('game')
        print(game)

        ## This works for both logged in and logged out users but inlcudes all games. Would like to have this for logged out users. Commenting this out to test below. 
        # qs = Game_Info.objects.filter(game_title__icontains=game).order_by('game_title')[:4]

        ## This only works for when users are logged in. 
        user_profile_game_obj = User_Info.objects.get(user=request.user)
        user_profile_rank = int(user_profile_game_obj.rank)
        qs = Game_Info.objects.filter(game_title__icontains=game, game_rank__lte=user_profile_rank).order_by('game_title')[:4]

        if len(qs) > 0 and len(game) > 0:
            data = []
            for pos in qs:
                item ={
                    'pk': pos.pk,
                    'name': pos.game_title,
                    'game_provider': pos.game_provider,
                    'image': str(pos.game_image.url),
                    'url': reverse('detail', args=[pos.pk]),
                }
                data.append(item)
            res = data
        else:
            res = 'No games found...'

        return JsonResponse({'data': res})
    return JsonResponse({})

custom.js

// Live Search Functionalty 
$(function () {
    const url = window.location.href
    const searchForm = document.getElementById("search-form");
    const searchInput = document.getElementById("search_input_field");
    const resultsBox = document.getElementById("search-results");
    const csrf = document.getElementsByName('csrfmiddlewaretoken')[0].value

    const sendSearchData = (game) =>{
        $.ajax ({
            type: 'POST',
            url: '/games/',

            data: {
                'csrfmiddlewaretoken': csrf,
                'game' : game,
            },
            success: (res)=> {
                console.log(res.data)
                const data = res.data
                if (Array.isArray(data)) {
                    resultsBox.innerHTML = `<div class="search_heading"><h1>Recommended Games</h1></div>`
                    data.forEach(game=> {
                        resultsBox.innerHTML += `                    
                            <a href="${game.url}" class="item" >                          
                                <div class="row">
                                    <div class="search-cover-container">
                                        <img src="${game.image}" class="game-img">
                                    </div>
                                    <div class="search-title-container">
                                        <p>${game.name}</p>
                                        <span class="publisher_title">${game.game_provider}</span>
                                    </div>
                                    <div class="search-icon-container">
                                        <i class="material-icons">trending_up</i>
                                    </div>
                                </div>
                            </a>
                        `
                    })
                } else {
                   if (searchInput.value.length > 0) {
                    resultsBox.innerHTML = `<h2>${data}</h2>`
                   } else {
                    resultsBox.classList.add('not_visible')
                   }
                }
            },
            error: (err)=> {
                console.log(err)
            }
        })
    }

    searchInput.addEventListener('keyup', e=> {
        sendSearchData(e.target.value)
    })

});

base.html

            <form method="POST" autocomplete="off" id="search-form" action="{% url 'search_results' %}">
                {% csrf_token %}
                <div class="input-group">
                    <input id="search_input_field" type="text" name="q" autocomplete="off" class="form-control gs-search-bar" placeholder="Search Games..." value="">
                    <div id="search-results" class="results-container not_visible"></div>
                    <span class="search-clear">x</span>
                    <button id="search-btn" type="submit" class="btn btn-primary search-button" disabled>
                        <span class="input-group-addon">
                            <i class="zmdi zmdi-search"></i>
                        </span> 
                    </button>
                </div>
            </form>

Исходя из запроса, который вы показываете, пользователи, вышедшие из системы, не должны даже переходить к этому представлению. Я бы украсил представление символами @login_required.

Проблема, которую вы наблюдаете, находится в этой строке:

user_profile_game_obj = User_Info.objects.get(user=request.user)

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

Альтернативно, вы можете изменить поведение представления, используя user.is_authenticated()

Как уже было сказано @Sam Morgan, request.user - это AnonymousUser. Добавление @login_required не поможет, но использование user.is_authenticated() должно сработать:

def search_results_view(request):
    if request.headers.get('x-requested-with') == 'XMLHttpRequest': 
        res = None
        game = request.POST.get('game')
        print(game)

        ## This works for both logged in and logged out users but inlcudes all games. Would like to have this for logged out users. Commenting this out to test below. 
        # qs = Game_Info.objects.filter(game_title__icontains=game).order_by('game_title')[:4]

        ## This only works for when users are logged in. 
        if request.user.is_authenticated: 
            user_profile_game_obj = User_Info.objects.get(user=request.user)
            user_profile_rank = int(user_profile_game_obj.rank)
            qs = Game_Info.objects.filter(game_title__icontains=game, game_rank__lte=user_profile_rank).order_by('game_title')[:4]

        else:
            qs = Game_Info.objects.filter(game_title__icontains=game).order_by('game_title')[:4]

        if len(qs) > 0 and len(game) > 0:
            data = []
            for pos in qs:
                item ={
                    'pk': pos.pk,
                    'name': pos.game_title,
                    'game_provider': pos.game_provider,
                    'image': str(pos.game_image.url),
                    'url': reverse('detail', args=[pos.pk]),
                }
                data.append(item)
            res = data
        else:
            res = 'No games found...'

        return JsonResponse({'data': res})
    return JsonResponse({})
Вернуться на верх