I am trying to build a query that takes form data and removes any None or " " submissions but I'm not sure how to approach the logic. Here is the code;
#app.route('/filterassets', methods=['GET', 'POST'])
def searchassets():
form = FilterAssetsForm()
results = None
if request.method == "POST":
if form.validate_on_submit():
try:
horsepower = form.horsepower_search.data
voltage = form.voltage_search.data
rpm = form.rpm_search.data
results = Motor.query.filter_by(horsepower=horsepower, voltage=voltage, rpm=rpm).all()
except Exception as e:
flash(e)
db.session.rollback()
return render_template('filterassets.html', form=form, results=results)
return render_template('filterassets.html', form=form)
Because it's the backend of a page that lets users filter, rather than explicitly search, some form data is empty. This is causing the query to search for results where one or more forms == None.
Example: User enters 100 in the horsepower form and leaves RPM and Voltage blank. The query returns no results even though there are rows with 100 horsepower because it is looking for rows where Horsepower == 100 and RPM and Voltage == None.
I've tried using filter(None, object) with no success, and think the solution may be somewhere in using kwargs.
I know I need to pass all the form data to something that will remove None or Null entries, then pass it onto the final Motor.query.filter_by argument, I just don't know how.
You can create a dict with the filter data:
filter_data = {'horsepower': horsepower, 'voltage': voltage, 'rpm': rpm}
Then create another dict with only the keys which values exist:
filter_data = {key: value for (key, value) in filter_data.items()
if value}
And finally use this dict as kwargs to your query:
results = Motor.query.filter_by(**filter_data).all()
Related
I'm unable to loop through the "query" variable with the items list and push the code to database. but it is throughing an error ""ValueError: not enough values to unpack (expected 2, got 1)"", can someone check the code please?
#app.route('/', methods=['POST'])
def test():
if request.method == 'POST':
try:
query = request.form['url']
r = requests.get(query)
output = r.json()
items = output['result']
# # items = ['abc','bcd','cde','def'] # here items will be in list
for i in items:
user = User(listOfItems=items[i], query=query)
db.session.add(user)
db.session.commit()
responseBody = {'message': items}
return make_response(jsonify(responseBody))
except Exception, e:
return ('Oops!', e.__class__, 'occurred.')
else:
responseBody = {'message': 'failed'}
return make_response(jsonify(responseBody))
desired output in database:
listOfItems query time_stamp
abc example.com -date-
bcd example.com -date-
cde example.com -date-
def example.com -date-
xyz example1.com -datetime.now-
yza example1.com -datetime.now-
zab example1.com -datetime.now-
here,
query1: example.com returns ['abc','bcd','cde','def'] list items
query2: example1.com returns ['xyz','yza','zab'] list items
This part of the code has an issue. for i in items means the value at that index, not the index itself. So the first iteration will return 'abc' and so on.
for i in items:
user = User(listOfItems=items[i], query=query)
db.session.add(user)
db.session.commit()
Assuming that you want to have the values of the list and insert them, change the line to
user = User(listOfItems=i, query=query)
I found some problems:
you do not need the if request.method == 'POST' statement, you've already declared method in the route decorator.
for i in items returns each element from items, the i variable is not an index; so, user = User(listOfItems=items[i], query=query) is incorrect.
I'm not sure these will solve your problem or not; but if not, please show the output of items and output.
I am currently trying to append to the output list in my code the id of the query result. I can get it to do one of the ids but it will override the first one how can I change my code to allow any amount of looping to the output.append(q.id)
Here is the code:
#app.route('/new-mealplan', methods=['POST'])
def create_mealplan():
data = request.get_json()
recipes = data['recipes']
output = []
for recipe in recipes:
try:
query = Recipes.query.filter(func.lower(Recipes.recipe_name) == func.lower(recipe)).all()
# print(recipe)
if query:
query = Recipes.query.filter(func.lower(Recipes.recipe_name) == func.lower(recipe)).all()
for q in query:
output.append(q.id)
finally:
return jsonify({"data" : output})
To fix this I removed the
Try and Finally blocks.
Then returned after the for-loop was completed.
I try to get data from a webpage. This page contains several release information, but allow values not to be set. I.e. the date for testing from/to might be an empty string.
Now I try to deserialize all my data sucked from the page to insert it to a database and face problems handling empty dates.
from marshmallow import fields, Schema, ValidationError
class TestSchema(Schema):
training_necessary = fields.Function(deserialize=lambda x: True if x == 'Yes' else False)
test_from = fields.Date()
test_to = fields.Date()
data = dict(training_necessary='Yes', test_from='', test_to='')
try:
validated = TestSchema().load(data)
except ValidationError as err:
print(f"{err}")
Result:
{'test_to': ['Not a valid date.'], 'test_from': ['Not a valid date.']}
I already tried several combinations of allow_none=True or default='' but none of them helped my to get through. So, how to manage to allow empty dates? Setting a default to somewhat like 1970-01-01 won't help in that case.
Any hints?
Regards, Thomas
+++ EDIT: SOLUTION +++
Here's the working code I ended up after Jérômes helpful tipp:
from marshmallow import fields, Schema, ValidationError, pre_load
class TestSchema(Schema):
training_necessary = fields.Function(deserialize=lambda x: True if x == 'Yes' else False)
test_from = fields.Date(allow_none=True)
test_to = fields.Date(allow_none=True)
#pre_load(pass_many=False)
def string_to_none(self, data, many, **kwargs):
turn_to_none = lambda x: None if x == '' else x
for k, v in data.items():
data[k] = turn_to_none(v)
return data
data = dict(training_necessary='Yes', test_from='', test_to='')
try:
validated = TestSchema().load(data)
except ValidationError as err:
print(f"{err}")
I would pass no value at all.
data = dict(training_necessary='Yes')
Or I'd make the date fields allow_none and I'd pass None, not an empty string.
data = dict(training_necessary='Yes', test_from=None, test_to=None)
If the issue is that your input contains empty strings, I'd say this is a client issue, but you can add a pre_load method to delete empty strings from the input before deserializing. This is more or less equivalent to modifying the values you scrape from the page before feeding them to marshmallow.
I have a view which fetches multiple users from a database based on passed in skills. It works almost as desired except if it returns more than one user it only passes back the most recently fetched user. How do I aggregate fetched users to be passed back to the template. I've tried passing them back as a list but they didn't appear.
Here is my code:
form = FilterFreelancerForm(request.POST)
filtered_skills = set((request.POST.getlist('skills_select')))
match_fl = Freelancer.object.annotate(c=Count('skills')).filter(c=len(filtered_skills))
candidate_freelancers = None
for skill in filtered_skills:
candidate_freelancers = match_fl.filter(skills=skill)
freelancers = None
for freelancer in candidate_freelancers:
freelancers = User.objects.filter(freelancer=freelancer.id)
return render(request, 'freelancestudent/browsefreelancers.html', {'freelancers': freelancers,
'filter_form': form})
I previously had this:
freelancers = []
for freelancer in candidate_freelancers:
freelancers.append(User.objects.filter(freelancer=freelancer.id))
which returns nothing to the template.
Instead of:
for freelancer in candidate_freelancers:
freelancers = User.objects.filter(freelancer=freelancer.id)
try:
freelancers = User.objects.filter(freelancer__in=[freelancer.id for freelancer in candidate_freelancers])
out:
[<User: user1>, <User: user2>]
I'm trying to build a search system, and I want to search by multiple fieldsname, state, city, in my django models. I wrote the below code, yet I've been unable to figure out how to go about it. I use Q but it seems not working:
views.py:
def data_consulting(request):
if request.method == 'POST':
form = FilterForm(request.POST)
if form.is_valid():
conditions = [('toBuy', form.cleaned_data['toBuy']), ('name__contains', form.cleaned_data['searchName']),(('price__gte', form.cleaned_data['searchPriceBegin']), ('price__lte',form.cleaned_data['searchPriceEnd'])),(('calories__gte', form.cleaned_data['searchCalorieBegin']), ('calories__lte', form.cleaned_data['searchCalorieEnd'])), (('date__gte',form.cleaned_data['DateBegin']), ('date__lte', form.cleaned_data['DateEnd']))]
all_products = Product.objects.filter(reduce(operator.or_, [Q(condition) for condition in conditions]))
send = True
all_products = Product.objects.filter(reduce(operator.or_, [Q(condition) for condition in conditions]))
else:
form = FilterForm()
all_products = Product.objects.all()
return render(request, 'mealManager/data_consulting.html', locals())
Have a think about what
reduce(operator.or_, [Q(condition) for condition in conditions])
becomes with e.g. [('toBuy', 'bread'), ('name__contains', 'bread')]. It becomes
Q(('toBuy', 'bread')) | Q(('name_contains', 'bread'))
which is obviously wrong syntax, since Q rather needs kwargs than a tuple:
Q(toBuy='bread') | Q(name__contains='bread')
that's where the ** operator comes to the rescue. If you get data like this:
[{'toBuy': 'bread'}, {'name__contains': 'bread'}]
which may be accomplished by simply changing the conditions assignment you can then do
reduce(operator.or_, [Q(**condition) for condition in conditions])
which translates in the particular case to
Q(toBuy='bread') | Q(name__contains='bread')
which is exactly what we need.