How create a sqlalchemy delete query with multiples parameter from a loop - python

I'm new in python and sqlalchemy.
I already have a delete method working if I construct the where conditions by hand.
Now, I need to read the columns and values from an enter request in yaml format and create the where conditions.
#enter data as yaml
items:
- item:
table: [MyTable,OtherTable]
filters:
field_id: 1234
#other_id: null
Here is what I try and can't go ahead:
for i in use_case_cfg['items']:
item = i.get('item')
for t in item['table']:
if item['filters']:
filters = item['filters']
where_conditions = ''
count = 0
for column, value in filters.items():
aux = str(getattr(t, column) == bindparam(value))
if count == 0:
where_conditions += aux
else:
where_conditions += ', ' + aux
count += 1
to_delete = inv[t].__table__.delete().where(text(where_conditions))
#to_delete = t.__table__.delete().where(getattr(t, column) == value)
else:
to_delete = inv[t].__table__.delete()
CoreData.session.execute(to_delete)
To me, it looks ok, but when I run, I got the error below:
sqlalchemy.exc.StatementError: (sqlalchemy.exc.InvalidRequestError) A value is required for bind parameter '9876'
[SQL: DELETE FROM MyTable WHERE "MyTable".field_id = %(1234)s]
[parameters: [{}]]
(Background on this error at: http://sqlalche.me/e/cd3x)
Can someone explain to me what is wrong or the proper way to do it?
Thanks.

There are two problems with the code.
Firstly,
str(getattr(t, column) == bindparam(value))
is binding the value as a placeholder, so you end up with
WHERE f2 = :Bob
but it should be the name that maps to the value in filters (so the column name in your case), so you end up with
WHERE f2 = :f2
Secondly, multiple WHERE conditions are being joined with a comma, but you should use AND or OR, depending on what you are trying to do.
Given a model Foo:
class Foo(Base):
__tablename__ = 'foo'
id = sa.Column(sa.Integer, primary_key=True)
f1 = sa.Column(sa.Integer)
f2 = sa.Column(sa.String)
Here's a working version of a segment of your code:
filters = {'f1': 2, 'f2': 'Bob'}
t = Foo
where_conditions = ''
count = 0
for column in filters:
aux = str(getattr(t, column) == sa.bindparam(column))
if count == 0:
where_conditions += aux
else:
where_conditions += ' AND ' + aux
count += 1
to_delete = t.__table__.delete().where(sa.text(where_conditions))
print(to_delete)
session.execute(to_delete, filters)
If you aren't obliged to construct the WHERE conditions as strings, you can do it like this:
where_conditions = [(getattr(t, column) == sa.bindparam(column))
for column in filters]
to_delete = t.__table__.delete().where(sa.and_(*where_conditions))
session.execute(to_delete, filters)

Related

Relocate the table index in python 3

Query = search _entry.get()
Sql = *SELECT FROM customers where last_name = %s"
Data = (query,)
Result = my_cursor. Execute (sql, data)
Result = my_cursor. fetchall ()
If not result :
Result = "record not found... "
Query_label = Label(search _customer _window, text =result)
Query_label. Place (x=40,y=130)
else :
For index, x in enumerate (result) :
Num =0
Index +=2
For y in x:
Query_label = Label(search _customer_window, text=y)
Query_label.grid(row=index,column=num)
Num +=1
I set the value of index to 2 but nothing happens. Thanks for your help.
When I run the program, the label (query_lqbel) is shown at top left side of the window (row 0, column =0), how can I change the location of label. Its actually a label on which some data are shown.

How do I insert into a Table one Primary Key and Two Foreign Keys?

I work with Rolls of plastic film in different legnth and width. And I'm creating a Database to store all the orders, and, in order to avoid repetition, I created separate tables for length(class(Comprimento)) and width(class(Largura)). I used UUID to create distinct ID's.
Now, I want to cross both tables in a Model class. Which is:
class Largura(Base):
__tablename__ = 'largura'
id = Column(GUID(), primary_key=True, default=lambda: str(uuid.uuid4()))
largura = Column(String)
modelos_l = relationship('Modelo', back_populates='larguras', cascade='all, delete')
def __repr__(self):
return f"<Largura {self.largura}>"
class Comprimento(Base):
__tablename__ = 'comprimento'
id = Column(GUID(), primary_key=True, default=lambda: str(uuid.uuid4()))
comprimento = Column(String)
modelos_c = relationship('Modelo', back_populates='comprimentos', cascade='all, delete')
def __repr__(self):
return f"<Comprimento {self.comprimento}>"
class Modelo(Base):
__tablename__ = 'modelo'
id = Column(GUID(), primary_key=True, default=lambda: str(uuid.uuid4()))
descricao = Column(String(50))
largura_id = Column(GUID(), ForeignKey("largura.id"), default=lambda: str(uuid.uuid4()))
comprimento_id = Column(GUID(), ForeignKey("comprimento.id"), default=lambda: str(uuid.uuid4()))
larguras = relationship('Largura', back_populates='modelos_l')
comprimentos = relationship('Comprimento', back_populates='modelos_c')
def __repr__(self):
return f"<Modelo {self.id}>"
Then, i created a file dedicated to my data insert on this table:
from DBModelPy3 import Comprimento,Largura,Modelo,session
from sqlalchemy import create_engine
import pandas as pd
#Pre Loading my CSV file
df = pd.read_csv("dataorged.csv", sep=',')
pd.set_option('display.float_format','{:.0f}'.format) #change the number format to hide the ','
cnx = create_engine('sqlite:///data_hub2.db', echo=True).connect()
df_modelo = df[['larg_ajustada', 'comp']] # My dataframe that contains the orders. I chose the specifics columns needed for this insertion.
#print(df_modelo)
# Loading the Tables from my database
df_largura = pd.read_sql_table('largura', cnx)
df_comprimento = pd.read_sql_table('comprimento', cnx)
With everything loaded I decided to combine all the legnths and widths i had already on my two tables (df_largura and df_comprimento), and then filtered using the original file which contains the orders.
# COMBINING ALL THE LENGTH AND WIDTH OF MY TABLES
model_num = []
for n_larg in range(len(df_largura)):
db_larg = str(df_largura['largura'][n_larg])
for n_comp in range(len(df_comprimento)):
db_comp = df_comprimento['comprimento'][n_comp]
combined = str(db_larg) + "x" + str(db_comp)
model_num.append([db_larg,db_comp,combined])
df_modelos_ex = pd.DataFrame(model_num)
df_modelos_ex.columns = ['larg','comp','combined']
With these, i had all possible combinations on my dataframe.
And created the combined variable to match later
modelos_existentes = []
# COMBINATIONS THAT APPEAR IN THE ORDER DATAFRAME #
for item in range(len(df_modelo)):
mod_larg = df_modelo['larg_ajustada'][item]
mod_comp = df_modelo['comp'][item]
mod_comb = str(mod_larg) + "x" + str(mod_comp)
modelos_existentes.append([mod_larg,mod_comp,mod_comb])
df_mod_existentes = pd.DataFrame(modelos_existentes)
df_mod_existentes.columns = ['ex_larg','ex_comp','ex_comb']
df_limpo = df_mod_existentes.drop_duplicates(subset=['ex_comb'])
df_limpo.reset_index(drop=True, inplace=True)
With all my elements, then the madness began.
I started a loop to run through all my Dataframes:
for l_row in range(len(df_limpo)): # For Each Row in my dataframe which contains the orders,
larg = df_limpo['ex_larg'][l_row] # create variable for width
comp = df_limpo['ex_comp'][l_row] # create variable for lenght
comb = df_limpo['ex_comb'][l_row] # create variable for combination of both
for n_row in range(len(df_largura)): # For each row in my width table from DB,
db_larg_id = df_largura['id'][n_row] # I create a Variable for the PK from width
db_larg_largura = df_largura['largura'][n_row] # Create a Variable with the value
lar = session.query(Largura).filter(Largura.id == db_larg_id).first()
if db_larg_largura == larg: # If the value on my table matches the value of the row in the order,
for m_row in range(len(df_comprimento)): # For each length in my table on the DB,
db_comp_id = df_comprimento['id'][m_row]
db_comp_comprimento = df_comprimento['comprimento'][m_row]
compr = session.query(Comprimento).filter(Comprimento.id == db_comp_id).first()
if db_comp_comprimento == comp: # If the value on my table matches the value of the row in the order
new_model = Modelo(descricao=df_limpo['ex_comb'][n_linha], larguras=lar, comprimentos=compr)
from here, i would only add the session.add(new_model) and session.commit() to finish my code.
But it's not adding.
What I would like is for my Modelo table be like:
MODELO Table
ID(PK) | DESCRIPTION (Combined values String) | Largura_id (width_id, FK) | Comprimento_id (length_id, FK)
Sorry about the long explanation. Tried my best!
If anyone have the same trouble:
##########################
# ADDING TO THE DATABANK #
##########################
lista_a = [] #Created an empty List
for n_linha in range(len(df_limpo)): #Ran through my dataframe
larg_a = df_limpo['ex_larg'][n_linha] #Extracted width and length from it
comp_a = df_limpo['ex_comp'][n_linha]
for m_linha in range(len(df_largura)): #Ran my width table from database
db_larg_id = df_largura['id'][m_linha]
db_larg_largura = df_largura['largura'][m_linha]
if larg_a == db_larg_largura: #Checked if the width from my dataframe matches the one on the table
lista_a.append([larg_a,comp_a,db_larg_id]) #appended to the list_a
#print(lista_a)
df_lista_a = pd.DataFrame(lista_a) #Created a new Dataframe
df_lista_a.columns = ['larg','comp','id_larg']
lista_b = [] #Created a new list
for n_row in range(len(df_lista_a)): #Ran through my new dataframe
larg_b = df_lista_a['larg'][n_row] #Extracted each column from it
comp_b = df_lista_a['comp'][n_row]
larg_b_id = df_lista_a['id_larg'][n_row]
#df_limpo_lrow = df_limpo['ex_larg'][n_row]
#df_limpo_crow = df_limpo['ex_comp'][n_row]
#df_limpo_cbrow = df_limpo['ex_comb'][n_row]
#print(larg_b,comp_b,larg_b_id,n_row)
for m_row in range(len(df_comprimento)): #Ran through my lenght table
db_comp_id = df_comprimento['id'][m_row]
db_comp_comprimento = df_comprimento['comprimento'][m_row]
if comp_b == db_comp_comprimento: #Check if the lenght from dataframe matches the lenght on my table on the database
#print(larg_b,comp_b,n_row,m_row,df_limpo_lrow)
lista_b.append([larg_b,comp_b,larg_b_id,db_comp_id]) #appended the lenght id to my list
break
#print(lista_b)
#print(len(df_lista_a),len(df_limpo),len(lista_b))
df_lista_b = pd.DataFrame(lista_b) #converted to Dataframe.
df_lista_b.columns = ['larg','comp','id_larg','id_comp']
# HERE's the ACTUAL INSERTION
for n_model in range(len(df_lista_b)): #For each model found on the list, extract the values and add to new_model.
mod_largura = df_lista_b['larg'][n_model]
mod_comprimento = df_lista_b['comp'][n_model]
mod_largura_id = df_lista_b['id_larg'][n_model]
mod_comprimento_id = df_lista_b['id_comp'][n_model]
lar = session.query(Largura).filter(Largura.id == df_largura['id'][1]).first()
compr = session.query(Comprimento).filter(Comprimento.id == df_comprimento['id'][1]).first()
new_model = Modelo(descricao=df_limpo['ex_comb'][n_model], larguras=lar, comprimentos=compr)
print("Modelo: " + df_limpo['ex_comb'][n_model] + " com Id's " + mod_largura_id + " e " + mod_comprimento_id + " adicionados!")
session.add(new_model)
session.commit()
Then it's done.

How do I update a value in a dataframe in a loop?

I am trying to update a rating row by row. I have one dataframe of players, that all start with the same rating. For each match, I want the rating to change. Another dataframe contains results of each match.
import pandas as pd
gamesdata = [['paul','tom'],['paul','lisa'],['tom','paul'],['lisa','tom'],['paul','lisa'],['lisa','tom'],['paul','tom']]
games = pd.DataFrame(gamesdata, columns = ['Winner', 'Looser'])
playersdata= ['lisa','paul','tom']
players = pd.DataFrame(playersdata, columns = ['Name'])
mean_elo = 1000
elo_width = 400
k_factor = 64
players['elo'] = mean_elo
def update_elo(winner_elo, loser_elo):
expected_win = expected_result(winner_elo, loser_elo)
change_in_elo = k_factor * (1-expected_win)
winner_elo += change_in_elo
loser_elo -= change_in_elo
return winner_elo, loser_elo
def expected_result(elo_a, elo_b):
expect_a = 1.0/(1+10**((elo_b - elo_a)/elo_width))
return expect_a
for index, row in games.iterrows():
winnername = row['Winner']
losername = row['Looser']
web = players['elo'].loc[players['Name'] == winnername].values[0]
wIndex = players.loc[players['Name'] == winnername]
#I want to return just the index, so I can update the value
print(wIndex)
leb = players['elo'].loc[players['Name'] == losername].values[0]
print('Winner Elo before: ' + str(web))
winner_elo, looser_elo = update_elo(web, leb)
print('Winner Elo after: ' + str(winner_elo))
#here I want to update value
#players.at[wIndex,'elo']=winner_elo
I am trying to update the value in the players table using
players.at[wIndex,'elo']=winner_elo
but i struggle to get the index with this code:
wIndex = players.loc[players['Name'] == winnername]
Found a sollution:
wIndex = players.loc[players['Name'] == winnername].index.values
Can't believe i missed that

How to prevent duplicated records and only update it?

i want to add some records to another table model without duplicated it
i create a function to check the table data and return specific values to add it in another table
here is my code
def lol_hah(self,cr,uid,ids,context=None):
noobs_data=[]
cr.execute("select DISTINCT ON (subject_id)subject_id from fci_attendance_line")
noobs1 = cr.dictfetchall()
ages = [li['subject_id'] for li in noobs1]
print (ages)
for k in ages:
cr.execute(
"select DISTINCT ON (student_id)student_id, count(present) AS Number_of_Absenece,present,subject_id as subject_name, s.name AS Student_Name,s.standard_id,s.group_id from fci_attendance_line ,fci_student s where subject_id=%d and present=False and s.id=student_id group by student_id ,s.sit_number,present, s.name,s.standard_id,s.group_id ,subject_id "% (
k))
noobs = cr.dictfetchall()
cr.execute(
"select DISTINCT ON (student_id)student_id, count(present) AS Number_of_Absenece,present,subject_id as subject_name, s.name AS Student_Name,s.standard_id,s.group_id from fci_attendance_line ,fci_student s where subject_id=%d and present=False and s.id=student_id group by student_id ,s.sit_number,present, s.name,s.standard_id,s.group_id ,subject_id "% (
k))
noobs_details = cr.dictfetchall()
for details_ids in noobs_details:
for data in noobs:
details_ids[data['student_id']] = str(data['number_of_absenece'])+str(data['student_id']) + str(data['standard_id'])+str(data['group_id'])+str(data['subject_name'])
noobs_data.append(details_ids)
print (noobs_data)
subo_obj = self.pool.get('fci.attendance.subjects')
count=0
for name in noobs_data:
count =count+1
student_ids=self.search(cr,uid,[('student_id.id','=',int(name['student_id']))])
if student_ids and int(name['number_of_absenece']) >= 3:
subo_obj.create(cr, uid,{'student_id':int(name['student_id']),
'number_of_absence':int(name['number_of_absenece']),
'subject_id':int(name['subject_name']),
'standard_id':int(name['standard_id']),
'standard_group':int(name['group_id'])})
print ('Number of times LOL : ',count)
return True
my function work perfectly but when i add another value to my table and try to add to the other fields it duplicated but i want to just update the already date if excist i try to change my function like this but it didn't work :
def lol_hah(self,cr,uid,ids,context=None):
noobs_data=[]
cr.execute("select DISTINCT ON (subject_id)subject_id from fci_attendance_line")
noobs1 = cr.dictfetchall()
ages = [li['subject_id'] for li in noobs1]
print (ages)
for k in ages:
cr.execute(
"select DISTINCT ON (student_id)student_id, count(present) AS Number_of_Absenece,present,subject_id as subject_name, s.name AS Student_Name,s.standard_id,s.group_id from fci_attendance_line ,fci_student s where subject_id=%d and present=False and s.id=student_id group by student_id ,s.sit_number,present, s.name,s.standard_id,s.group_id ,subject_id "% (
k))
noobs = cr.dictfetchall()
cr.execute(
"select DISTINCT ON (student_id)student_id, count(present) AS Number_of_Absenece,present,subject_id as subject_name, s.name AS Student_Name,s.standard_id,s.group_id from fci_attendance_line ,fci_student s where subject_id=%d and present=False and s.id=student_id group by student_id ,s.sit_number,present, s.name,s.standard_id,s.group_id ,subject_id "% (
k))
noobs_details = cr.dictfetchall()
for details_ids in noobs_details:
for data in noobs:
details_ids[data['student_id']] = str(data['number_of_absenece'])+str(data['student_id']) + str(data['standard_id'])+str(data['group_id'])+str(data['subject_name'])
noobs_data.append(details_ids)
print (noobs_data)
subo_obj = self.pool.get('fci.attendance.subjects')
count=0
for name in noobs_data:
count =count+1
student_ids=self.search(cr,uid,[('student_id.id','=',int(name['student_id']))])
if student_ids and int(name['number_of_absenece']) >= 3:
ds_ids=subo_obj.search(cr,uid,[('student_id.id','=',int(name['student_id']))])
print('Here is ids found',ds_ids)
if ds_ids != []:
subo_obj.write(cr, uid, ds_ids, {'number_of_absence': int(name['number_of_absenece'])}, context=context)
else:
subo_obj.create(cr, uid,{'student_id':int(name['student_id']),
'number_of_absence':int(name['number_of_absenece']),
'subject_id':int(name['subject_name']),
'standard_id':int(name['standard_id']),
'standard_group':int(name['group_id'])})
print ('Number of times LOL : ',count)
return True
I hope you got what i want :)
Do you mean you're trying to merge 2 list but want to have only 1 unique instance of each item?
If this is the case you could add all of the data to the list then run something like noobs_data_trimmed = list(set(noobs_data))
Making a list into a set will obliterate exact duplicates within the set. Then you can turn it back into a list for easier processing.

Append column field name with date range operator dynamically in django?

This is the code I'm using :
where_con=''
#loop on model name
# getting all info for one model
where_con = {}
for k in model_k_j:
type_val = type(model_k_j[k])
if type_val== dict:
print "dictonary type"
"""
for model_field_dict in model_k_j[k]:
start= model_k_j[k][model_field_dict]
end= model_k_j[k][model_field_dict]
where_con[k] = medical_home_last_visit__range=[start,end ]
break
"""
else:
col_name.append(k)
where_con[k] = model_k_j[k]
# covert data type
# **where_con {unpack tuple}
# where_con =str(where_con)
# print where_con
qs_new = model_obj.objects.filter(**where_con)
The field medical_home_last_visit is not static, it is coming dynamically.
How do I append it ? I have tried something like:
colname_variable = medical_home_last_visit
where_con[k] = colname_variable + __range=[start,end ]
but it is not working properly, and gives this error :
where_con[k] = colname_variable + __range=[start,end ]
^
SyntaxError: invalid syntax
where_con is dict and key name should be equal colname_variable__range:
#k = 'medical_home_last_visit__range'
where_con[k] = (start, end)
qs_new = model_obj.objects.filter(**where_con)
it is equal to:
model_obj.objects.filter(medical_home_last_visit__range=(start, end))
and any other filter args should be keys in where_con, for example:
#k = 'some_date__lte'
where_con[k] = datetime.datetime.now()

Categories