Django bulk updating via F - django

I am trying to bulk update a number of objects for a given model. I figured I could do this via a dictionary together with F doing something like
FooBar.objects.filter(...).update(order = order_dict[F('id')])
where order_dict is something like
{1: 2, 2: 3, 3: 1, 4: 4}
objects with id equal to 1, 2, 3, and 4 exist but it is giving me a key error: F(id) nonetheless. Why precisely does this not work? And is there some way to achieve this other than updating objects one by one or using a 3th party package?

Related

DynamoDB: Is it possible to get the last element in the list datatype?

I have document that looks like as follows:
{'id': 123,
'favorites': [5, 3, 7, 8, 1, 9, 2]}
In this document, favorite is of list type. I want to query the latest favorite or first/last 5 favorites. I'm not sure how can I achieve that in DynamoDB. Please help.
After hunting for this question for a while, unfortunately it's not supported by the DynamoDB. May be, it'll be supported in the future.
In current(22 Jun 2021) example of documentation, they used size(info.actors) to get the size.
You can do this:
ConditionExpression='#list[0] = :num',
ConditionExpression='size(#list) = :num',
However, you CANNOT do this:
ConditionExpression='#list[ size(#list)-1 ] = :num',
According to
boto3 documentation, it looks like it's impossible to get the last element.
The best work-around I've found so far is:
reverse all lists, then use #list[0]
use contains(#list, :elem)

Python 3 list with range and other individual numbers

I need to make a list of numbers. These numbers represent binary masks. The first 100 or so masks are all included in this range. In the next group of masks only certain masks are included. I need a list similar to the following.
[1,2,3,5,6,7,8,9,10,30,34,48,53,62]
Can I do something like [range(1,10),30,34,48,53,62]
or do I need to create my list using range(1,10) and then append the next list to it?
Thanks
Python 3 actually allow you to build a list literal prepending an * to any iterable objects - which are in turn expanded in place:
>>> [1,2, *range(10), *range(2)]
[1, 2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1]
If you need this n older Pythons, or if you'd prefer to keep readability for people not too proeficient in Python who might have to walk through your code, an option is just to concatenate your different list fragments using the + operator:
a = list(range(1,10)) + [ 30,34,48,53,62]
Looks like I had to use the list(range(1,10)+[47,34,57]
solution

Creation of unexpected tuple value

I am dealing with somewhat of a mystery and hoped for some clarity. I wrote a script for finding dice roll combinations adding to 24 that looks like the following:
start=[3,3,3,3,3,3,3,3]
outcomes=set(tuple(start)) #Use a set to ensure uniqueness
index_list=np.random.randint(0,8,1000)
#This little snippet adds one and subtracts one randomly, keeping total at 24
for i in xrange(0,500):
upper=index_list[i]
downer=index_list[i+20]
if start[upper]!=6 and start[downer]!=1:
start[upper]=start[upper]+1
start[downer]=start[downer]-1
outcomes.add(tuple(start))
print outcomes
What I am running into, is that When I look at outcomes, there is a single 3 of type 'int' in there.
set([(4, 4, 4, 3, 2, 2, 2, 3), 3, (2, 5, 4, 3, 1, 4, 2, 3), (4, 4, 4, 2, 3, 1, 3, 3),(4, 2, 5, 2, 3, 4, 1, 3)])
While I could certainly remove it, I am just curious how it is getting in there to begin with? My initial guess was the index list might be producing an index outside of [0-7], but it is not. I've looked for a similar question other places, but have yet to find a similar issue. Thanks!
set expects an iterable. You're passing a tuple which is an iterable.
set iterates through it, leaving just 1 value: 3 (because your tuple only contains the same 3 value).
You have to put your element in a list or tuple so it is seen as a single element (exactly the same problem when you pass a string and it is unexpectedly iterated upon)
The rest of your code is OK and has nothing to do with the problem.
Do this instead:
outcomes=set([tuple(start),])
now set iterates through a list of 1 tuple, effectively creating tuple elements.
You could do that also, maybe simpler:
outcomes=set()
outcomes.add(tuple(start))
there's no ambiguity since you're adding 1 element. It's not iterated through.

Django - Many To Many after filtering one end of the relationship, counting backwards always produces the value 1

I have two models that are in a Many To Many relationship, and I want the following effect to occur:
Consider models A and B in a many to many relationship with eachother.
A's related_name for B is bs and B's related name for A is as
Whenever I create an A or B it will always be immediately connect to one or more of the other, so initially all instances of A and B will have at least one related object.
If I want to delete an A (let's call it a0) I want it to delete all Bs that would be left with no related A's after a0 is deleted, so essentially I want to delete all B that have only a0 in their related_set as (the reverse example of this would also be expected).
The way I was trying to implement this is, when I want to delete an A such as a0, I would say:
a0.bs.annotate(Count('bs')).filter(bs__count=1).delete()
However this would unconditionally delete ALL related B instances in a0.bs, and when I went to the shell to test it out, when I would get this result:
>>> a0.bs.annotate(Count('bs')).values_list('bs__count',flat=True)
<QuerySet [1, 1, 1, 1]>
>>> B.objects.filter(as=a0).annotate(Count('bs')).values_list('bs__count',flat=True)
<QuerySet [1, 1, 1, 1]>
But I would also get this if I did this with the same database instance:
>>> B.objects.annotate(Count('bs')).filter(as=a0).values_list('bs__count',flat=True)
<QuerySet [1, 4, 6, 6]>
So it is the case that 3 out of the 4 of these B instances owuldn't satisfy count == 1 but they all satisfy if I filter for the specific B instances I want to look at before annotating, which seems significantly more efficient than the last command used (the one with the accurate result).
Can anyone give me any insight on this effect?
Can't you assume that any B record that does not have any related A records to it should be deleted as well? The same is true vice-versa as well.
A.objects.filter(pk=1).delete()
B.objects.filter(as=None).delete()

Doctrine2 custom records order

I have simple query to get all pictures from database:
$this->createQueryBuilder('p')
->getQuery()
->getResult();
And I have array of ID's, which represents how they should be arranged in result array. How can I tell doctrine, to return these pictures in that specific order? For example, my "order array" is [3, 5, 9, 1, 10] and I want to get results in that particular order.
There are several ways to do this. If you're using postgresql you can try one of the raw queries here: ORDER BY the IN value list . If you're using mysql you can try the suggestions here: Ordering by the order of values in a SQL IN() clause
If you instead want to do it through straight Doctrine you could create a generic mapper function that orders the results. For very large result sets you may hit performance issues since you have O(n^2). But it's a little simpler than trying to make your own custom Doctrine function to handle it, relying on database implementation.
Say your query returns 5 results with the following ids: (95, 4, 1, 33, 35). Now say you want them returned as (1, 35, 4, 33, 95):
$entities = $em->getRepository('YourBundle:Picture')->findBy(/*some criteria*/);
$orderFunction = function($id) use ($entities)
{
foreach ($entities as $entity)
{
if ($entity->getId() == $id) {
return $entity;
}
}
};
$orderAs = array(1, 35, 4, 33, 95);
$orderedEntities = array_map($orderFunction, $orderAs);
Now your $orderedEntities array will be in the order you specified.