Как запустить цикл forloop в django views.py?

Я хочу взаимодействовать с набором запросов и если добавляется новый пользователь, я хочу добавить несколько очков для конкретного пользователя. Чтобы быть более ясным с тем, что я создаю: => Я пишу логику реферальной системы на django. Сейчас реферальная система работает хорошо, но я хочу реализовать следующее. Когда я ссылаюсь на пользователя "user 2" и "user 3", сохраняется, что я ссылаюсь на two users, теперь я также реализовал способ узнать, если "user 2" или "user 3", которые ссылаются на меня: получили нового пользователя, ссылающегося на них ("user 2" или "user 3").

Теперь я хочу добиться следующего, когда появляется новый пользователь "пользователь 2" или "пользователь 3" я хочу добавить несколько пунктов к "пользователь 1", который ссылался на двух пользователей ("user 2" и "user 3"), которые ссылались на новых пользователей.

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

# for i in second_level_recommended:
    profile = Profile.objects.filter(recommended_by=request.user)
    profile.indirect_sign_up = profile.indirect_sign_up =+ 200
        

Вот код для проверки новых пользователей, которые "user 2" и "user 3" назвали себя принадлежащими "user 1". views.py

my_recomended = Profile.objects.filter(recommended_by=request.user).values_list('user__id', flat=True)
second_level_recommended=Profile.objects.filter(recommended_by__in=my_recomended)

Затем в шаблонах есть цикл forloop для отображения second_level_recommended

NOTE: Существует Profile модель, в которой есть эти поля

class Profile(models.Model):
    user = models.OneToOneField(User, ...)
    ...
    code = models.CharField(max_lenght=100, ...)
    recommended_by = models.ForeignKey(User, ...)

Если нужен код того, как я регистрирую пользователей для рефералов, то вот он views.py

def registerRef(request, *args, **kwargs):
    profile_id = request.session.get('ref_profile')
    print('profile_id', profile_id)

    code = str(kwargs.get('ref_code'))
    try:
        profile = Profile.objects.get(code=code)
        request.session['ref_profile'] = profile.id
        print('Referer Profile:', profile.id)
    except:
        pass
    print("Session Expiry Date:" + str(request.session.get_expiry_age()))

    form = UserRegisterForm(request.POST or None)
    if form.is_valid():
        if profile_id is not None:
            recommended_by_profile = Profile.objects.get(id=profile_id)
            ref_earn = InvestmentPackageID.objects.get()

            instance = form.save()
            registered_user = User.objects.get(id=instance.id)
            registered_profile = Profile.objects.get(user=registered_user)
            registered_profile.recommended_by = recommended_by_profile.user
            registered_profile.save()

        else:
            instance = form.save()
            registered_user = User.objects.get(id=instance.id)
            profile = Profile.objects.get(user=registered_user)
            profile.save()

        username = form.cleaned_data.get('email')
        password = form.cleaned_data.get('password1')
        user = authenticate(username=username, password=password)
        login(request, user)
        return redirect('core:index')

    context = {'form':form}
    return render(request, 'userauths/sign-up.html', context)

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

Вместо цикла for мы будем использовать эту технику: https://docs.djangoproject.com/en/4.0/ref/models/expressions/#f-expressions

(см. также https://docs.djangoproject.com/en/4.0/ref/models/instances/#updating-attributes-based-on-existing-fields)

from django.db.models import F


my_recomended = Profile.objects.filter(recommended_by=request.user).values_list('user__id', flat=True)
second_level_recommended=Profile.objects.filter(recommended_by__in=my_recomended)

second_level_recommended.update(indirect_sign_up=F('indirect_sign_up') + 200)

Это означает, что мы можем обновить всех совпадающих пользователей в second_level_recommended наборе запросов в одной операции с БД.

В противном случае, если вы используете цикл for, это, вероятно, будет медленнее, но, что более важно, вы рискуете столкнуться с "состоянием гонки".

Условием гонки будет ситуация, когда вы получаете строку из базы данных в память, как экземпляр модели Django, обновляете значение в экземпляре модели на основе только что полученного значения, а затем сохраняете его обратно в базу данных. Таким образом, вы можете получить проблему, когда кто-то запрашивает одно и то же представление для одного и того же или связанного пользователя одновременно - оба запроса получают одно и то же старое значение и добавляют к нему 200, но конечным результатом двух запросов будет просто +200 вместо +400.

Использование запроса update позволяет избежать этого, поскольку операция в базе данных "атомарна" - мы говорим базе данных database добавить 200 к каждой строке вместо того, чтобы делать это самостоятельно по очереди в коде Python. Если два запроса придут почти одновременно, база данных обеспечит их последовательное выполнение, так что сначала один +200, а затем второй +200.

Вернуться на верх