How to order by two fields in Odoo 8? - python

I have a recordset of partners. Now I want to order this recordset by two attributes. One of this attributes is a simple Char, but the other one is a Many2one, which is a problem.
Example (suppose variable partners is the recordset):
This works: partners.sorted(key=lambda r: r.name) (with Char no problem).
This does not work: partners.sorted(key=lambda r: r.country_id) (with Many2one, you must add an attribute of the other model).
This works: partners.sorted(key=lambda r: r.country_id.id) (now we have indicated an attribute of res.country, the recordset is ordered rightly).
The problem is: I need to order by two fields, as I wrote above. For that it seems that I have to use itemgetter, but:
This does not work: partners.sorted(key=itemgetter('name', 'country_id')) (country_id is ignored, as when I tried to order by only this one above).
This gives an error: partners.sorted(key=itemgetter('name', 'country_id.id')) (the error message is that country_id.id is not a field of res.partner).
This seems to work: partners.sorted(key=itemgetter('name', 'phone')) (because both fields are Char).
I also tried to link two sorted in a row, this way:
partners.sorted(key=lambda r: r.name).sorted(key=lambda r: r.country_id.id)
But it is not working neither, because the second sorted function messes up the result of the first one.
Can anyone help me with this, please?

What about
partners.sorted(key=lambda p: (p.name, p.country_id.id))

I think you need to sort using country name.
Using your last code line and calling sort one time it will solve the problem:
partners.sorted(key=lambda r: (r.name, r.country_id.name))

Related

Python / Pyspark Indexing and Slicing issue on Databricks

I'm not entirely sure if I need to index or slice to retrieve elements from an output in Python.
For example, the variable "Ancestor" produces the following output.
Out[30]: {'ancestorPath': '/mnt/lake/RAW/Internal/origination/dbo/xpd_opportunitystatushistory/1/Year=2022/Month=11/Day=29/Time=05-11',
'dfConfig': '{"sparkConfig":{"header":"true"}}',
'fileFormat': 'SQL'}
The element "xpd_opportunitystatushistory" is a table and I would like to retrieve "xpd_opportunitystatushistory" from the output.
I was thinking of something like:
table = Ancestor[:6]
But it fails.
Any thoughts?
I have been working on this while waiting for help.
the following
Ancestor['ancestorPath']
Give me
Out[17]: '/mnt/lake/RAW/Internal/origination/dbo/xpd_opportunitystatushistory/1/Year=2022/Month=11/Day=29/Time=05-11'
If someone could help with the remaining code to pull out 'xpd_opportunitystatushistory' that would be most helpful
ta
Ancestor is a dictionary (key value pairs) and hence has to be accessed using a key which in this case is ancestorPath.
I have assigned the value similar to yours and was able to retrieve ancesterPath as you have figured out.
Now to get the xpd_opportunitystatushistory you can use the following code. Since the value of Ancestor['ancestorPath'] is a string, you can split and then extract the required value from the resulting array:
req_array = Ancestor['ancestorPath'].split("/")
print(req_array)
print(req_array[7])
If you want to retrieve complete path until xpd_opportunitystatushistory, then you can use the following instead:
req_array = Ancestor['ancestorPath'].split("/")
print(req_array)
print('/'.join(req_array[:8]))

Why is "numpy.int32" not able to be printed here? (Using geopandas + python 3.9.5)

Here is the relevant code:
import geopandas as gpd
#A shape file (.shp) is imported here, contents do not matter, since the "size()" function gets the size of the contents
shapefile = 'Data/Code_Specific/ne_50m_admin_1_states_provinces/ne_50m_admin_1_states_provinces.shp'
gdf = gpd.read_file(shapefile)[['admin', 'adm0_a3', 'postal', 'geometry']]
#size
#Return an int representing the number of elements in this object.
print(gdf.size())
I am getting an error for the last line of code,
TypeError: 'numpy.int32' object is not callable
The main purpose for this is that I am trying to integrade gdf.size() into a for loop:
for index in range(gdf.size()):
print("test", index)
#if Austrailia, remove
if gdf.get('adm0_a3')[index] == "AUS":
gdf = gdf.drop(gdf.index[index])
I have absolutely no clue what to do here, this is my first post on this site ever. Hope I don't get guilded with a badge of honor for how stupid or simple this is, I'm stumped.
gpd.read_file will return either a GeoDataFrame or a DataFrame object, both of which have the attribute size which returns an integer. The attribute is simply accessed with gdf.size and by adding brackets next to it, you get your error.
size is the wrong attribute to use, as for a table it returns the number of rows times the number of columns. At first glance the following should work
for index in gdf.index:
...
but you're modifying the length of an iterable while iterating from it. This can throw everything out of sync and cause a KeyError if you drop an index and before you try to access it. Since all you want to do is filter some rows, simply use
gdf = gdf[gdf['adm0_a3'] != 'AUS']
I think the function you are looking for is,
gdf.shape[0]
or
len(gdf.index)
I think the first option is more readable but the second one is faster.

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()

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.

how to pass list values through url

I have written a python script where I have collected some values in a list. I need to pass on these values to an URL in a loop where in each time a different value is picked up.
i..e, I want to achieve this:
http://www.abc.com/xyz/pqr/symbol=something[i].
Here "something" is a list and I have verified that it contains the proper values. However when I pass the values to the URL, I am not getting the desired results. I have tried with URL encoding for something[i] but still it is not giving me proper results. Can someone help me?
EDIT: My example script at the moment is:
import json
script=["Linux","Windows"]
for i in xrange(len(script)):
site="abc.com/pqr/xyz/symbol=json.dumps(script[i])";
print site
I think the problem is your approach to formatting. You don't really need json if you have a list already and are just trying to modify a URL...
import json
script=["Linux","Windows"]
something = ["first","second"]
for i,j in zip(script,something):
site="http:abc.com/pqr/xyz/symbol={0}".format(j)
print i, site
This uses the .format() operator, which "sends" the values in parentheses into the string at the positions marked with {}. You could just add the strings together if it is always at the end. You could also use the older % operator instead. It does pretty much the same thing, but in this case it inserts the string j at the position marked by %s:
site="http:abc.com/pqr/xyz/symbol=%s" % (j)
Side note: I slightly prefer % because once you learn it, it can also be used in other programming languages, but .format() has more options and is the recommended way to do it since python 2.6.
Output:
Linux http:abc.com/pqr/xyz/symbol=first
Windows http:abc.com/pqr/xyz/symbol=second
You should be able to get close to what you want from this starting point, but if this is nothing like your desired output, then you need to clarify in your question...

Categories