How i can update a value of object from api response - postgresql

I am completely new to the Python world, but I am trying to learn this beautiful language. But I need your help.
I have an API, and I want it when a user wants to change the value of any data about his product, and it is updated with the new value.
For example:
I have the following product:
Title = DC snowboard boots
Description = Hi everyone, I'm selling this snowboard boots and both
are brand new for £ 130
Price = £ 130
And then the user makes a request to change for example the price of the product.
And completely lost in how to do that.
My view for update the product:
import app.utils.responses as resp
from app.api import api
from app.database import db
from app.models.products import Products, ProductsSchema
from app.utils.responses import m_return
#api.route('/product/<product_id>', methods=['PATCH'])
def update_product(product_id):
# Get products data
product_to_update = Products.query.get(product_id)
Products.id = product_to_update
result = Products.id
db.session.merge(result)
db.session.commit()
# Products schema for some fields.
products_schema = ProductsSchema(
only=('id', 'title', 'description', 'post_code', 'product_name', 'is_available', 'created', 'price'))
# Return item updated.
return m_return(
http_code=resp.PRODUCT_UPDATED_SUCCESSFULLY['http_code'],
message=resp.PRODUCT_UPDATED_SUCCESSFULLY['message'],
value=products_schema.dump(result).data
)

product_to_update = Products.query.get(product_id)
This code returns a Products object if product_id is in db, if yes then you can update columns of this product:
product_to_update.price = 123#new price
db.session.commit()
So for this specific product the price will be update.

Related

Entity Framework, Linq : concatenating results from child table

I have an existing linq query which gets some data into a view model object. This is working fine.
I want to add a new property for data from child table which will have column values from a child table in a comma separated string format.
Problem: I am not able to concatenate the results using string.join
Simplified version of tables showing only relevant fields
part
id
part number
1
ABC1
2
DEF1
vendor
id
vendorname
1
acme
2
john
vendor part name (vendor specific part number)
partid
vendorid
partname
1
1
GDSE-553-32
1
2
JWWVV-HH-01
simplified version of query
result = (from p in DBContext.Parts.Where(w => w.EquipmentId == eId)
select new PartModel
{
Id = p.Id,
Number = p.PartNumber,
VendorPartNames= String.Join(",", DBContext.VendorPartName.Where(w => w.PartId == p.Id).Select(s => s.PartName))//this line causes exception (shown below)
});
Exception:
LINQ to Entities does not recognize the method 'System.String Join(System.String, System.String[])' method, and this method cannot be translated into a store expression.
Please note: the actual query has some joins and other columns, so please dont suggest solutions that requires joins.
If I change the "VendorPartName" to a List type , I can get the results without any problems.
My only problem is in "How to convert the results for "VendorPartName" property to a comma separated strings?"
eg: based on sample table data provided, it should be
GDSE-553-32, JWWVV-HH-01
Entity Framework does not support String.Join() method.
So, what we can do is to fetch VendorPartNames as a string collection and then we can later separate it with ,.
Note: For this, we would first use an anonymous object and later convert it to PartModel.
So your query would look like this:
var parts = DBContext.Parts
.Where(w => w.EquipmentId == eId)
.Select(p => new {
Id = p.Id,
Number = p.PartNumber,
VendorPartNames = p.VendorPartName.Select(n => n.PartName)
}).ToList();
var result = parts.Select(i => new PartModel {
Id = i.Id,
Number = i.Number,
VendorPartNames = String.Join(",", i.VendorPartNames)
}).ToList();

Flask Translate Choice in Form To ForeignKey Pointing to Another Table

This part of the app works, buts it's ugly and not sustainable. Need a more evolved solution.
PROBLEM I AM TRYING TO SOLVE:
This part of the application enables users to access a form to enter purchases they've made and store them in a Postgres DB. I am using Flask SQLAlchemy ORM.
Within my purchase table exists a field store_id, that has a ForeignKey relationship to my store table. I don't want my user to select a store ID # in the form, so I am using a SelectField to enable them to choose the store name instead. However, I can't seem to find a sustainable way to translate the store name back to its associated ID. Right now I am using the ugly IF statements seen below.
What is a better way to map/translate store name to ID which is already housed in the "store" table in my DB?
MY MODEL:
class Purchase(db.Model):
id = db.Column(db.Integer, primary_key=True)
item = db.Column(db.String(80))
quantity = db.Column(db.Integer)
unit_cost = db.Column(db.Integer)
total_cost= db.Column(db.Integer)
date = db.Column(db.DateTime)
store_id = db.Column(db.Integer, db.ForeignKey('store.id'))
MY FORM:
class CreatePurchase(FlaskForm):
item = StringField('Item', validators=[DataRequired()])
quantity = IntegerField('Quantity', validators=[DataRequired()])
unit_cost = IntegerField('Unit Cost', validators=[DataRequired()])
total_cost = IntegerField('Total Cost', validators=[DataRequired()])
store_id = SelectField("Store Selector", choices=[('0','Select Store'),('1','Furgesons'), ('2','Ocean State'), ('3','Chewy'), ('4','Amazon'), ('5', 'Rumford')])
date = DateField('Purchase Date', validators=[DataRequired()])
submit = SubmitField('Enter')
MY ROUTE:
#main.route('/enter_purchases', methods=['GET', 'POST'])
def enter_purchase():
form = CreatePurchase()
x = str(form.store_id) # this is a store name from our form
p = 0
if "Ocean State" in x:
p = 2
elif "Amazon" in x:
p = 4
elif "Furgesons" in x:
p = 1
elif "Chewy" in x:
p = 3
elif "Rumford" in x:
p = 5
if form.validate_on_submit():
purchase = Purchase(item=form.item.data, quantity=form.quantity.data, unit_cost=form.unit_cost.data,
total_cost=form.total_cost.data, date=form.date.data,store_id=p)
db.session.add(purchase)
db.session.commit()
flash('New purchase added successfully')
return redirect(url_for('main.success'))
return render_template('enter_purchases.html', form=form)
You have a store table, with a numeric id (as the PK) and a name attribute:
class Store(db.Model):
store_id = ..
store_name = ..
You populate your form with all of the unique values from the store_name. This needs to be a dynamically generated form, so instead of using a form that is statically created do something like:
def CreatePurchase()
class TempForm(FlaskForm):
item = StringField('Item', validators=[DataRequired()])
quantity = IntegerField('Quantity', validators=[DataRequired()])
unit_cost = IntegerField('Unit Cost', validators=[DataRequired()])
total_cost = IntegerField('Total Cost', validators=[DataRequired()])
date = DateField('Purchase Date', validators=[DataRequired()])
submit = SubmitField('Enter')
choices = ## some SQLalchemy code to get all unique store_names from the table
TempForm.store_id = SelectField("Store Selector", choices=choices)
return TempForm()
Then form.store_id will provide the right id, but display the string name of the store in the form.
The key in this setup is making sure you use the right SQLalchemy code to populate the SelectField dynamically. Basically for each store in the table you can just iterate through something like this:
choices = list()
for store in Store.query.all(): # <- assumes store_id and store_names are unique
choices.append((store.store_id, store.store_name))

Optimizing foreign key & manytomany field in REST API query

I'm wondering is there anyway to optimize an api when using foreign key and ManytoMany field, for example :
Serializer :
class SerializerA(serializers.ModelSerializer):
class Meta:
model = Model_A
fields = ('id', 'official_name', 'gender')
depth = 1
class SerializerB(serializers.ModelSerializer):
user = SerializerA(many=True)
class Meta:
model = Model_B
fields = ('id', 'project_name','project_type', 'project_start_date', 'user')
depth = 1
API :
class ReportAPI(APIView):
def get(self, request):
all_projects = Model_B.objects.all()
project_serializer = SerializerB(all_projects, many=True)
return Response(project_serializer.data)
now with this, if i go to the API url, and debug this page, it''l show that I'm querying 78 times from the SQL query. But if I remove one field from manytoMany seriealizer field which the 'gender', the page now will only query from the database 21 times, so my question is again, how can I optimize this?
You can use select_related (for ForeignKey) and/or prefetch_related (For ManyToMany or ManyToOne) so that it will not hit the database for each Model_B object.
If user is a FK in Model_B then you can do:
class ReportAPI(APIView):
def get(self, request):
all_projects = Model_B.objects.all().select_related('user')
project_serializer = SerializerB(all_projects, many=True)
return Response(project_serializer.data)
If the user model has other FK that you need in it's serializer, then you can also do select_related('user', 'user__other_field').

Use of full-text search + GIN in a view (Django 1.11 )

I need some help with building proper query in a django view for full-text search using GIN index. I have quite a big database (~400k lines) and need to do a full-text search on 3 fields from it. Tried to use django docs search and this is code BEFORE GIN. It works, but takes 6+ seconds to search over all fields. Next I tried to implement a GIN index to speed up my search. There are a lot of questions already how to build it. But my question is - how does the view query change when using a GIN index for search? What fields should I search?
Before GIN:
models.py
class Product(TimeStampedModel):
product_id = models.AutoField(primary_key=True)
shop = models.ForeignKey("Shop", to_field="shop_name")
brand = models.ForeignKey("Brand", to_field="brand_name")
title = models.TextField(blank=False, null=False)
description = models.TextField(blank=True, null=True)
views.py
def get_cosmetic(request):
if request.method == "GET":
pass
else:
search_words = request.POST.get("search")
search_vectors = (
SearchVector("title", weight="B")
+ SearchVector("description", weight="C")
+ SearchVector("brand__brand_name", weight="A")
)
products = (
Product.objects.annotate(
search=search_vectors, rank=SearchRank(search_vectors, search)
)
.filter(search=search_words)
.order_by("-rank")
)
return render(request, "example.html", {"products": products})
After GIN:
models.py
class ProductManager(models.Manager):
def with_documents(self):
vector = (
pg_search.SearchVector("brand__brand_name", weight="A")
+ pg_search.SearchVector("title", weight="A")
+ pg_search.SearchVector("description", weight="C")
)
return self.get_queryset().annotate(document=vector)
class Product(TimeStampedModel):
product_id = models.AutoField(primary_key=True)
shop = models.ForeignKey("Shop", to_field="shop_name")
brand = models.ForeignKey("Brand", to_field="brand_name")
title = models.TextField(blank=False, null=False)
description = models.TextField(blank=True, null=True)
search_vector = pg_search.SearchVectorField(null=True)
objects = ProductManager()
class Meta:
indexes = [
indexes.GinIndex(
fields=["search_vector"],
name="title_index",
),
]
# update search_vector every time the entry updates
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
if (
"update_fields" not in kwargs
or "search_vector" not in kwargs["update_fields"]
):
instance = (
self._meta.default_manager
.with_documents().get(pk=self.pk)
)
instance.search_vector = instance.document
instance.save(update_fields=["search_vector"])
views.py
def get_cosmetic(request):
if request.method == "GET":
pass
else:
search_words = request.POST.get('search')
products = ?????????
return render(request, 'example.html', {"products": products})
Answering my own question:
products = (
Product.objects.annotate(rank=SearchRank(F("search_vector"), search_words))
.filter(search_vector=search_words)
.order_by("-rank")
)
This means you should search your index field - in my case search_vector field.
Also I have changed my code a bit in ProductManager() class, so now I can just use
products = Product.objects.with_documents(search_words)
Where with_documents() is a custom function of custom ProductManager(). The recipe of this change is here (page 29).
What does all this code do:
creates search_vector with scores to fields, field with bigger score - gets higher place in result sorting.
creates GIN index for full-text search via ORM Django
updates GIN index every time the instance of model is changed
What this code dosn't do:
It doesn't sort by relevance of substring which is queried. Possible solution.
Hope this will help somebody with a bit complicated full-text search in Django.

How to filter records using group functionality in BreezeJs

I'm developing a client app that uses breezejs and Entity Framework 6 on the back end. I've got a statement like this:
var country = 'Mexico';
var customers = EntityQuery.from('customers')
.where('country', '==', country)
.expand('order')
I want to use There may be hundreds of orders that each customer has made. For the purposes of performance, I only want to retrieve the latest order for each customer. This will be based on the created date for the order. In SQL, I could write something like this:
SELECT c.customerId, companyName, ContactName, City, Country, max(o.OrderDate) as LatestOrder FROM Customers c
inner join Orders o on c.CustomerID = o.CustomerID
group by c.customerId, companyName, ContactName, City, Country
If this was run against the northwind database, only the most recent order row is returned for each customer.
How can I write a similar query in breeze, so that it runs on the server side and therefore returns less data to the client. I know I could handle this all on the client but writing some javascript in a querysucceeded method that could be run by the client - but that's not the goal here.
thanks
For a case like this, you should create a special endpoint method that will perform your query.
Then you can use an Entity Framework query to do what you want, using the LINQ syntax.
Here are two Web API examples:
[HttpGet]
public IQueryable<Object> CustomersLatestOrderEntities()
{
// IQueryable<Object> containing Customer and Order entity
var entities = ContextProvider.Context.Customers.Select(c => new { Customer = c, LatestOrder = c.Orders.OrderByDescending(o => o.OrderDate).FirstOrDefault() });
return entities;
}
[HttpGet]
public IQueryable<Object> CustomersLatestOrderProjections()
{
// IQueryable<Object> containing Customer and Order entity
var entities = ContextProvider.Context.Customers.Select(c => new { Customer = c, LatestOrder = c.Orders.OrderByDescending(o => o.OrderDate).FirstOrDefault() });
// IQueryable<Object> containing just data fields, no entities
var projections = entities.Select(e => new { e.Customer.CustomerID, e.Customer.ContactName, e.LatestOrder.OrderDate });
return projections;
}
Note that you have a choice here. You can return actual entities, or you can return just some data fields. Which is right for you depends upon how you are going to use them on the client. If they are just for display in a
non-editable list, you can just return the plain data (CustomersLatestOrderProjections above). If they can potentially
be edited, then return the object containing the entities (CustomersLatestOrderEntities). Breeze will merge the entities
into its cache, even though they are contained inside this anonymous object.
Either way, because it returns IQueryable, you can use the Breeze filtering syntax from the client to further qualify the query.
var projectionQuery = breeze.EntityQuery.from("CustomersLatestOrderProjections")
.skip(20)
.take(10);
var entityQuery = breeze.EntityQuery.from("CustomersLatestOrderEntities")
.where('customer.countryName', 'startsWith', 'C');
.take(10);