Getting back property of object in a query list SQLAlchemy - python

I have a join table called UserServices. Which has a FK of service_id and makes a back ref to a service. Below I get all the userServices in which the id in the route param matches the user_id (another FK)
I am then trying to access all the service properties on the all_user_services list.
My current code only returns one dict instead of a list of dicts. What am i doing wrong?
#bp.route('/user/<id>/services', methods=['GET'])
def get_services_from_user(id):
all_user_services = db_session.query(UserService).filter(UserService.user_id == id).all()
for service in all_user_services:
result = service_schema.dump(service.service)
return jsonify(result)

You just return on first for iteration. You need to create result list:
dumped = [service_schema.dump(s.service) for s in all_user_services]
return jsonify(dumped)

Related

added two search bar in django one search by id and other by name .Tried many ways but cannot do it if i try by id then i am not able to do with name

I have to make 2 search bars. I don't know how to add multiple fiels...
match= Staff.objects.filter(id=srch1...) here how can I add name=srch1
over here after trying many ways I found it but the problem is all input here is string how to change it to int
def search(request):
# Catch the data and search in Staff model.
if request.method=='POST':
srch1 = request.POST['srch']
print(type(srch1))
if type(srch1)== int:
match= Staff.objects.filter(id=srch1)
if match :
return render(request,'search.html',{'sr': match})
else:
messages.error(request,'no results,found')
elif type(srch1)== str:
catch= Staff.objects.filter(name=srch1)
if catch:
return render(request,'search.html',{'sr': catch})
else:
messages.error(request,'no results,found')
else:
return HttpResponseRedirect("/search")
return render(request,"search.html")
You should be using a GET request with querysting parameters or (url parameters, which is a bit more complicated) for this, not a POST. Here's how I would do this:
def search(request, *args, **kwargs):
# Initial empty query dictionary for use with query later.
query = {}
# Getting 'name' and 'id' from querystring parameters (i.e. ?id=1&name=foo)
name = request.GET.get('name', None)
id = request.GET.get('id', None)
# Add 'id' to the query dictionary if it exists
if id is not None:
query['id'] = id
# Add name to the query dictionary if it exists
if name is not None:
query['name'] = name
# If the query dictionary has name or id, get the Staff entry from the database
if query.get('name', None) or query.get('id', None):
# Note that .filter() returns a QuerySet. You should probably use .get()
# since my guess is that you only want one Staff object (judging by your
# search parameters). Also note that since we are using **query we will be
# using BOTH 'name' AND 'id' to search for the Staff, as long as both exist in
# the query dictionary.
match = Staff.objects.get(**query)
# If there is a match, send it in the rendered response context dict
if match:
return render(request, 'search.html', {'sr': match})
# no match, send message notifying that a Staff entry was not found matching
# the desired criteria
return render(request, 'search.html', {message: 'Not Found'}
# There were no query parameters, so we are not searching for anything.
else:
return render(request, 'search.html')
You can see that the above code is much simpler, and more concise. This will help you or anyone else checking out your code in the future to better understand what you're trying to acheive.
P.S. I typically only use POST requests when I am creating an entry in the database. Maybe this is preference, but to my knowledge it is best practice to use a GET request for search.

How does allocateIds() work in Cloud Datastore Mode?

In the new Datastore Mode documentation, there is mention of allocateIds() method. However, beyond a single paragraph, there isn't an example code that illustrates how this method is used.
I am trying to allocate an ID each time I create a new entity so that I can save the ID as a property of the entity itself.
I assume that in pseudocode, it works like this:
user_id = allocateIds(number_id_ids=1)
user_key = datastore_client.key(kind='User', user_id)
user = datastore.Entity(key=user_key)
user.update({ 'user_id': user_id }) # Allows a get_user_by_id() query
datastore_client.put(user)
How exactly does allocateIds() work in practice?
When you call the allocateIds() function it invokes a new instance of class Key(object) when the consturctor of "Key" is called it takes all of the arguments you provided allocateIds and recombines them through a _combine_args method. That is what produces your key.
(and if you want to see the code yourself)
source: https://googleapis.dev/python/datastore/latest/_modules/google/cloud/datastore/key.html#Key
Yes, allocateIds() should work for the case where you want to get an ID from Datastore mode and use it as both an ID and property value:
from google.cloud import datastore
client = datastore.Client()
# Allocate a single ID in kind User
# Returns list of keys
keys = client.allocate_ids(client.key('User'), 1)
# Get key from list
key = keys[0]
print(key.id)
# Create a User entity using our key
user = datastore.Entity(key)
# Add ID as a field
user.update({
'user_id': key.id
})
# Commit to database
client.put(user)
# Query based on full key
query = client.query(kind='User')
query.key_filter(user.key, '=')
results = list(query.fetch())
print(results)
For most other cases where you just want a single auto-ID, you can skip allocate_ids:
# Create a User entity
# Use an incomplete key so Datastore assigns an ID
user = datastore.Entity(client.key('User'))
# Add some data
user.update({
'foo': 'bar'
})
# Datastore allocates an ID when you call client.put
client.put(user)
# user.key now contains an ID
user_id = user.key.id
print(user_id)
# Query with the ID and key
query = client.query(kind='User')
query.key_filter(user.key, '=')
results = list(query.fetch())
print(results)

Django - Create object if field not in database

I want to create an object only if there's no other object with the same ID already in the database. The code below would create the same item if one the parameters below like the State was modified.
returns = Return.objects.all()
for ret in returns:
obj, created = Return.objects.get_or_create(ItemID="UUID",
ItemName="Hodaddy", State="Started")
obj.save()
get_or_create works off all the arguments provided to find the object.
What you need to do instead is use the special defaults argument to provide the new value for a field that you don't want to filter on.
In your case, you only want the UUID field to be unique, and so you provide the other two members as defaults.
obj, created = Return.objects.get_or_create(ItemID="UUID",
defaults={ItemName:"Hodaddy", State:"Started"})
Then you can make further decisions based on the value of created. I am not sure why you're iterating over all the Returns in the original question?
If you know the id, you can query for it:
In your question, you have:
returns = Return.objects.all()
for ret in returns:
return_in_database = Return.objects.filter(ItemId="UUID").exists()
if not return_in_database:
obj, created = Return.objects.get_or_create(ItemID="UUID",
ItemName="Hodaddy", State="Started")
obj.save()
This can be done as:
if not Return.objects.filter(ItemId="UUID").exists():
obj, created = Return.objects.get_or_create(ItemID="UUID",
ItemName="Hodaddy", State="Started")
obj.save()
As you can see, I've removed the for loop, as you were not using the variable ret anywhere, so no need to iterate over all Return objects. The above is functionally equivalent to what you had. :)
OR:
You can write your own manager with a create_or_update method inside your models.py
class ReturnManager(models.Manager):
def create_or_update(self, **kwargs):
new_return = Return(**kwargs)
existing = Return.objects.filter(ItemId=new_returns.ItemID).first()
if existing:
new_return.pk = existing.pk
new_return.id = existing.id
new_return.save()
return new_return
You would then assign this to your Return model
class Return(model.Models):
# your object fields here
objects = ReturnManager()
You need to change the param in the query, to just constraint the object lookup on ItemID. Once, a new object is returned you can update the ItemName and State
obj, created = Return.objects.get_or_create(ItemID="UUID")
if created:
obj.ItemName="<item-name>"
obj.State="<Started>"
obj.save()

How can I return a list of results as JSON?

I want to return the result of a query as JSON. I'm using the following route to return one model instance as a JSON object.
#mod.route('/autocomplete/<term>', methods=['GET'])
def autocomplete(term):
country = Country.query.filter(Country.name_pt.ilike('%'+ term + '%')).first()
country_dict = country.__dict__
country_dict.pop('_sa_instance_state', None)
return jsonify(json_list=country_dict)
This code works well if I use the first() method. However, I need to use the all() to get all results. When I do that, I get the following error.
country_dict = country.__dict__
AttributeError: 'list' object has no attribute '__dict__'
What should I be doing to return the entire list of results as JSON?
You need to do that "jsonify preparation step" for each item in the list, since .all() returns a list of model instances, not just one instance like .first(). Work on a copy of each __dict__ so you don't mess with SQLAlchemy's internal representation of the instances.
#mod.route('/autocomplete/<term>', methods=['GET'])
def autocomplete(term):
countries = []
for country in Country.query.filter(Country.name_pt.ilike('%' + term + '%'):
country_dict = country.__dict__.copy()
country_dict.pop('_sa_instance_state', None)
countries.append(country_dict)
return jsonify(json_list=countries)
Probably better just to return the data about each country explicitly, rather than trying to magically jsonify the instance.
#mod.route('/autocomplete/<term>', methods=['GET'])
def autocomplete(term):
countries = []
for country in Country.query.filter(Country.name_pt.ilike('%' + term + '%'):
countries.append({
'id': country.id,
'name': country.name_pt,
})
return jsonify(countries=countries)

pass in table name to sqlalchemy query through url in flask

In short, how do i
var="TableName"
models.var.query.all()
explanation
My goal is to allow the user to change the order of list of items.
I set up an ajax call that sends an array of id's to the api below.
It works if i hard code the query, and make a api view per table.
my problem is that i want "table" to fill in this line
models.table.query.filter_by(id=item).first()
to complete the query.
here is the view api which gives me an error "no attribute 'table'"
#app.route('/order/<table>')
def order(table):
# import pdb;pdb.set_trace()
sortedItems = request.args.listvalues()[0]
o=1
import pdb;pdb.set_trace()
for item in sortedItems:
grab = models.table.query.filter_by(id=item).first()
grab.order=o
o=o+1
db.session.commit()
return jsonify(result=sortedItems)
You can use getattr():
>>> var = 'table_name'
>>> table = getattr(models, var)
>>> table.query.filter_by(id=item).first()
getattr() will raise an AttributeError if the attribute your trying to get does not exist.
Example for your order()-function:
#app.route('/order/<table>')
def order(table):
sortedItems = request.args.listvalues()[0]
o=1
table = getattr(models, table)
for item in sortedItems:
grab = table.query.filter_by(id=item).first()
grab.order=o
o=o+1
db.session.commit()
return jsonify(result=sortedItems)

Categories

Resources