I am writing a basic function that takes three arguments, request, field, and user_id.
The idea is, when you pass through the info, the function returns the result which would be the column (identified by argument "field"), the row (identified by the argument "user_id").
this is my function:
def get_user_field(request, user_id, field):
result = Users.objects.raw("SELECT id, %s FROM blog_users WHERE id = %s", [field, user_id])[0]
#return result.??????
what I do not know how to do is to replace those question marks with what to return the corresponding column. If i try
return result.field
It will pass a string where "field" is. And of course a string cannot be put there.
So how can i achieve a function that works pretty much exactly like this and returns one result?
Thanks!
This can be done with the getattr Python builtin:
return getattr(result, field)
But it would be better to do it entirely differently:
def get_user_field(request, user_id, field):
return User.objects.filter(id=user_id).values_list(field, flat=True)[0]
Or, to allow for the possibility of the user not existing:
def get_user_field(request, user_id, field):
result = User.objects.filter(id=user_id).values_list(field, flat=True)
if result:
return result[0]
else:
return None # or raise an exception or whatever you like
Related
I need to check for empty values of every field of a distinct object. And I'm tiered of typing it out.
In this case. I have the an object called signal with multiple fields, which should not be empty.
if self.is_blank(signal.provider_id):
error_response = "Signal rejected. No signal provider id given."
elif self.is_blank(signal.sequence_id):
error_response = "Signal rejected. No signal sequence id provided."
....
def is_blank (self, string):
"""Checks for None and empty values"""
return True if string and string.strip() else False
Anyhow, what is the fast way in python to check all fields for "emptiness"? How do we loop them?
You may want to use operator.attrgetter:
def is_blank(self, field_names):
for name in field_names:
if getattr(self, name) and getattr(self, name).strip():
return True, name
return False, None
...
is_blank, name = self.is_blank(['provider_id', 'sequence_id', ...])
if is_blank:
print(f'Signal rejected. No signal {name} provided.')
You can also implement is_blank with next:
def is_blank(self, field_names):
return next(
((True, name)
for name in field_names
if getattr(self, name) and getattr(self, name).strip()),
(False, None),
)
This is going to print an error message for the first field that is failing the check. All you need to do is to provide a complete list of the attributes to be checked.
As rostamn mentioned, you can convert your object into a dictionary,
after which you can loop through the (key, values) in a single line with a filter and check the result like so:
any_empty = any([True for x, y in your_obj.__dict__.items() if not y])
Change the condition in the loop to the type of empty check you need.
To loop over all instance properties you use my_instance.__dict__
see this answer for details: Explain __dict__ attribute
I am trying to use find_one operator to fetch results from mongodb:
My document structure is as below:
{"_id":{"$oid":"600e6f592944ccc5790f1a9e"},
"user_id":"user_1",
"device_access":[
{"device_id":"DT002","access_type":"r"},
{"device_id":"DT007","access_type":"rm"},
{"device_id":"DT009","access_type":"rt"},
]
}
I have created my filter query as below
filter={'user_id': 'user_1','device_access.device_id': 'DT002'},
{'device_access': {'$elemMatch': {'device_id': 'DT002'}}}
But Pymongo returns None, when used in a function as below:
#Model.py
#this function in turn calls the pymongo find_one function
def test(self):
doc = self.__find(filter)
print(doc)
def __find(self, key):
device_document = self._db.get_single_data(COLLECTION_NAME, key)
return device_document
#Database.py
def get_single_data(self, collection, key):
db_collection = self._db[collection]
document = db_collection.find_one(key)
return document
.
Could you let me know what might be wrong here ?
Your brackets are incorrect. Try:
filter = {'user_id': 'user_1','device_access.device_id': 'DT002', 'device_access': {'$elemMatch': {'device_id': 'DT002'}}}
Also filter is a built-in function in python so you're better off using a different variable name.
Finally figured out on why the above query is returning None
The **filter** variable, as you could see, is ,comma separated. This is considered by python internally as *Tuple of Dictionary values* and when the filter var is passed on over another function it considers as a separate argument, though it never throws any exception in this case.
In order to overcome this, I now added *args to all the function calls that is being passed over.
#Model.py
#this function in turn calls the pymongo find_one function
def test(self):
doc = self.__find(filter)
print(doc)
def __find(self, key, *args):
device_document = self._db.get_single_data(COLLECTION_NAME, key, *args)
return device_document
#Database.py
def get_single_data(self, collection, key, *args):
db_collection = self._db[collection]
document = db_collection.find_one(key, *args)
return document
I am querying (via sqlalchemy) my_table with a conditional on a column and then retrieve distinct values in another column. Quite simply
selection_1 = session.query(func.distinct(my_table.col2)).\
filter(my_table.col1 == value1)
I need to do this repeatedly to get distinct values from different columns from my_table.
selection_2 = session.query(func.distinct(my_table.col3)).\
filter(my_table.col1 == value1).\
filter(my_table.col2 == value2)
selection_3 = session.query(func.distinct(my_table.col4)).\
filter(my_table.col1 == value1).\
filter(my_table.col2 == value2).\
filter(my_table.col3 == value3)
The above code works, but as I need to have 6 successive calls it's getting a bit out of hand. I have created a class to handle the method chaining:
class QueryProcessor:
def add_filter(self, my_table_col, value):
filter(my_table_col == value)
return self
def set_distinct_col(self, my_other_table_col):
self.my_other_table_col = my_other_table_col
return session.query(func.distinct(self.my_other_table_col))
Ideally I'd be able to use the class like
selection_1 = QueryProcessor().set_distinct_col(my_table.col2).add_filter(my_table.col1, value1)
selection_2 = selection_1.set_distinct_col(my_table.col3).add_filter(my_table.col2, value2)
selection_3 = selection_2.set_distinct_col(my_table.col4).add_filter(my_table.col3, value3)
but when I run
selection_1 = QueryProcessor().set_distinct_col(my_table.col2).add_filter(my_table.col1, value1)
I get the following error:
Traceback (most recent call last):
File " ... "
exec(code_obj, self.user_global_ns, self.user_ns)
File "<ipython-input-20-789b26eccbc5>", line 10, in <module>
selection_1 = QueryProcessor().set_distinct_col(my_table.col2).add_filter(my_table.col1, value1)
AttributeError: 'Query' object has no attribute 'add_filter'
Any help will be much welcomed.
You don't really need a special class for this. Your existing code
selection_2 = session.query(func.distinct(my_table.col3)).\
filter(my_table.col1 == value1).\
filter(my_table.col2 == value2)
works because filter is returning a new query based on the original query, but with an additional filter added to it. You can just iterate over the columns and their corresponding values, replacing each old query with its successor.
selection2 = session.query(func.distinct(my_table.col3))
for col, val in zip([my_table.col1, my_table.col2], [value1, value2]):
selection2 = selection2.filter(col == val)
selection_3 = session.query(func.distinct(my_table.col4))
for col, val in zip([mytable.col1, mytable.col2, mytable.col3],
[value1, value2, value3]):
selection_3 = selection_3.filter(col == val)
That said, the problem with your code is that add_filter doesn't actually call the query's filter method, or update the wrapped query.
class QueryProcessor:
def set_distinct_col(self, my_other_table_col):
self.query = session.query(func.distinct(self.my_other_table_col))
return self
def add_filter(self, my_table_col, value):
self.query = self.query.filter(my_table_col == value)
return self
This poses a problem, though: set_distinct_col creates a new query, so it doesn't really make sense in the following
selection_1 = QueryProcessor().set_distinct_col(my_table.col2).add_filter(my_table.col1, value1)
selection_2 = selection_1.set_distinct_col(my_table.col3).add_filter(my_table.col2, value2)
selection_3 = selection_2.set_distinct_col(my_table.col4).add_filter(my_table.col3, value3)
to call set_distinct_col on an existing instance. It can return either a new query or the existing one, but not both (at least, not if you want to do chaining).
Also, note that selection_1 itself is not the query, but selection_1.query.
For your add_filter() function to work as intended, you need your set_distinct_col() function to return a reference to itself (an instance of QueryProcessor).
session.query() returns a Query object which doesn't have an add_filter() method.
Query could have an add_filter method if you did something like Query.add_filter = add_filter, but that's a bad practice because it modifies the Query class, so I don't recommend doing it.
What you're doing is a better option. In order to have access to the query you create with the set_distinct_col() method, you need to store it as an instance variable.
Below, I have done this by storing the query in the instance variable query withself.query = session.query(func.distinct(self.my_other_table_col))
Then, I changed the add_filter() method to return itself to allow for chaining more add_filter() methods.
class QueryProcessor:
def add_filter(self, my_table_col, value):
self.query = self.query.filter(my_table_col == value)
return self
def set_distinct_col(self, my_other_table_col):
self.my_other_table_col = my_other_table_col
self.query = session.query(func.distinct(self.my_other_table_col))
return self
You should also know that you can use multiple filter conditions at a time, so you don't actually need to chain multiple filters together.
session.query(db.users).filter(or_(db.users.name=='Ryan', db.users.country=='England'))
or
session.query(db.users).filter((db.users.name=='Ryan') | (db.users.country=='England'))
Difference between filter and filter_by in SQLAlchemy
P.S. This code has not been tested
Writing a dry function that returns either previous or next instances of a given instance.
This function return previous instances:
def previous(instance):
try:
return Picture.objects.filter(id__lt=instance.id).first()
except Picture.DoesNotExist:
return instance
I want to create an abstracted function which returns either the previous or the next instance using an additional gt_or_lt argument. The problem lies in interpolating that argument into the filter(id__gt_or_lt).
def seek_instance(gt_or_lt, instance):
try:
return Picture.objects.filter(id__gt_or_lt=instance.id).first()
except Picture.DoesNotExist:
return instance
I've tried:
return Picture.objects.filter(id__gt_or_lt = instance.id).first()
seek_instance("gt", instance)
return Picture.objects.filter(id__f"{gt_or_lt}" = instance.id).first()
seek_instance("gt", instance)
return Picture.objects.filter(f"{gt_or_lt}" = instance.id).first()
return Picture.objects.filter(gt_or_lt = instance.id).first()
seek("id__gt", instance)
All fail with their respective errors.
Use a dictionary with kwargs expansion.
return Picture.objects.filter(**{f"id__{gt_or_lt}": instance.id})
You can use dictionary expansion, like #DanielRoseman suggests. But that will still not per se render the previous, or next item. If for example the model has an ordering option [Django-doc], then it is possible that the order is different than on the id. Furthermore, for the previous one, you will need to reverse the ordering.
Furthermore depending on the situation, you might want to prevent that seek_instance can be given a different lookup, like 'in' for example.
We can thus use an if … elif … else here to branch on the item we wish to retrieve, and raise a ValueError in case you use some other lookup:
def seek_instance(lt_or_gt, instance):
try:
if lt_or_gt == 'lt':
return Picture.objects.filter(pk__lt=instance.pk).order_by('-pk').first()
elif lt_or_gt == 'gt':
return Picture.objects.filter(pk__gt=instance.pk).order_by('pk').first()
else:
raise ValueError("Should be 'lt' or 'gt'")
except Picture.DoesNotExist:
return instance
I have a recursive script that's scraping a JSON file for cars. At each recursive level, it gets a new variable added, and passes that (along with the other values) on to the recursive call, each time getting more and more detailed in the information. I tried to use locals() to dynamically assign a variable, but it remains None even after the call (I recall seeing that sometimes locals() is read only).
I tried using eval() as well, and it gives me the same issue (I know eval is not ideal). I'd ideally like to avoid using a dictionary, because that would require me to load it with values first, which seems like it has some unnecessary steps, but I'm open to anything at this point.
Example:
scraper(manufacturer='Honda') would scrape a JSON file of models, set model='Accord' and then recursively call
scraper(manufacturer='Honda, model='Accord') which scrapes a file of years, set's year=2014 and recursively calls
scraper(manufacturer='Honda', model='Accord', year='2014') which is the base case
def scraper(self, manufacturers, model=None, year=None):
if year:
scrapeurl = '%s&manufacturer=%s&model=%s&year=%s' % (url, manufacturer, model, year)
return someFinalFunction()
elif model:
scrapeurl = '%s&manufacturer=%s&model=%s' % (url, manufacturer, model)
elif manufacturer:
scrapeurl = '%s&manufacturer=%s' % (url, manufacturer)
j = getJSONFromUrl(scrapeurl)
key, values = j.popitems()
for value in values:
locals()[key] = value
return self.scraper(manufacturer, model, year, color)
I'd appreciate any input on how to handle this, I know Python always seems to have some clever ways of doing things, and I'm always learning more about it, so thank you in advance! I'm using Python3 in this example too, if that changes anything
locals()['key'] = value should be locals()[key] = value
Better yet, use **kwargs:
def scraper(self, manufacturer, model=None, year=None):
kwargs = dict(manufacturer=manufacturer, model=model, year=year)
if year:
scrapeurl = '%s&manufacturer=%s&model=%s&year=%s' % (url, manufacturer, model, year)
return someFinalFunction()
elif model:
scrapeurl = '%s&manufacturer=%s&model=%s' % (url, manufacturer, model)
elif manufacturer:
scrapeurl = '%s&manufacturer=%s' % (url, manufacturer)
j = getJSONFromUrl(scrapeurl)
key, values = j.popitems()
for value in values:
kwargs[key] = value
return self.scraper(**kwargs)
It's not entirely clear what you're trying to do, but perhaps this will help:
def scraper(self, **kwargs):
if kwargs.get('year') is not None:
scrapeurl = '{0}&manufacturer={manufacturer}&model={model}&year={year}'
return someFinalFunction() # not sure why this takes no arguments
elif kwargs.get('model') is not None:
scrapeurl = '{0}&manufacturer={manufacturer}&model={model}'
elif kwargs.get('manufacturer') is not None:
scrapeurl = '{0}&manufacturer={manufacturer}'
else:
raise KeyError
j = getJSONFromUrl(scrapeurl.format(url, **kwargs))
key, values = j.popitems()
for value in values:
kwargs[key] = value
return self.scraper(**kwargs)
This uses Python's built-in functionality to treat arbitrary keyword arguments as a dictionary, along with more modern str.format string formatting, to dynamically handle the arguments you're looking for. The only difference is that you now need to call it:
instance.scraper(manufacturer='...')
rather than just
instance.scraper('...')
An example of the string formatting, mixing positional and keyword arguments:
>>> '{0}&manufacturer={manufacturer}'.format('foo', **{'manufacturer': 'bar'})
'foo&manufacturer=bar'