Increment Model Field Inside Get Or Create Django - python

I am developing a music web application where I am trying to calculate the number of times a song was played. When the play button is clicked, a function called getLink() is called. Here, I try to use get_or_create to update the PlayCount model, like so.
h = PlayCount.objects.all()
if len(h) == 0:
u = PlayCount.objects.get_or_create(
user=request.user.username,
song=song,
plays=1,
)[0]
u.save()
else:
flag = False
for i in h:
if i.song == song:
u = PlayCount.objects.get_or_create(
user=request.user.username,
song=song,
plays=plays + 1,
)[0]
u.save()
flag = True
break
else:
pass
if flag is False:
u = PlayCount.objects.get_or_create(
user=request.user.username,
song=song,
plays=1,
)[0]
u.save()
else:
pass
However, when I enter the else loop, 127.0.0.1:8000 returns play is not defined.
How may I proceed?

I don't understand why you loop through all the PlayCount objects when all you need is to find the one for the specific user and song.
Note also that get_or_create will only find the specific object that matches all the parameters you pass to it, so get_or_create(user=..., song=..., plays=...) will try finding the one with the exact number of plays you specify which isn't what you want.
You only need to do this:
from django.db.models import F
play_counter, created = PlayCount.objects.get_or_create(
user=request.user,
song=song,
defaults={'plays': 1})
if not created:
play_counter.plays = F('plays') + 1
play_counter.save()
So here we first fetch or create the counter for the particular song and user. If we create it, we set plays to 1 by setting it in the defaults parameter.
Then, if it is not created (i.e. it's an existing one), we increment plays by 1, using the F expression, which ensures it's updated in the database directly (and there's no risk of database inconsistency due if another request is updating the same value).

Related

Python conditions statement logic

Im beginner on selenium & python and i trying to understand the logic of condition statement but it doesn't take the second condition into account :
What i try to do :
PS : I put " ? " because I'm not sure if is that
My code :
users = []
elems = browser.find_elements_by_xpath("//body//div[#class='PZuss']//a[#class='FPmhX notranslate _0imsa ']")
url = "https://www.instagram.com/"
# Generate a list where to put the followers name
for i in range(100):
val = elems[i].get_attribute('innerHTML')
users.append(url+val)
print(users)
for follower in users:
#Iterate into the list
browser.get(follower)
sleep(2)
followButton = browser.find_element_by_css_selector('button')
print(follower_count)
print(following_count)
if int(follower_count) == 0:
follower_count = int(browser.find_element_by_xpath('/html/body/div[1]/section/main/div/header/section/ul/li[2]/span/span').text.replace(",",""))
following_count = int(browser.find_element_by_xpath('/html/body/div[1]/section/main/div/header/section/ul/li[3]/span/span').text.replace(",",""))
continue #don't know if i need this word ?
if browser.find_elements_by_xpath("//img[contains(#src,'YW5vbnltb3VzX3Byb2ZpbGVfcGlj')]"):
print("profil haven't profil pic")
continue
else:
print("eligible")
followButton.click()
My understanding of what you're trying to achieve is this.
if int(follower_count) == 0:
follower_count = int(browser.find_element_by_xpath('/html/body/div[1]/section/main/div/header/section/ul/li[2]/span/span').text.replace(",",""))
following_count = int(browser.find_element_by_xpath('/html/body/div[1]/section/main/div/header/section/ul/li[3]/span/span').text.replace(",",""))
if browser.find_elements_by_xpath("//img[contains(#src,'YW5vbnltb3VzX3Byb2ZpbGVfcGlj')]"):
print("profil haven't profil pic")
else:
print("eligible")
followButton.click()
You do not need the continue for the code to work
The second if statement is within the first if statement, with the else a part of the second if statement. The indented block of code is within the first if statement and is only run if follower_count is equal to 0, otherwise it will skip the if statement and go to the next value in the for loop.
You should use logical operators here. Assume you have your conditions check and validation logic in three dedicated methods:
def check_condition_one(*args):
pass # You evaluate your conditions here
def check_condition_two(*args):
pass # You evaluate your conditions here
def validate(*args):
pass # you implement your validation logic here
Then you do like this:
for user in users:
if check_condition_one(user) and check_condition_two(user):
validate(user)
So you validate a user when both the conditions have evaluated to True. Otherwise nothing happens.
P.S. - continue just skips the rest of the code till the end of current loop iteration and proceeds to the next one if any.

Self Limiting Repition Function

I'm writing a program that is basically a study guide/ practice test for the current section of my A&P class (it keeps me more engaged than just rereading notes over and over). The test works without any problems, but I have an issue where some of my questions use an "enterbox" input, I can have the question loop if the answer is incorrect, but I can't get it to break without a correct answer.
I figured out a way to make it work by putting the entire function back into the initial "else" tree, so that right or wrong you advance to the next question but it looks incredibly ugly and I can't believe there isn't a better way.
So my "solution" looks like such:
def question82():
x = "which type of metabolism provides the maximum amount of ATP needed for contraction?"
ques82 = enterbox(msg = x, title = version)
#version is a variable defined earlier
if ques82.lower() in ["aerobic"]:
add() #a function that is explained in the example further below
question83()
else:
loss() #again its a housecleaning function shown below
ques82b = enterbox(msg = x, title = version)
if ques82b.lower() in ["aerobic"]:
add()
question83()
else:
loss()
question83()
Okay so it worked, but using a nested if tree for each "enterbox" question looks kinda sloppy. I'm self taught so it may be the only solution but if there is something better I would love to learn about it.
So here is a complete section from my program:
from easygui import *
import sys
version = 'A&P EXAM 3 REVIEW'
points = 0
def add():
global points
msgbox("Correct", title = version)
points = points + 1
def loss():
global points
msgbox("Try Again", title = version)
points = points - 1
def question81():
x = "What chemical is stored by muscle as a source of readily available energy for muscle contractions"
ques81 = enterbox(msg = x, title = version)
if ques81.lower() in ["creatine"]:
add()
question82()
else:
loss()
question81()
It works as is so any errors from what's provided are probably my fault from copy and pasting.
Also I'm running it in python 2.7rc1 if that helps.
Thanks for any help in advance.
I don't know if there is a way to combine "enterbox" that has a button for "skip" as that would also be a solution.
Consider the following approach:
We define a list of question and answer pairs. We do this in one place so it's easy to maintain and we don't have to search all over the file to make changes or re-use this code for a different questionset.
We create an ask_question function that we can call for all of our questions. This way, if we want to make a change about how we implement our question logic, we only have to make it in one spot (and not in each of the questionXX functions).
We compare user input to our answer using == and not in (in will do something else, not what you expect).
We create an object to keep track of our answer results. Here, it's an instance of ResultsStore, but it can be anything really, let's just try to get away from global variables.
Use a loop when prompting for answers. The loop will repeat if the answer given was incorrect (and if retry_on_fail is False).
Allow for the user to enter some "skip" keyword to skip the question.
Display the results once the "test" is complete. Here, we do that by defining and calling the store.display_results() method.
So, what about:
from easygui import enterbox
question_answer_pairs = [
("1 + 1 = ?", "2"),
("2 * 3 = ?", "6"),
("which type of metabolism provides the maximum amount of ATP needed for contraction?", "aerobic")
]
VERSION = 'A&P EXAM 3 REVIEW'
class ResultStore:
def __init__(self):
self.num_correct = 0
self.num_skipped = 0
self.num_wrong = 0
def show_results(self):
print("Results:")
print(" Correct:", self.num_correct)
print(" Skipped:", self.num_skipped)
print(" Wrong: ", self.num_wrong)
def ask_question(q, a, rs, retry_on_fail=True):
while True:
resp = enterbox(msg=q, title=VERSION)
# Force resp to be a string if nothing is entered (so .lower() doesn't throw)
if resp is None: resp = ''
if resp.lower() == a.lower():
rs.num_correct += 1
return True
if resp.lower() == "skip":
rs.num_skipped += 1
return None
# If we get here, we haven't returned (so the answer was neither correct nor
# "skip"). Increment num_wrong and check whether we should repeat.
rs.num_wrong += 1
if retry_on_fail is False:
return False
# Create a ResultsStore object to keep track of how we did
store = ResultStore()
# Ask questions
for (q,a) in question_answer_pairs:
ask_question(q, a, store)
# Display results (calling the .show_results() method on the ResultsStore object)
store.show_results()
Now, the return value currently doesn't do anything, but it could!
RES_MAP = {
True: "Correct!",
None: "(skipped)",
False: "Incorrect" # Will only be shown if retry_on_fail is False
}
for (q,a) in question_answer_pairs:
res = ask_question(q, a, store)
print(RES_MAP[res])
Quick and dirty solution could be using the default value "skip" for the answer:
def question81():
x = "What chemical is stored by muscle as a source of readily available energy for muscle contractions"
ques81 = enterbox(msg = x, title = version, default = "skip")
if ques81.lower() == 'creatine':
add()
question82()
elif ques81 == 'skip':
# Do something
else:
loss()
question81()
But you should really study the answer given by jedwards. There's a lot to learn about
program design. He's not giving you the fish, he's teaching you to fish.

Assigning a value to a objects created at run time (python)

I am trying to use a while loop to create object to populate a list of a user defined type until a certain condition is met. I want to assign a value to each object based on the number of iterations the loop has completed. For example:
class WalkingPeeps:
def___init___(self):
self.location = 0
def leftAt(self,time):
self.tleft = time
def changePos(self):
self.location += random.choice([1, -1])
objectList =[]
location_reached = False
time = 0
while not location_reached
objectList.append(WalkingPeeps())
for x in objectList:
x.tleft = time
if x.location == 20:
location_reached = True
time+=1
print("Person left at: ",x.tleft)
print("Person arrived at: ", time)
However, when it runs, it just set the time the object was created to one less than when the person reached 20. Any pointers? Hints? Thanks in advance.
In python, loops do not define their own scope. When you write
for x in objectList: ...
There variable x is created. At each step in the loop, the variable is updated. When the loop ends, the variable is not destroyed. Therefore, when you print x.tleft, you're printing the time on the last x, which by definition is 20, since you break the loop only when x.tleft == 20.
Furthermore, since you loop over every single element at each phase and update its time, you're setting each elements time to the most reccent time. Therefore, all elements have time == 20, when you terminate. What you mean, I believe, is to only update the last element
What I think you want to print, to check that your loop is working is,
for obj in objectList:
print( obj.tleft )
You would then see the expected behaviour
You also have many errors, including some syntax errors and some that make the code enter an infinite loop. This is the version I worked with, in good faith (try and make sure that the the only bugs in your code are the one's you're asking about!)
class WalkingPeeps: pass # None of the methods were relevant
objectList =[]
location_reached = False
time =0
while not location_reached:
objectList.append(WalkingPeeps())
x = objectList[-1]
x.tleft = time
# you need to check tleft, not location; location is never set
if x.tleft == 20:
location_reached = True
time+=1
print("Person left at: ",x.tleft)
print("Person arrived at: ", time)
for person in objectList: print(person.tleft)
A far more readable and concise version of this code would be:
class WalkingPerson:
def __init__(self,time=0):
self.time=time
objectList = [WalkingPerson(t) for t in range(20)]

InvalidRequestError: Object '' is already attached to session

I'm getting:
sqlalchemy.exc.InvalidRequestError: Object '<DBEdge at 0x103c4a190>' is already attached to session '1' (this is '2')
in this line
session.add(edge)
When I'm trying to run this:
def findOrCreateEdge(self,user1,user2): #user1 is followed by user2
if user1.id>user2.id:
user1, user2 = user2, user1
kind = 2
else:
kind = 1
edge = self.findEdge(user1,user2)
if edge:
if edge.kind==1 and kind==2:
edge.kind = 3
if edge.kind==2 and kind==1:
edge.kind = 3
return edge
else:
edge = DBEdge(user1,user2)
edge.kind = kind
user1.edge_count = user1.edge_count + 1
user2.edge_count = user2.edge_count + 1
#session.save(edge) # we don't flush edges here, because it gives us a huge speedup to do a bunch at once then flush.
try:
session.add(edge)
session.commit()
except:
session = Session()
session.add(edge)
session.commit()
return edge
The problem lies with adding the edge twice, once to the first session and then, on an exception, to the second session. I don't know what exactly you are trying to achieve here, but instead of brutally stuffing the edge into a new session, it would be better if you investigated the error and fixed the problem. Alternatively, you may want to roll the previous session back and restart it, then adding the edge to it.
Creating a new session when you already have one is almost always a mistake (except when the context itself changed, but that doesn't seem to be the case here).

Binary search of unaccesible data field in ldap from python

I'm interested in reproducing a particular python script.
I have a friend who was accessing an ldap database, without authentication. There was a particular field of interest, we'll call it nin (an integer) for reference, and this field wasn't accessible without proper authentication. However, my friend managed to access this field through some sort of binary search (rather than just looping through integers) on the data; he would check the first digit, check if it was greater or less than the starting value, he would augment that until it returned a true value indicating existence, adding digits and continuing checking until he found the exact value of the integer nin.
Any ideas on how he went about this? I've access to a similarly set up database.
Your best bet would be to get authorization to access that field. You are circumventing the security of the database otherwise.
Figured it out. I just needed to filter on (&(cn=My name)(nin=guess*) and I managed to filter until it returns the correct result.
Code follows in case anyone else needs to find a field they aren't supposed to access, but can check results for and know the name of.
def lookup(self, username="", guess=0,verbose=0):
guin = guess
result_set = []
varsearch = "(&(name=" + str(username) + ")(" + "nin" + "=" + str(guin) + "*))"
result_id = self.l.search("", ldap.SCOPE_SUBTREE, varsearch, ["nin"])
while True:
try:
result_type, result_data = self.l.result(result_id, 0, 5.0)
if (result_data == []):
break
else:
if result_type == ldap.RES_SEARCH_ENTRY:
result_set.append(result_data)
except ldap.TIMEOUT:
return {"name": username}
if len(result_set) == 0:
return self.lookup(username, guin + 1,verbose)
else:
if guess < 1000000:
return self.lookup(username, guess * 10,verbose)
else:
if verbose==1:
print "Bingo!",
return str(guess)

Categories

Resources