Get the last element of the list in Django - sql

I have a model:
class List:
data = ...
previous = models.ForeignKey('List', related_name='r1')
obj = models.ForeignKey('Obj', related_name='nodes')
This is one direction list containing reference to some obj of Obj class. I can reverse relation and get some list's all elements refering to obj by:
obj.nodes
But how Can I get the very last node? Without using raw sql, genering as little SQL queries by django as can.

obj.nodes is a RelatedManager, not a list. As with any manager, you can get the last queried element by
obj.nodes.all().reverse()[0]
This makes sense anyway only if there is any default order defined on the Node's Meta class, because otherwise the semantic of 'reverse' don't make any sense. If you don't have any specified order, set it explicitly:
obj.nodes.order_by('-pk')[0]

len(obj.nodes)-1
should give you the index of the last element (counting from 0) of your list
so something like
obj.nodes[len(obj.nodes)-1]
should give the last element of the list
i'm not sure it's good for your case, just give it a try :)

I see this question is quite old, but in newer versions of Django there are first() and last() methods on querysets now.

Well, you just can use [-1] index and it will return last element from the list. Maybe this question are close to yours:
Getting the last element of a list in Python

for further reading, Django does not support negative indexing and using something like
obj.nodes.all()[-1]
will raise an error.
in newer versions of Django you can use last() function on queryset to get the last item of your list.
obj.nodes.last()
another approach is to use len() function to get the index of last item of a list
obj.nodes[len(obj.nodes)-1]

Related

How can I find element by non-unique resousre-id?

I test an application which use non-unique resourse-id for elements.
Is there any way to find such elements by xpath like
//*[#resourse-id='non-unique-id'][2]
I mean the second element with same resourse-id.
I'd recommend avoiding xpath in mobile automation since this is the most time-consuming strategy to find elements.
If you don't have any other anchors for your elements but you confident in its order, you can stick to the following approach: Appium driver can return a list of elements with the same locator, in case of Page Object model you can either do this way:
#AndroidFindBy(uiAutomator = "resourceIdMatches(\".*whatever\")")
private List<MobileElement> elements;
so, once your page is initialized, you can access an element by index:
elements.get(1).click();
or, in case of manual managenemt, you can do this way:
List<MobileElement> elements = driver.findElements(MobileBy.AndroidUIAutomator("resoureceIdMatches(\".*whatever\")"));
elements.get(3).click();
Hope this helps.
As far as my understanding goes, you need to select the second element with the path as mentioned: //*[#resourse-id='non-unique-id']
To do that, you need to first grab all the elements with the same non-unique resource ID and then get() them. So, your code should be:
driver.findElements(By.xpath("//*[#resourse-id='non-unique-id']")).get(1).click();
The index for any list starts at 0. So, the second element can be accessed through the value of 1.
Hope this helps.
Try following approach:
(//*[#resourse-id='non-unique-id'])[2]
HTML with non-unique ids is not a valid HTML document.
So, for the sake of future testability, ask the developers to fix the ids.

Rails 5.2 ActiveRecord query returns array instead of ActiveRecord::AssociationRelation

I see that performing a .first() or .last() query on an ActiveRecord query returns an array instead of an ActiveRecord::AssociationRelation. This prevents me from appending an .order() clause as that is not an array method.
Stepping back to the goal for a minute, I want to pull the latest five ("live", ie. active) comments related to a post and this is the code that fails:
#post.comments.where(status: "live").last(5).order(id: :desc)
The error is
undefined method `order' for #<Array:0x00000011b096c0>
If I remove the .last() clause, or the .order() clause I get a valid result but obviously not the result set that I am angling for.
What's the best way to get the last five live comments in reverse chronological order? More importantly, perhaps, where is the best documentation / tutorial on this syntax? I find the official guide too brief.
Talking about documentation, I could recommend Rails API. It has a lot of detailed descriptions for each interface method.
What about your question, you could use limit method instead of first or last:
#post.comments.where(status: "live").limit(5).order(id: :desc)
It does not affect the type of result (it stays ActiveRecord::AssociationRelation). Hence, if no result is found, this relation with to_a method will be converted to an empty array. This is different from the behavior of first and last methods which return nil in case of no result.
How about something like:
#post.comments.where(status: 'live').order(created_at: :desc).take(5)
I just plugged in created_at. Maybe you'll want updated_at instead.

Build XPath using wildcard for changing strings

I am trying to build an XPath for a property that is constantly changing. The number prefix is bound to change sometimes.
Original:
//*[#id="MainContent_DXEditor3_I"]
which I can query using
$x('//*[#id="MainContent_DXEditor3_I"]
Intended use: I would like to build the string to handle any number in the sub-string. Example: if the property changes to 'MainContent_DXEditor33_I' or 'MainContent_DXEditor8_IXYZ' - I still want to be able to find the element without having to rebuild
You can try to relax the predicate by using starts-with() :
//*[#starts-with(#id, "MainContent_DXEditor")]
You should try to identify a unique parent of the element or save xpath as a string that contains a variable.
These are the 2 possible solutions.
A general selector will return multiple elements, if you identify a unique parent then you are closer and after that you can select any first, second.. last if you have a list.

String Template: is it possible to get the n-th element of a Java List in the template?

In String Template one can easily get an element of a Java Map within the template.
Is it possible to get the n-th element of an array in a similar way?
According to the String Template Cheat Sheet you can easily get the first or second element:
You can combine operations to say things like first(rest(names)) to get second element.
but it doesn't seem possible to get the n-th element easily. I usually transform my list into a map with list indexes as keys and do something like
map.("25")
Is there some easier/more straightforward way?
Sorry, there is no mechanism to get a[i].
There is no easy way getting n-th element of the list.
In my opinion this indicates that your view and business logic are not separated enough: knowledge of what magic number 25 means is spread in both tiers.
One possible solution might be converting list of values to object which provides meaning to the elements. For example, lets say list of String represents address lines, in which case instead of map.("3") you would write address.street.

In django, how do I sort a model on a field and then get the last item?

Specifically, I have a model that has a field like this
pub_date = models.DateField("date published")
I want to be able to easily grab the object with the most recent pub_date. What is the easiest/best way to do this?
Would something like the following do what I want?
Edition.objects.order_by('pub_date')[:-1]
obj = Edition.objects.latest('pub_date')
You can also simplify things by putting get_latest_by in the model's Meta, then you'll be able to do
obj = Edition.objects.latest()
See the docs for more info. You'll probably also want to set the ordering Meta option.
Harley's answer is the way to go for the case where you want the latest according to some ordering criteria for particular Models, as you do, but the general solution is to reverse the ordering and retrieve the first item:
Edition.objects.order_by('-pub_date')[0]
Note:
Normal python lists accept negative indexes, which signify an offset from the end of the list, rather than the beginning like a positive number. However, QuerySet objects will raise AssertionError: Negative indexing is not supported. if you use a negative index, which is why you have to do what insin said: reverse the ordering and grab the 0th element.
Be careful of using
Edition.objects.order_by('-pub_date')[0]
as you might be indexing an empty QuerySet. I'm not sure what the correct Pythonic approach is, but the simplest would be to wrap it in an if/else or try/catch:
try:
last = Edition.objects.order_by('-pub_date')[0]
except IndexError:
# Didn't find anything...
But, as #Harley said, when you're ordering by date, latest() is the djangonic way to do it.
This has already been answered, but for more reference, this is what Django Book has to say about Slicing Data on QuerySets:
Note that negative slicing is not supported:
>>> Publisher.objects.order_by('name')[-1]
Traceback (most recent call last):
...
AssertionError: Negative indexing is not supported.
This is easy to get around, though. Just change the order_by()
statement, like this:
>>> Publisher.objects.order_by('-name')[0]
Refer the link for more such details. Hope that helps!