Convert Django Queryset to list or dict - python

From my views.py I doing this query:
var_query = DB.objects.filter(Q(user_id=str(request.user.id)) & Q(router_name='router1' )).values('router_type', 'router_ip')
Working because I get this result:
{'router1': set(['[{"router_type": "CISCO", "router_ip": "192.168.1.1"}]'])}
the type of var_query is: <class 'django.db.models.query.QuerySet'>
When I convert this with list()
converted = list(var_query)
and this error:
AttributeError: 'set' object has no attribute 'iteritems'
becasue when a convert this queryset to list is inserted this: set(['
How to convert to real list or dict so I can work with my key or value?

It's not really clear what your final aim is. But it seems like you are overcomplicating things unnecessarily. I would suggest simplifying your approach and just filter the queryset normally (note, it looks like these Q objects are also unnecessary here, you can just pass the args in directly).
var_query = DB.objects.filter(
Q(user_id=str(request.user.id)) & Q(router_name='router1')
)
The result will be a queryset object that implements the iterator protocol and can be iterated over normally like a list or list-like object. Then to work with the fields in the data that you seem to be interested in, you can just do something like:
var_query = DB.objects.filter(
Q(user_id=str(request.user.id)) & Q(router_name='router1')
)
for obj in var_query:
router_type = obj.router_type
router_ip = obj.router_ip
# ... do other stuff with your data.
You don't need to bother using values unless you really have a proper use case for it.
If you can supply more context we can refine a more accurate solution.

Related

Django interpreting dict values ambiguously [duplicate]

In a Django view you can access the request.GET['variablename'], so in your view you can do something like this:
myvar = request.GET['myvar']
The actual request.GET['myvar'] object type is:
<class 'django.http.QueryDict'>
Now, if you want to pass multiple variables with the same parameter name, i.e:
http://example.com/blah/?myvar=123&myvar=567
You would like a python list returned for the parameter myvar, then do something like this:
for var in request.GET['myvar']:
print(var)
However, when you try that you only get the last value passed in the url i.e in the example above you will get 567, and the result in the shell will be:
5
6
7
However, when you do a print of request.GET it seems like it has a list i.e:
<QueryDict: {u'myvar': [u'123', u'567']}>
Ok Update:
It's designed to return the last value, my use case is i need a list.
from django docs:
QueryDict.getitem(key)
Returns
the value for the given key. If the
key has more than one value,
getitem() returns the last value. Raises
django.utils.datastructures.MultiValueDictKeyError
if the key does not exist. (This is a
subclass of Python's standard
KeyError, so you can stick to catching
KeyError
QueryDict.getlist(key) Returns the
data with the requested key, as a
Python list. Returns an empty list if
the key doesn't exist. It's guaranteed
to return a list of some sort.
Update:
If anyone knows why django dev's have done this please let me know, seems counter-intuitive to show a list and it does not behave like one. Not very pythonic!
You want the getlist() function of the GET object:
request.GET.getlist('myvar')
Another solution is creating a copy of the request object... Normally, you can not iterate through a request.GET or request.POST object, but you can do such operations on the copy:
res_set = request.GET.copy()
for item in res_set['myvar']:
item
...
When creating a query string from a QueryDict object that contains multiple values for the same parameter (such as a set of checkboxes) use the urlencode() method:
For example, I needed to obtain the incoming query request, remove a parameter and return the updated query string to the resulting page.
# Obtain a mutable copy of the original string
original_query = request.GET.copy()
# remove an undesired parameter
if 'page' in original_query:
del original_query['page']
Now if the original query has multiple values for the same parameter like this:
{...'track_id': ['1', '2'],...} you will lose the first element in the query string when using code like:
new_query = urllib.parse.urlencode(original_query)
results in...
...&track_id=2&...
However, one can use the urlencode method of the QueryDict class in order to properly include multiple values:
new_query = original_query.urlencode()
which produces...
...&track_id=1&track_id=2&...

Python requests.json() object as dictionary does not recognize its own keys with hasattr() or value in object.keys() call

Summary: dictionary/json object indicates it does not have a given key (using either a hasattr call or a value in object.keys boolean test even though that key shows up in an object.keys() call. So how can I access the value for that key?
Longer version: I am quite puzzled trying to parse some json coming back from an API. When I try to determine whether the json object, which is showing up as a dictionary, has a given key, the code returns false for the key even when it shows the key is there for the object.
Here is how I am retrieving the json:
r = requests.get(url, headers = {'User-Agent':UA})
try:
print(r.json())
jsonobject = r.json()
print("class of jsonobject is %s"%jsonobject.__class__.__name__)
print("here are dictionary keys %s"%jsonobject.keys())
if hasattr(jsonobject, 'laps') and jsonobject['laps'] is not None:
...
else:
print("no laps object")
if hasattr(jsonobject, 'points') and jsonobject['points'] is not None:
...
The reason I am doing this is that often I am getting encoding errors from the field nested within the 'laps' array or the 'points' array so that I cannot insert the json data into a MongoDB database. I would like to delete these fields from the json object since they don't contain useful information anyway.
The problem is that the json object is always returning false for hasattr(jsonobject, 'laps') and hasattr(jsonobject,'points'. It returned false even in the case of a record where I then printed out the keys and they showed:
here are dictionary keys dict_keys(['is_peptalk_allowed', 'show_workout', 'hydration', 'records', 'include_in_stats', 'expand', 'pb_count', 'start_time', 'calories', 'altitude_max', 'hashtags', 'laps', 'pictures', 'duration', 'playlist'\
, 'sport', 'points', 'show_map', 'local_start_time', 'speed_avg', 'tagged_users', 'distance', 'altitude_min', 'is_live', 'author', 'feed_id', 'speed_max', 'id'])
So I thought perhaps the dict was behaving strangely with hasattr, and rewrote the code as:
if 'laps' in jsonobject.keys() and jsonobject['laps'] is not None:
but that also returns false even thoug hit again prints the same array of keys that does include 'laps'.
hasattr() is entirely the wrong tool to use. It tests for attributes, but dictionary keys are not attributes.
To test for keys, use the in test directly against the dictionary:
if 'lap' in jsonobject:
Calling jsonobject.keys() is redundant and creates a new dictionary view object.
It'll be true for your dictionary, but that's not the only thing you are testing for. Your test is:
if 'lap' in jsonobject and jsonobject['lap'] is not None:
That'll fail if 'lap' is a key but the value in the dictionary is None.
The above test can be more simply and compactly stated as:
if jsonobject.get('lap') is not None:
If None is a valid value, don't test for it; stick to just 'lap' in jsonobject.

Getting all field names from a protocol buffer?

I want to get all the field names of a proto into a list. Is there a way to do this? I looked in the documentation and there doesn't seem to be anything for this.
Every proto class possess a DESCRIPTOR class variable that can be used to inspect the fields of corresponding protobuf messages.
Have a look at the documentation of the Descriptor and FieldDescriptor classes for more details.
Here is a simple example to get the FieldDescriptors of all the fields in message into a list:
res = message.DESCRIPTOR.fields
To get the names of the fields "exactly as they appear in the .proto file":
res = [field.name for field in message.DESCRIPTOR.fields]
or (from the comments):
res = message.DESCRIPTOR.fields_by_name.keys()
To get the full names of the fields "including containing scope":
res = [field.full_name for field in message.DESCRIPTOR.fields]
qfiard's answer didn't work for me. Calling message.DESCRIPTOR.fields.keys() produced AttributeError: 'list' object has no attribute 'keys'.
Not sure why it wouldn't work. Maybe it has something to do with how the message was defined/compiled.
The workaround was to do a list composition of the individual field objects and get the name property for each. This gave me a list of strings of all fields in this list.
res = [f.name for f in message.DESCRIPTOR.fields]
Note that this does not get you the field names within those fields recursively.
You can easily get a list of fields as follows
message_fields = [field for field in message.DESCRIPTOR.fields_by_name]
I bumped to Python 3.9 and some of these solutions broke, so I found a solution using the public interface of a message object, not using the DESCRIPTOR attribute.
fields = [desc.name for desc, val in message.ListFields()]
Note however, this solution will only fetch the fields which have been set.
Doc is here: https://googleapis.dev/python/protobuf/latest/google/protobuf/message.html#google.protobuf.message.Message.ListFields

Convert web.py iterbetter to dictionary or list

I'm trying to get the some data from a MySQL table (ipb_members) using web.py's database.select. This is the code I'm using: members = db.select("ipb_members", where="name=\"asdfquerty\"")
it returns an instance of iterbetter. What I'm trying to figure out is how to convert that to a dictionary or a list. I saw this, which recommends using list(), but that just puts everything in the first index. I've also tried dict(), but that didn't work either. What am I doing wrong?
This should work:
members = db.select("ipb_members", where="name=\"asdfquerty\"")
for member in members #members is IterBetter
print member.posts #member is Storage
Note that you dont have to call .list() on the result of db.select if you need to iterate over it only once.
Have you tried dict(members)?
iterBetter is not very convenient as it can only iterate once, here is code convert iterBetter to list:
list_conv_from_db = []
for menber in menbers:
temp = dict()
for key in menber:
temp[key]=menber[key]
list_conv_from_db.append(temp)
then you get list_conv_from_db you can do everything you want!

filter() method in python django

out_links = Link.objects.filter(iweb=iweb_id).order_by('-pub_date')
for link in out_links:
comments = LinkComment.objects.filter(link=link.id)
Filter method creates the list of object, so out_links is a list, right ?
Next, after for loop, I filtering again to find objects in LinkComments class by link id.
The question arises though, shoud I refer to link as it would be the object or rather a list?
I'm not shure about it as long it is django views? link.id or link['id']? My python says [ ], but django does not work.
The out_links is a queryset and in the for loop you can reach all LinkComments by:
for link in out_links:
comments = link.linkcomment_set.all()
Filter creates a QuerySet, as explained in the documentation: https://docs.djangoproject.com/en/dev/ref/models/querysets/#methods-that-return-new-querysets
If you subscript a QuerySet, like comments[n], you get the nth member (just as you would with a list). Where you have an order_by, that is in the order specified by that clause. You cannot query by id using the subscript notation.
When you iterate over the QuerySet, you get the members of the queryset, which are python model objects, and you may treat them just as you do anywhere else in your code.
Filter method creates the list of object, so out_links is a list,
right ?
Wrong. It creates QuerySet object, which also happens to be an iterable.

Categories

Resources