i want to interate over queryset and if there is a new user added, i want to add some points for a specific user. To be more clear with what i am building: => I am writing a referral system logic in django. The referral system works fine now, but what i want to implement is this. When i refer a user which are "user 2" and "user 3", it is stored that i have refered two users, now i have also implemented a way to know if "user 2" or "user 3" which are refered by me: have gotten a new user refered by them ("user 2" or "user 3").
Now what i want to achieve is this, when there is a new user from "user 2" or " user 3 " i want to add a some points to the "user 1" which refered the two user ("user 2" and "user 3") that referred the new users.
I am thinking of using a forloop to iterate over the second_level_recommended
, then add the point to the profile but it doesn't seem to work or maybe the code that i wrote was wrong. This is the code that i wrote for the foorloop below
# for i in second_level_recommended:
profile = Profile.objects.filter(recommended_by=request.user)
profile.indirect_sign_up = profile.indirect_sign_up = 200
This is the code to check for the new users that "user 2" and "user 3" have reffered belonging to "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)
Then there is a forloop in the templates to display the second_level_recommended
NOTE: There is a Profile
model which have these fields in it
class Profile(models.Model):
user = models.OneToOneField(User, ...)
...
code = models.CharField(max_lenght=100, ...)
recommended_by = models.ForeignKey(User, ...)
CodePudding user response:
It's hard to tell if this is exactly what you want without seeing more context of your code, but I will take a stab at answering...
Instead of a for loop, we are going to use this technique: https://docs.djangoproject.com/en/4.0/ref/models/expressions/#f-expressions
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)
This means we can update all the matched users in second_level_recommended
queryset in a single db operation.
Otherwise if you use a for loop it is probably slower, but more importantly you run the risk of a "race condition".
The race condition would be where you fetch the db row into memory, as a Django model instance, update value on the model instance based on the value just fetched, then save it back to the db. So you can get a problem where someone requests the same view for same or related user at the same time - both requests get the same old value and add 200 to it, but the end result of two requests is just 200 instead of 400.
Using an update
query avoids that because the operation is "atomic" in the db - we tell the database to add 200 to each row instead of doing it ourselves one by one in Python code. If two requests come in almost simultaneously the db will ensure they execute serially, so first one 200 and then a second 200.