how to run a forloop in django views.py?

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
I have also tried using django F() expressions but it does seem to work too (Code Below)

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)

NOTE: There is a Profile model which have these fields in it

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

What could be the best way to achive??

So one problem here is that by using the filter function, profile is a queryset and not an individual instance of a Profile. You would need to iterate over profile to access the individual instances, changing the values of the indirect_sign_up field for each one.

Second - profile.indirect_sign_up = profile.indirect_sign_up =+ 200 may be syntactically valid, but unnecessary. You only need to write profile.indirect_sign_up =+ 200. The += operation performs the combination of the addition and the assignment.

Finally, when you update an instance of a model, you need to save it.

Regarding your second example, using the F object, that appears like it should work. However, in your Profile model, you don’t show a field named indirect_sign_up, so I don’t know if that’s right or not.

I just updated the question there is a field named indirect_sign_up = models.IntegerField(default=0) in my Profile Model.

i tried iterating over the profile like this

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

i am not sure that is correct becuase i got this error afterward 'QuerySet' object has no attribute 'indirect_sign_up'.

Again, two things wrong here.

First, you’re using the same variable i in your inner loop as your outer loop.

Second, you’re not referencing the object being iterated over. In your inner loop, you’re trying to reference something called profile, but profile is not an instance of Profile - it’s still your queryset. The variable you are currently calling i is your instance of Profile.

I have changed it

does that mean in the inner loop i also have to do

for i in second_level_recommended:
        profile = Profile.objects.filter(recommended_by=request.user)
        for j in profile:
            # if i add this line again, that mean i am still getting a queryset and not an individual instance of profile
            profile = Profile.objects.filter(recommended_by=request.us
            profile.indirect_sign_up += 200
            profile.save

How do i get an individual instance of Profile and not the queryset in the innerloop?

Your loop variable, j is the individual instances of Profile each time through the loop.

so am i supposed to do something like this

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

Definitely getting closer. (Remember that save is a function to be called.) I also don’t see where or why you have that outer loop. You’re not using that iteration variable in either loop.

1 Like

I just printed print(second_level_recommended) which is from the first loop that i am not using in either of the loop and i got all the query set of the new users that the (user 1 and user 2) which i refered, have also registered (refered).

i also printed printed print(j.user) and this time around i got all the users that i refered which are the user 1 and user 2 and the odd part is that the indirect_ref_signup point is been added to them instead of me (the user who refered the two user who are refering others).

How do i add the indirect_ref_signup to me, based on all the users that are in the second_level_recommended (which are the users that my two users are refering)?

I’m having a bit of a problem understanding what all’s going on here.

Is this code we’ve been looking at part of a view? If so, can you post the complete view here so that I can get a better understanding of the overall objective? (If it’s not a view, where is this code located and how is it being run?)

My appologies if i’m not been understood.
This is the complete view


@login_required
def my_recommendations_view(request):
    profile = Profile.objects.get(user=request.user)
    my_recs = profile.get_recommened_profiles()
    active_refs = Profile.objects.filter(active=True, recommended_by=request.user)
    all_refs = Profile.objects.filter(recommended_by=request.user)
    ref_content = ReferralMessage.objects.get()
    content_string = urllib.parse.quote_plus(ref_content.content)
    title_string = urllib.parse.quote_plus(ref_content.title)
    url_string = f"{company.website_address}/user/sign-up/{request.user.profile.code}"

    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)

    print(second_level_recommended)

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

    context = {
            'second_level_recommended': second_level_recommended,
            'url_string': url_string,
            'title_string': title_string,
            'content_string': content_string,
            'ref_content': ref_content,
            'my_recs': my_recs,
            'active_refs': active_refs,
            'all_refs': all_refs,
        }
    return render(request, 'core/referrals.html', context)

Correct, because you are iterating over the list of people who were recommended by you.

Please confirm my understanding here.

It looks to me that what you’re trying to get is a count of all people having a recommended_by field of people having a recommended_by field referring to you. Once you have that count, you want to increase your indirect_sign_up field by 200 * that count.

You really aren’t concerned with who those people are, you’re just trying to get the number of them satisfying this condition.

Am I understanding the objective?

Correct. That is exactly what i want to do and to be more explicit, let’s say you recommended me to a platform, and i started recommending others, just because you were the one who recommended me, you’d get some point for anyone that i recommend

Yes, that is what i want to do.

Ok, so you can simplify this with a query like

some_user = request.user
my_count = Profile.objects.filter(recommended_by__profile__recommended_by=some_user).count()
some_user.indirect_sign_up = my_count * 200

Note - you would need to be very careful with just adding all the values to the existing value. If you just continue to add totals to the indirect_sign_up field, you’re going to be adding the same counts multiple times. (Each time the view is called, it’s going to continue to add those totals over and over again.)

This is the type of calculation that generally isn’t worth storing as an individual field. It can be calculated easily every time it’s needed.

Okay thanks, let me give it a shot now

    some_user = request.user
    my_count = Profile.objects.filter(recommended_by__profile__recommended_by=some_user).count()
    some_user.indirect_sign_up = my_count * 200
    # I even tried saving the some_user but it does get updated in the model field
    some_user.save()
    print("Indirect Sign Up Earn:" + str(some_user.indirect_sign_up))
    print("My Count:" + str(my_count))
    print("Some User is:" + str(some_user))
    print("Total Indirect Sign Up Points from db:" + str(some_user.profile.indirect_sign_up))

NOTE: when i print print("Indirect Sign Up Earn:" + str(some_user.indirect_sign_up)) it shows the indirect_sign_up new value in the terminal like this

[02/Aug/2022 12:12:53] "GET /media/default.jpg HTTP/1.1" 200 13657
Indirect Sign Up Earn:600
My Count:3
Some User is:destiny
[02/Aug/2022 12:12:54] "GET /user/profiles/ HTTP/1.1" 200 68238

but it doesn’t get updated in the db (Profile model), and to confirm that i printed print("Total Indirect Sign Up Points from db:" + str(some_user.profile.indirect_sign_up)) and this is how the terminal looks

...
Some User is:destiny
Total Indirect Sign Up Points from db:0
[02/Aug/2022 12:18:02] "GET /user/profiles/ HTTP/1.1" 200 54998

It seems everything is working fine now, but the new value is not been updated in the Profile model (indirect_sign_up) field.

The mistake is mine here - indirect_sign_up is a field in Profile, not User.

This means you need to get the Profile from the user and update it

As an example:

    some_profile = request.user.profile
    my_count = Profile.objects.filter(recommended_by__profile__recommended_by=request.user).count()
    some_profile.indirect_sign_up = my_count * 200
    # I even tried saving the some_user but it does get updated in the model field
    some_profile.save()

(Note - the query still needs to find the relationship to the User, because that’s what the recommended_by field relates to.)

This fixed it. But i’m getting a little bug again. I also have this field called main_all_earning = models.IntegerField(default=0)

i simply want to add the new value of the indirect_sign_up to the main_all_earning but whenever i refresh the page, it take the value that is in the indirect_sign_up and add it to the main_all_earning and so on… e.g main_all_earning = 200 and indirect_sign_up = 100 whenever i refresh the page where the code is sitting the value becomes main_all_earning = 300 i refreshed again main_all_earning = 400 i refreshed again main_all_earning = 500 and so on…
What might be the best way to stop this?

user = request.user
profile = request.user.profile
my_count = Profile.objects.filter(recommended_by__profile__recommended_by=user).count()
profile.indirect_sign_up = my_count *200
# This is the new line to also add the new value of the "indirect_sign_up" but it increments 
profile.main_all_earning = profile.main_all_earning + profile.indirect_sign_up
profile.save()

Fundamentally, you have two ways to approach this.

First, as I mentioned in my earlier reply, is to not store these values as fields in the database. Calculate them on an as-needed basis. That’s actually the preferred approach.

The other way to handle this is to only update this field from those views that would change the value. Take the calculations out of this view and put them in the view where something is done that would affect these totals. That way, you’re only changing the values when conditions change such that the values need to be updated.

I would like to use this approach but i don’t have an idea on how to go about it…

Right now i can’t seem to find the perfect view where i can put the code, i tried the register page, but then the user is not registered yet to determine if the user belongs to the main user