I have a list of Account objects in self.accounts, and I know that only one of them will have a type attribute equal to 'equity'. What is the best (most pythonic) way to get only that object from the list?
Currently I have the following, but I'm wondering if the [0] at the end is superfluous. Is there a more succinct way to do this?
return [account for account in self.accounts if account.type == 'equity'][0]
return next(account for account in self.accounts if account.type == 'equity')
or
return (account for account in self.accounts if account.type == 'equity').next()
"Pythonic" means nothing. There is probably not any more "Succinct" solution than yours, no.
Ignacios solution has the benefit of stopping once it finds the item. Another way of doing it would be:
def get_equity_account(self):
for item in self.accounts:
if item.type == 'equity':
return item
raise ValueError('No equity account found')
Which perhaps is more readable. Readability is Pythonic. :)
Edit: Improved after martineaus suggestions. Made it into a complete method.
It's such a common need in Python but afaik there is no built in way to do it. You could also do:
return next(filter(lambda x: x.type == 'equity', self.accounts))
Related
I'm hoping this is super simple. I just started playing around with Django for fun and have been playing around with making a search engine.
I'm setting a temporary list in a views.py file so I set it like this:
tempsearch_list = Name.objects.filter(
Q(name__iexact='Name Not Found')
)
Later in my code I want to see if it's the same as I originally set so I'm trying to do this:
if tempsearch_list == 'Name Not Found':
This never matches. Even if I put it as the next statement after I set it. What am I doing wrong here. This has to be super simple. I've been trying different things for more time than I'd like to admit.
you filtered the objects as tempsearch_list = Name.objects.filter(Q(name__iexact='Name Not Found')) and later on you when you want to compare if tempsearch_list equals to Name Not Found, you don't need any if statment just use if tempsearch_list.exists().
tempsearch_list.exists() will return True if there was an object named Name Not Found else it returns False
how do I check the query set is still equal to the original way it was set
The queryset(tempsearch_list) won't changed unless you reassign it, and that would be always update in case of adding, editing or removing a Name. but again if you wondering, you can compare it with fresh queryset as if tempsearch_list == Name.objects.filter(Q(name__iexact='Name Not Found'))
Ok, so I appreciate everyone who responded. I think this helped a lot. Here's what I did for now. There's probably a better way to do this but it works
tempsearch_queryset1 = Name.objects.filter(
Q(name__iexact='Name Not Found')
)
tempsearch_queryset2 = Name.objects.filter(
Q(name__iexact='Name Not Found')
)
if set(tempsearch_queryset1) == set(tempsearch_queryset2):
Note. Without the set commands it does not work. This doesn't work:
tempsearch_queryset1 = Name.objects.filter(
Q(name__iexact='Name Not Found')
)
tempsearch_queryset2 = Name.objects.filter(
Q(name__iexact='Name Not Found')
)
if tempsearch_queryset1 == tempsearch_queryset2:
Your problem is compare Queryset and string (Queryset is list of model so you can access model by index and access model field by . like model.name
you can do that like
for tempsearch in tempsearch_list :
if tempsearch.name == "Name Not Found":
You should compare Charfield like name field with string
I want to find out what content_type I'm about in my function but I'm Unable to reach the "got me" print statement no matter how I design my if statement. I also tried to use pprint to get the naming of the content_type but with no effect till now.
def mark_refunded(modeladmin, request, queryset):
queryset.update(status=2)
transactions = queryset.all()
for transaction in queryset.all():
print(transaction)
transaction.sender.acc_usd_balance += float(transaction.amount)
transaction.sender.save()
transaction.receiver.acc_usd_balance -= float(transaction.amount)
transaction.receiver.save()
print(transaction.content_type)
if transaction.content_type == "App | Sell Type A":
print("got me")
It seems that I'm unable to compare the output of print(transaction.content_type) with the if statement, why that?
I would expect that the output is the same value that I ask for at the if statement.
Assuming content_type is a foreign key, you'd need to compare if str(...) == ....
However, the more important issue here is that multiple concurrent requests will eventually absolutely surely corrupt those account balances since you're not managing them in an atomic way.
Long time reader, first time poster, please be gentle.
I've been working on a web app using Flask and SQLAlchemy that allows users to review and comment on MMA fights. I have a list of fights in a SQL table appropriately named "fights" and I'm trying to use dynamic routing to filter through the data. I have a list of all the fights on one route like so:
#app.route('/ufc251')
#login_required
def ufc251():
return render_template('ufc251.html', fights=Fight.query.all())
which helped me make a slick page with all the fights listed, and then made another route for info on individual fights like so:
#app.route('/fight/<int:id>')
#login_required
def fight(id):
id = Fight.query.filter_by(id=id).first_or_404()
return render_template('fight.html')
so far, so good. If I click on a fight from the main page i get sent to a url fightsite/fights/<fight_id>, which is perfect. The problem that I'm having is that I can't for the life of me figure out how to call the data from the row for a single fight. If i change my route to:
#app.route('/fight/<int:id>')
#login_required
def fight(id):
id = Fight.query.filter_by(id=id).first_or_404()
return render_template('fight.html', fight=Fight.query.filter_by(id=id).first())
I get the error
sqlalchemy.exc.ArgumentError: Object <Fight 1> is not legal as a SQL literal value
but if i give id a value (i.e. id=1) it will display the data from the first row in my fights table, so i feel like the problem is in the (id=id) part, but after hours of scouring the internet, I can't seem to find a solution.
Any help would be greatly appreciated. And yes, I've read the other StackOverflow article on this subject, however the answer doesn't seem to apply to this situation.
Thank you in advance!
I figured it out, however I decided I'd leave the question in case anybody else has this issue.
i changed:
#app.route('/fight/<int:id>')
#login_required
def fight(id):
id = Fight.query.filter_by(id=id).first_or_404()
return render_template('fight.html', fight=Fight.query.filter_by(id=id).first())
to:
#app.route('/fight/<int:id>')
#login_required
def fight(id):
id = Fight.query.filter_by(id=id).first_or_404()
return render_template('fight.html', fight=Fight.query.filter_by(id=id.id).first())
because initially it was passing the argument 'fight_1' instead of just '1'. I hope nobody else has to spend this long trying to solve the same problem!
The use of id to hold a Fight confuses things. Then there's the double query when one would suffice.
Consider changing
id = Fight.query.filter_by(id=id).first_or_404()
return render_template('fight.html', fight=Fight.query.filter_by(id=id).first())
to
fight = Fight.query.filter_by(id=id).first_or_404()
return render_template('fight.html', fight=fight)
What is the pythonic way of checking if multiple sub strings are present in the string?
For eg. I'm doing poll and check on the download status through API. The API returns status as "Download complete", "x% Downloaded" or "Installing".
Now, I want to check if 'downloaded' and 'installing' strings are present in status returned by API and if not, raise exception. I have implemented this by very novice way.
if api_object.status == 'Download Complete' :
break
elif 'Downloaded' in api_object.status.split():
time.sleep(interval)
elif 'Downloaded' not in api_object.status.split() or \
'Installing' not in api_object.status.split():
raise Exception("Error")
I would like to know any better approaches for comparison.
Thanks in advance.
A slightly more compact version:
if api_object.status == 'Download Complete':
break
elif 'Downloaded' in api_object.status:
time.sleep(interval)
elif 'Installing' not in api_object.status:
raise Exception("Error")
I don't know if your code is "pythonic" or not, but it is easy to understand and that's what matters most, even if it is a bit longer. Check the following "more pythonic" way:
....
elif all([(x not in status) for x in ['Downloaded', 'Installing'] ]):
....
does it read better?
How about:
status = api_object.status.partition(" ");
try:
action = {
"Downloaded": doA
"Complete": doB
"Installing": doC
}[status[2] or status[0]]
except KeyError:
# unknown status
raise
action();
Using a dict is a common idiom in python to replace a missing switch-statement. doA through doC shall be callables, which you call in the last line. Using the partition(sep) method and the or operator, one can easily pick the correct part of the string: If it exists, one gets the part behind the space, otherwise one gets the whole string.
One should note though, that caching the dictionary might be useful in a performance critical application to safe time for hashing the keys and building the dict.
For case insensitive matching, one would call lower() on the status string (before partition) and put the keys to lower case.
In this particular case, a break is required. One could do this by allowing the callable to return a boolean value, which, if True, triggers a break or a similar approach.
Here is my code :
if 'Download Complete' == api_object.status:
break
if 'Installing' == api_object.status:
continue
if api_object.status and api_object.status.endswith('Downloaded'):
time.sleep(interval)
else:
raise Exception("Error")
I know this question sounds weird, but please, let me explain myself.
I'm using a decorator to make a message persist until the user actually dismisses it (like the behavior of stack overflow's messages). The problem is, as a result of this, the message gets added before the user signs out, and so the message gets displayed right after the user logs out. I'm wondering what the best way to remove the message in the logout view is. I've thought of two ways to do this, and am wondering if anyone can think of a better one.
I'm currently favoring this:
storage = messages.get_messages(request)
storage.used = True
Over this:
storage = messages.get_messages(request)
del storage._loaded_messages[0]
To me the second way seems more explicit, even though it is uglier: my intention is to remove the currently loaded messages and this makes that clear. The first way employs a means by which the messages will be cleared as a side effect ... but at least it doesn't rely upon a dunder variable ... what do you guys think?
I had to use 2 of the solutions proposed above toghether as no one alone was enought:
storage = messages.get_messages(request)
for _ in storage:
pass
if len(storage._loaded_messages) == 1:
del storage._loaded_messages[0]
As far as the accepted solution I can loop over the messages several time
and I see that the messages don't seem to be "consumed"
I like this simpler approach for clearing out the underlying iterator, since I actually wanted to add a new message in the place of a standard Django message.
list(messages.get_messages(request))
For the sake of resolution I'm going to mark the method I went with as "The Answer". Thanks to those who commented.
I went with this:
storage = messages.get_messages(request)
storage.used = True
Because it seemed cleaner, was easier to test, and conformed with the general practices of the rest of the project.
If your logout view always redirects to a "logout page", then you can just change your logout template to hide your messages.
e.g., in template:
{% block extra-header %}
<style type="text/css">
#message-id { display: none; }
</style>
{% endblock %}
It feels a little 'hacky' but I think it's certainly less hacky than your #2.
For me in Django 1.5 and session message storage accepted method dit not the trick.
I needed to use:
storage = messages.get_messages(request)
for _ in storage:
pass
To get rid of messages from storage.
One way of doing the same thing in Django Admin (tested with Django==1.11.6) is to override response_post_*.
def response_post_save_change(self, request, obj):
storage = messages.get_messages(request)
storage._loaded_messages = []
return super().response_post_save_change(request, obj)
And if you want to keep only your custom messages (e.g. added in save_model or any other overridden method) remove the last queued message (which is the one Django ads by default).
def response_post_save_change(self, request, obj):
storage = messages.get_messages(request)
if len(storage._queued_messages) > 1:
del storage._queued_messages[-1]
return super().response_post_save_change(request, obj)