How to prevent duplicated records and only update it? - python

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.

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 create a sqlalchemy delete query with multiples parameter from a loop

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)

Split Purchase Order according to Product Category

I wanna split the Purchase Order according to Product Category.
My Code so far:
_inherit ='purchase.order.line'
split = fields.Boolean(string='Split')
_inherit ='purchase.order'
def btn_split_rfq(self):
flag = []
for record in self:
if record.order_line:
for rec in record.order_line:
rec.split = True # oles tis eggrafes true
flag.append(rec.product_id.categ_id.id) # lista me ta categ ids
newlist=[ii for n,ii in enumerate(flag) if ii not in flag[:n]] # ta krata mono mia fora an uparxoun polles
for index in newlist: # gia 2 katigories 8a treksi 2 fores
quotation_id = self.copy()
for index in record.order_line:
if index.split:
self.env['purchase.order.line'].browse(index.id).unlink()
else:
raise ValidationError(_('Please Select Order Line To Split'))
The code so far, is split to multiple POs e.g. if i have 2 type of categories is making 2 POs but and the two POs is taking and the 4 products not only of product category(see image below).
Output:
But i want this kind of Output:
Any solution?
I tried to just ignore your code example, because it is difficult to understand for me. If you want try out my attempt:
def button_split_by_prod_categ(self):
self.ensure_one()
groups = {}
# group lines by product category
for line in self.order_line:
if line.product_id.categ_id not in groups:
groups[line.product_id.categ_id] = line
else:
groups[line.product_id.categ_id] =| line
skip = True
orders = self
for lines in groups.values():
# skip first group
if skip:
skip = False
continue
# or create a new order without lines and connect
# the group's lines with it
else:
default_values = {'order_line': []}
new_order = self.copy(default=default_values)
lines.write({'order_id': new_order.id})
orders |= new_order
# now you could return a list view with all orders
# or just do 'nothing'
return
I found solution to my problem, i dont think is pretty but it does the job. Thanks # CZoellner and #Charif DZ for the effort!!!
def btn_split_rfq(self):
flag =[]
for record in self:
if record.order_line:
for rec in record.order_line: #run for all products on purchase order
flag.append(rec.product_id.categ_id.id) # append product category ids
categ_ids=[ii for n,ii in enumerate(flag) if ii not in flag[:n]] # filter list,keep only one time every product category id
categ_ids.sort() # sorting list
for index in categ_ids: # will run 2 times if there is 2 product categories
quotations_ids = [self.copy()]
for order_line in quotations_ids:
prods = self.env['purchase.order.line'].search([('product_categ_id' ,'!=',index),('order_id','=',int(order_line))])
for ids in prods:
self.env['purchase.order.line'].browse(ids.id).unlink()
else:
raise ValidationError(_('Not Available Purchase Order Lines'))

Group by column to get array results in Postgresql

I have a table called moviegenre which looks like:
moviegenre:
- movie (FK movie.id)
- genre (FK genre.id)
I have a query (ORM generated) which returns all movie.imdb and genre.id's which have genre.id's in common with a given movie.imdb_id.
SELECT "movie"."imdb_id",
"moviegenre"."genre_id"
FROM "moviegenre"
INNER JOIN "movie"
ON ( "moviegenre"."movie_id" = "movie"."id" )
WHERE ( "movie"."imdb_id" IN (SELECT U0."imdb_id"
FROM "movie" U0
INNER JOIN "moviegenre" U1
ON ( U0."id" = U1."movie_id" )
WHERE ( U0."last_ingested_on" IS NOT NULL
AND NOT ( U0."imdb_id" IN
( 'tt0169547' ) )
AND NOT ( U0."imdb_id" IN
( 'tt0169547' ) )
AND U1."genre_id" IN ( 2, 10 ) ))
AND "moviegenre"."genre_id" IN ( 2, 10 ) )
The problem is that I'll get results in the format:
[
('imdbid22`, 'genreid1'),
('imdbid22`, 'genreid2'),
('imdbid44`, 'genreid1'),
('imdbid55`, 'genreid8'),
]
Is there a way within the query itself I can group all of the genre ids into a list under the movie.imdb_id's? I'd like do to grouping in the query.
Currently doing it in my web app code (Python) which is extremely slow when 50k+ rows are returned.
[
('imdbid22`, ['genreid1', 'genreid2']),
('imdbid44`, 'genreid1'),
('imdbid55`, 'genreid8'),
]
thanks in advance!
edit:
here's the python code which runs against the current results
results_list = []
for item in movies_and_genres:
genres_in_common = len(set([
i['genre__id'] for i in movies_and_genres
if i['movie__imdb_id'] == item['movie__imdb_id']
]))
imdb_id = item['movie__imdb_id']
if genres_in_common >= min_in_comon:
result_item = {
'movie.imdb_id': imdb_id,
'count': genres_in_common
}
if result_item not in results_list:
results_list.append(result_item)
return results_list
select m.imdb_id, array_agg(g.genre_id) as genre_id
from
moviegenre g
inner join
movie m on g.movie_id = m.id
where
m.last_ingested_on is not null
and not m.imdb_id in ('tt0169547')
and not m.imdb_id in ('tt0169547')
and g.genre_id in (2, 10)
group by m.imdb_id
array_agg will create an array of all the genre_ids of a certain imdb_id:
http://www.postgresql.org/docs/current/interactive/functions-aggregate.html#FUNCTIONS-AGGREGATE-TABLE
I hope python code will be fast enough:
movielist = [
('imdbid22', 'genreid1'),
('imdbid22', 'genreid2'),
('imdbid44, 'genreid1'),
('imdbid55', 'genreid8'),
]
dict = {}
for items in movielist:
if dict[items[0]] not in dict:
dict[items[0]] = items[1]
else:
dict[items[0]] = dict[items[0]].append(items[1])
print dict
Output:
{'imdbid44': ['genreid1'], 'imdbid55': ['genreid8'], 'imdbid22': ['genreid1', 'genreid2']}
If you just need movie name, count:
Change this in original query you will get the answer you dont need python code
SELECT "movie"."imdb_id", count("moviegenre"."genre_id")
group by "movie"."imdb_id"

Q: Pandas dataframe from for loop

EDIT 2, 9/1 See my answer below!
Pretty new at Python and Pandas here. I've got a script here that uses a for loop to query my database using each line in my list. That all works great, but I can't figure out how to build a data frame from the results of that loop. Any and all pointers are welcome!
#Remove stuff
print "Cleaning list"
def multiple_replacer(key_values):
replace_dict = dict(key_values)
replacement_function = lambda match: replace_dict[match.group(0)]
pattern = re.compile("|".join([re.escape(k) for k, v in key_values]), re.M)
return lambda string: pattern.sub(replacement_function, string)
multi_line = multiple_replacer(key_values)
print "Querying Database..."
for line in source:
brand_url = multi_line(line)
#Run Query with cleaned list
mysql_query = ("select ub.url as 'URL', b.name as 'Name', b.id as 'ID' from api.brand b join api.url_brand ub on b.id=ub.brand_id where ub.url like '%%%s%%' and b.deleted=0 group by 3;" % brand_url)
list1 = []
brands = my_query('prod', mysql_query)
print "Writing CSV..."
#Create DF and CSV
for row in brands:
list1.append({"URL":row['URL'],"Name":['Name'],"ID":['ID']})
if brands.shape == (3,0):
df1 = pd.DataFrame(data = brands, columns=['URL','Name','ID'])
output = df1.to_csv('ongoing.csv',index=False)
EDIT 8/30
Here is my edit, attempting to use zyxue's method:
#Remove stuff
print "Cleaning list"
def multiple_replacer(key_values):
replace_dict = dict(key_values)
replacement_function = lambda match: replace_dict[match.group(0)]
pattern = re.compile("|".join([re.escape(k) for k, v in key_values]), re.M)
return lambda string: pattern.sub(replacement_function, string)
multi_line = multiple_replacer(key_values)
print "Querying Database..."
for line in source:
brand_url = multi_line(line)
#Run Query with cleaned list
mysql_query = ("select ub.url as 'URL', b.name as 'Name', b.id as 'ID' from api.brand b join api.url_brand ub on b.id=ub.brand_id where ub.url like '%%%s%%' and b.deleted=0 group by 3;" % brand_url)
brands = my_query('prod', mysql_query)
print "Writing CSV..."
#Create DF and CSV
records = []
for row in brands:
records.append({"URL":row['URL'],"Name":['Name'],"ID":['ID']})
if brands.shape == (3,0):
records.append(dict(zip(brands, ['URL', 'Name', 'ID'])))
df1 = pd.DataFrame.from_records(records)
output = df1.to_csv('ongoing.csv', index=False)
but this only returns a blank CSV. I'm sure I'm applying it wrong.
records = []
for row in brands:
# if brands.shape == (3,0):
# records.append(dict(zip(brands, ['URL', 'Name', 'ID'])))
# update bug fix:
if row.shape == (3,0):
records.append(dict(zip(row, ['URL', 'Name', 'ID'])))
df1 = pd.DataFrame.from_records(records)
output = df1.to_csv('ongoing.csv', index=False)
# ref:
# >>> pd.DataFrame.from_records([{'a': 1, 'b':2}, {'a': 11, 'b': 22}])
# a b
# 0 1 2
# 1 11 22
Okay, I figured it out, and I thought I should post the working script. #zyxue was pretty much right.
source = open('urls.txt')
key_values = ("http://",""), ("https://",""), ("www.",""), ("\n","")
#Remove stuff
print "Cleaning list"
def multiple_replacer(key_values):
replace_dict = dict(key_values)
replacement_function = lambda match: replace_dict[match.group(0)]
pattern = re.compile("|".join([re.escape(k) for k, v in key_values]), re.M)
return lambda string: pattern.sub(replacement_function, string)
multi_line = multiple_replacer(key_values)
print "Querying Database..."
records = []
for line in source:
brand_url = multi_line(line)
#Run Query with cleaned list
mysql_query = ("select ub.url as 'URL', b.name as 'Name', b.id as 'ID' from api.brand b join api.url_brand ub on b.id=ub.brand_id where ub.url like '%%%s%%' and b.deleted=0 group by 3;" % brand_url)
brands = my_query('prod', mysql_query)
#Append results to dict (records)
for row in brands:
records.append({"URL":row['URL'],"Name":row['Name'],"ID":row['ID']})
#Create DataFrame
df = pd.DataFrame.from_dict(records)
#Create CSV
output = df.to_csv('ongoing.csv',index=False)
Essentially, I needed to layer the second for loop under the first and create the 'records' dictionary before the looping began. This causes an append to the dictionary for every line in 'source'. Seems like a pretty simple concept now!

Categories