Search not exists in Django - python

I'm really new to django programming, and I'm facing a problem I don't really know how to solve:
I want to get a list of users who have many string attributes, but only the users whom none of it's attributes is equal to a given one.
I have this piece of code
all_users = list(UserProfile.objects.attribute.filter(type=given).exists())
but this code will return me the users who have that attribute, so here's the question: How I can modify this line (or what lines do I need to add) in order to get the list of users without this attribute
Ps: Maybe I didn't explained myself clearly as I don't really know how to specify my problem in english, but, if you don't know what I'm asking I can try again
Thanks all

You can use exclude:
all_users = list(UserProfile.objects.attribute.exclude(type=given).exists())
To quote the docs:
To create such a subset, you refine the initial QuerySet, adding filter conditions. The two most common ways to refine a QuerySet are:
filter(**kwargs)
Returns a new QuerySet containing objects that match the given lookup parameters.
exclude(**kwargs)
Returns a new QuerySet containing objects that do not match the given lookup parameters.

Related

How to annotate a Django QuerySet with a Point?

Lets say I have a model A that has fields lat(FloatField) and lon(FloatField). I want to annotate the QuerySet using a point:
A.objects.annotate(point = Value(Point(F('lat'), F('lon')), output_field=PointField()))
I keep on getting TypeError('Invalid parameters given for Point initialization.')
For some reason Django is not recognizing the fields and instead is passing them as strings (I think).
How do I accomplish this?
Thanks
I personally believe you're better off writing a one time migration to add the point field rather than annotating this, but you are just passing strings ATM. You need to use F
A.objects.annotate(
point=ExpressionWrapper(
Point(F('lat'), F('lon')), output_field=PointField()))
ref: https://docs.djangoproject.com/en/3.0/ref/models/expressions/#using-f-with-annotations

How to delete first N items from queryset in django

I'm looking to delete only the first N results returned from a query in django. Following the django examples here which I found while reading this SO answer, I was able to limit the resulting set using the following code
m = Model.objects.all()[:N]
but attempting to delete it generates the following error
m.delete()
AssertionError: Cannot use 'limit' or 'offset' with delete.
Is there a way to accomplish this in django?
You can not delete through a limit. Most databases do not support this.
You can however accomplish this in two steps, like:
Model.objects.filter(id__in=list(Models.objects.values_list('pk', flat=True)[:N])).delete()
We thus first retrieve the primary keys of the first N elements, and then use this in a .filter(..) part to delete those items in bulk.
You don't have the option directly. So you should delete it by some advanced ways. For example:
not_ideal = Model.objects.all()[N:].values_list("id", flat=True)
Model.objects.exclude(pk__in=list(not_ideal)).delete()
Using this way you are finding your not ideal objects and delete everything except them.
You can use anything beside id. But id is unique and will help you to optimize.
Notice that in the first line I'm getting the items which are from N to the last.(Not from the first to N)
Try this.
Loop through all filtered objects
delatable_objects = Model.objects.all()[:N]
for m in delatable_objects:
m.delete()
You can loop through the queryset and apply delete method to the objects.
for obj in m:
obj.delete()

Idiomatic way to to match against list of munch.munch objects?

I am using the openstack shade library to manage our openstack stacks. One task is to list all stacks owned by a user (for example to then allow for deletion of them).
The shade library call list_stacks() returns a list of munch.Munch objects, and basically I want to identify that stack object that has either an 'id' or 'name' matching some user provided input.
I came up with this code here:
def __find_stack(self, connection, stack_info):
stacks = connection.list_stacks()
for stack in stacks:
if stack_info in stack.values():
return stack
return None
But it feels clumsy, and I am wondering if there is a more idiomatic way to solve this in python? (stack_info is a simple string, either the "name" or "id", in other words: it might match this or that entry within the "dict" values of the munched stack objects)
As my comment suggests, I don't really think there is something to improve.
However, performance-wise, you could use filter to push the loop down to C level which may be beneficial if there are a lot of stacks.
Readability-wise, I don't think that you would gain much.
def __find_stack(self, connection, stack_info):
stacks = connection.list_stacks()
return list(filter(lambda stack: stack_info in stack.values(), stacks))
However this approach is not "short-circuited". Your original code stops when it finds a match, and this one will not, so in theory you will get more than one match if they exist (or an empty list in case there is no match).

How to resolve inconsistent annotation in Django?

I have the following 2 lines of
CategoryContext = Somemodel.objects.values('title__categories__category').distinct()
CategoryContextSum = CategoryContext.annotate(Total_Revenue=Sum('revenue')).order_by('-Total_Revenue')
CategoryContextAvg = CategoryContext.annotate(Average_Revenue=Avg('revenue')).order_by('-Average_Revenue')
The avg query yields a querylist of objects where the category comes first, followed by the revenue. So basically:
<QuerySet [{'title__categories__category':'Category', 'Average_Revenue':Decimal('100'),}, {'title__categories__category':'Category2':'Average_Revenue':Decimal('120'), }]>
The sum query on the other hand yields the revenue followed by the category, so basically:
<QuerySet [{'Total_Revenue':Decimal('100'), 'title__categories__category':'Category'}, {'Total_Revenue':Decimal('120'), 'title__categories__category':'Category2'}]>
Now I have tried flipping the queries around and changing the variable names so far, but I cannot seem to figure out why in the heck these 2 statements are behaving so differently. Does anybody know what could influence annotation behavior in Django?
Edit:
In case you are wondering why I need to understand this: I am passing the queryset to a method that turns it into data for generating a barchart and the first object in the dataset must be the identifier of the value. I could make it so that it inverts the whole process by checking whether this indeed is the case and ivnerting otherwise, but it seems to me that this shouldnt be necessary
This has little or nothing to do with annotate. Dictionaries in Python have no conventional sense of ordering (at least not until Python 3.6), and keys can be ordered differently across different queryset results.
And this constitutes little or not problem since you'll be access required values by key and not serially (as with sequences):
for obj_dct in your_qs:
print(obj_dct[some_key])
If your plot function takes dicts, no need to worry about ordering.

Python Extension Returned Object Etiquette

I am writing a python extension to provide access to Solaris kstat data ( in the same spirit as the shipping perl library Sun::Solaris::Kstat ) and I have a question about conditionally returning a list or a single object. The python use case would look something like:
cpu_stats = cKstats.lookup(module='cpu_stat')
cpu_stat0 = cKstats.lookup('cpu_stat',0,'cpu_stat0')
As it's currently implemented, lookup() returns a list of all kstat objects which match. The first case would result in a list of objects ( as many as there are CPUs ) and the second call specifies a single kstat completely and would return a list containing one kstat.
My question is it poor form to return a single object when there is only one match, and a list when there are many?
Thank you for the thoughtful answer! My python-fu is weak but growing stronger due to folks like you.
"My question is it poor form to return a single object when there is only one match, and a list when there are many?"
It's poor form to return inconsistent types.
Return a consistent type: List of kstat.
Most Pythonistas don't like using type(result) to determine if it's a kstat or a list of kstats.
We'd rather check the length of the list in a simple, consistent way.
Also, if the length depends on a piece of system information, perhaps an API method could provide this metadata.
Look at DB-API PEP for advice and ideas on how to handle query-like things.

Categories