How to get an id in a many2many field? - python-2.7

Does someone can explain what is going on with my sql statement. Here is my code chunk.
for so in self.pool.get('sale.order').browse(cr,uid,so_id,context):
_logger.info("\n\n\t\t\t SALE ORDER ID %d"%(so.id))
confirmed_by = so.confirmed_by.id
_logger.info("\n\n\t\t\tconfirmed by %s"%(str(confirmed_by)))
rg_id = cr.execute("select rg.id from res_users ru,res_groups rg,res_groups_users_rel rgr
where ru.id = rgr.uid and rgr.gid = rg.id and ru.id = "+str(confirmed_by)+" and rg.name like 'Project Second User'")
_logger.info("\n\n\t\t\tRES GROUPS IDS %s"%(rg_id))
My confirmed by returns an id but I don't know why rg_id returns None when executed. When used in PgAdmin my query works fine.
Any help is very much appreciated.

This is how manage to solve the None issue:
cr.execute("select rg.id from res_users ru,res_groups rg,res_groups_users_rel rgr
where ru.id = rgr.uid and rgr.gid = rg.id and ru.id = "+str(confirmed_by)+" and rg.name like 'Project Second User'")
rg_id = cr.fetchall()
Now, my rg_id is returning either an id from a table res_groups or [] if there is no record found.

Related

Efficiently updating a large number of records based on a field in that record using Django

I have about a million Comment records that I want to update based on that comment's body field. I'm trying to figure out how to do this efficiently. Right now, my approach looks like this:
update_list = []
qs = Comments.objects.filter(word_count=0)
for comment in qs:
model_obj = Comments.objects.get(id=comment.id)
model_obj.word_count = len(model_obj.body.split())
update_list.append(model_obj)
Comment.objects.bulk_update(update_list, ['word_count'])
However, this hangs and seems to time out in my migration process. Does anybody have suggestions on how I can accomplish this?
It's not easy to determine the memory footprint of a Django object, but an absolute minimum is the amount of space needed to store all of its data. My guess is that you may be running out of memory and page-thrashing.
You probably want to work in batches of, say, 1000 objects at a time. Use Queryset slicing, which returns another queryset. Try something like
BATCH_SIZE = 1000
start = 0
base_qs = Comments.objects.filter(word_count=0)
while True:
batch_qs = base_qs[ start: start+BATCH_SIZE ]
start += BATCH_SIZE
if not batch_qs.exists():
break
update_list = []
for comment in batch_qs:
model_obj = Comments.objects.get(id=comment.id)
model_obj.word_count = len(model_obj.body.split())
update_list.append(model_obj)
Comment.objects.bulk_update(update_list, ['word_count'])
print( f'Processed batch starting at {start}' )
Each trip around the loop will free the space occupied by the previous trip when it replaces batch_qs and update_list. The print statement will allow you to watch it progress at a hopefully acceptable, regular rate!
Warning - I have never tried this. I'm also wondering whether slicing and filtering will play nice with each other or whether one should use
base_qs = Comments.objects.all()
...
while True:
batch_qs = base_qs[ start: start+BATCH_SIZE ]
....
for comment in batch_qs.filter(word_count=0) :
so you are slicing your way though rows in the entire DB table and retrieving a subset of each slice that needs updating. This feels "safer". Anybody know for sure?

How to "create or update" using F object?

I need to create LeaderboardEntry if it is not exists. It should be updated with the new value (current + new) if exists. I want to achieve this with a single query. How can I do that?
Current code looking like this: (2 queries)
reward_amount = 50
LeaderboardEntry.objects.get_or_create(player=player)
LeaderboardEntry.objects.filter(player=player).update(golds=F('golds') + reward_amount)
PS: Default value of "golds" is 0.
you can have one query hit less with the defaults :
reward_amount = 50
leader_board, created = LeaderboardEntry.objects.get_or_create(
player=player,
defaults={
"golds": reward_amount,
}
)
if not created:
leader_board.golds += reward_amount
leader_board.save(update_fields=["golds"])
I think your problem is the get_or_create() method so it return back a tuple with two values, (object, created) so you have to recieve them in your code as following:
reward_amount = 50
entry, __ = LeaderboardEntry.objects.get_or_create(player=player)
entry.golds += reward_amount
entry.save()
It will work better than your actual code, just will avoid make two queries.
Of course the save() method will hit again your database.
You can solve this with update_or_create:
LeaderboardEntry.objects.update_or_create(
player=player,
defaults={
'golds': F('golds') + reward_amount
}
)
EDIT:
Sorry, F expressions in update_or_create are not yet supported.

IF ELSE statement to set variable value

I am creating a site where clients can construct a price quote.
I have used Tabulator to show the data in a table.
The Tabulator data is in its own .JS file "buildTabulator.js", while the Quote scripts are in another .JS file "quote.js".
I am able to extract the data and get it mostly doing what I want so far.
But, when I try to create an IF ELSE statement in the quote.js file to determine which price should be displayed based on the unit of measure (UOM) of the item, it will not work correctly. It always shows the EACH or EA price of the item which is in the IF part of the IF ELSE statement.
More specifically, if the user adds an item to the quote that is sold by the EACH it should show one price, but if they choose an item that is sold by the CASE it should display a different price.
Please see the attached screenshots and code below and advise if you can...
I am hoping this is something simple that a noob like me has missed by mistake.
First screenshot is showing the code in VSC.
Second screenshot is showing an example in the console log of the browser. This example is using an item that is sold by the CASE and should show the case price of the item but instead shows a "-" because the EACH price of this item is a dash since its not sold by the each.
In the log it shows CS for CASE which is correct but the "-" should actually be 0.2937 which is shown in the table above the console.
Please let me know if there is any more information I can provide or any questions you may have.
Thank you so much in advance!!
CODE FROM "buildTabulator.js"
cellClick: function (e, cell) {
globalThis.itemImage =
"imgsQuote/" + cell.getRow().getData().IMAGE + ".png";
globalThis.itemCode = cell.getRow().getData().CODE;
globalThis.itemDescription = cell.getRow().getData().DESCRIPTION;
globalThis.itemBx = cell.getRow().getData().BX;
globalThis.itemCs = cell.getRow().getData().CS;
globalThis.itemUom = cell.getRow().getData().UOM;
globalThis.itemCost = cell.getRow().getData().COST;
globalThis.itemBox = cell.getRow().getData().BOX;
globalThis.itemHalf = cell.getRow().getData().HALF;
globalThis.itemLess = cell.getRow().getData().LESS;
globalThis.itemCase = cell.getRow().getData().CASE;
globalThis.itemBxWt = cell.getRow().getData().BXWT;
globalThis.itemCsWt = cell.getRow().getData().CSWT;
// globalToLocal();
setItemPrice();
},
CODE FROM "quote.js"
function setItemPrice() {
console.log(globalThis.itemUom);
var itemPrice;
if ((globalThis.itemUom = "EA")) {
itemPrice = globalThis.itemBox;
} else {
itemPrice = globalThis.itemCase;
}
console.log(itemPrice);
}
after another 3 hours or so of searching I found an answer that works:
setting variable with ternary expression

Django filter by query result

In my fixturesquery below you can see I am filtering by the results of the teamsquery, and it works, but only for the first result of the teamsquery. So it only outputs the fixtures for the first userteam__userID=request.user
teamsquery = Team.objects.filter(userteams__userID=request.user)
fixturesquery = Fixtures.objects.filter(Q(hometeamID=teamsquery) |
Q(awayteamID=teamsquery))
How do i fix it so it outputs the fixtures for all the results of teamsquery?
If I understand correctly, your user can have multiplte teams, right?
If so, you can use:
teamsquery = Team.objects.filter(userteams__userID=request.user)
fixturesquery = Fixtures.objects.filter(Q(hometeamID__in=teamsquery)|Q(awayteamID__in=teamsquery))

GoogleSheet script editor - onEdit event with conditions / if statement

guys!
I'm new to this website and also not good with coding. So I would really appreciate some help.
Right now I'm in need of a specific code to make a google sheet work perfectly.
To further explain:
I have a google sheet that a few information will be input by other co-workers. What I need is a code that will register the date in a specific cell and by whom the input was made on another cell.
So far this is what I have:
function onEdit(event) {
var sheet = event.source.getSheetByName("Input");
// Note: actRng = return the last cell of the row modified
var actRng = event.source.getActiveRange();
var index = actRng.getRowIndex();
var cindex = actRng.getColumnIndex();
// Note: date = return date
// Note: user = return the user email
var userCell = sheet.getRange(index,14);
var dateCell = sheet.getRange(index,2);
var inputdate = Utilities.formatDate(new Date(), "GMT+0200", "yyyy-MM-dd");
// Note(with hour): var inputdate = Utilities.formatDate(new Date(), "GMT+0200", "yy-MM-dd HH:mm");
//var user = event.user; // Note: event.user will not give you collaborator's Id
var user = Session.getEffectiveUser();
// Note: setValue = Insert in the cell the date when this row was modified
if (userCell.Value == null) {
userCell.setValue(user);
dateCell.setValue(inputdate)
}
}
My main problems/questions are:
I don't exactly need the last modifier, but the person who first input info on the cells. Therefore I tried that last IF (If the cell that is supposed to have the last modifier e-mail is blank, it means that nobody changed that row before, so the code should add the user on the userCell), although it is not working since every change I make it ignores the verification.
I also want to add that the event will only happen if you add values, if you delete them, nothing happens. (so far even when I delete cells, it counts as modification)
Most of the sheet is protected to avoid that people by accident erase some of the formulas, so the cells that this code changes are also protected. Is there a way to make the code bypass cell protection?
Please, help me identify what I'm doing wrong and hopefully I'll get this working perfectly! Thanks for the help !
If you want to prevent the script from firing when a cell is deleted, try:
var editedCell = SpreadsheetApp.getActiveSheet().getRange(e.range.getRow(), e.range.getColumn());
if (editedCell == "") {
return;
}
I would change Session.getEffectiveUser() to session.getActiveUser().
The last if statement is unnecessary. You want whoever most recently edited the field to be identified, along with the date.