Storing JSON into sqlite database using Python - python

I am posting a JSON object back to the server side and retrieving that information through a request. Right now this is my code for my views.py
#csrf_exempt
def save(request):
if request.method == 'POST':
rawdata = request.body
JSONData= json.dumps(rawdata)
return HttpResponse(rawdata)
when I return rawdata my response looks like this:
[{"time_elapsed":"0","volts":"239.3","amps":"19.3","kW":"4.618","kWh":"0","session":"1"},...]
when I return JSONdata my response looks like this:
"[{\"time_elapsed\":\"0\",\"volts\":\"239.1\",\"amps\":\"20.8\",\"kW\":\"4.973\",\"kWh\":\"0\",\"session\":\"1\"},....]
which response is better when trying to insert this data into a sqlite database using Python/Django?
Also how would I start a loop for this do I have to do this kind of code?
conn = sqlite3.connect('sqlite.db')
c = conn.cursor()
c.execute("INSERT STATEMENTS")
I assume I have to do a loop for the INSERT STATEMENTS portion of that code, but I don't have any key to work off of. In my data everything between {} is one row. How do I iterate through this array saying everytime you see {...data...} insert it into a new row?

Here is how I eventually solved my problem. It was a matter of figuring out how to translate the JSON object to something python could recognize and then writing a simple loop to iterate through all the data that was produced.
#csrf_exempt
def save(request):
if request.method == 'POST':
rawdata1 = request.body
rawdata2 = json.loads(rawdata1)
length = len(rawdata2)
for i in range(0,length,1):
x = meterdata(time_elapsed=rawdata2[i]['time_elapsed'], volts=rawdata2[i]['volts'], amps=rawdata2[i]['amps'], kW=rawdata2[i]['kW'], kWh=rawdata2[i]['kWh'], session=rawdata2[i]['session'])
x.save()
return HttpResponse("Success!")
The big differences is the json.loads rather than dumps and in the for loop how to access the newly converted data. The first bracket specifies the row to look in and the second specifies what item to look for. for the longest time I was trying to do data[0][0]. May this help anyone who finds this in the future.

probably if you need to store that data in a db is best to create a model representing it, then you create a ModelForm with associated your model for handling your POST.
In this manner saving the model to the db is trivial and serializing it as a json response is something like
data = serializers.serialize('json',
YourModel.objects.filter(id=id),
fields=('list','of','fields'))
return HttpResponse(data, mimetype='application/json')

Related

How can I update cache rows within the flask-cache (FileSystemCache)

I am using flask-cache (FileSystemCache)to store an entire table worth of data (to prevent constant database IO)
This works great, and really speeds up the reading of the records, but my app also allows users to "update rows" in the database.
I am fine with the IO in this case, however I would also like to update the local cache of the row in this situation (because if the user revisits the last updated row, the cache will be what was previously fetched from the database and will not reflect the most recent user update).
I can see the cache is generated and it is stored in some binary way (pickle?), which I can see contains all the rows (and as mentioned, the cache is working as expected for "reads"). I don't know how to either "get" or "set" specific rows within the cache file though.
Below is the simplified code of what I am doing:
#cache.cached(timeout=500, key_prefix='all_docs')
def cache_all_db_rows(table_name):
engine = create_sql_alchemy_engine()
connection = engine.connect()
results = connection.execute(stmt).fetchall()
return [row for row in results]
#site.route('/display/<doc_id>', methods=["GET", "POST"])
#login_required
def display(doc_id):
form = CommentForm(request.form)
results = cache_all_db_rows(table_name)
if request.method == "POST":
if form.validate_on_submit():
comments = form.comment.data
relevant = form.relevant.data
database_rate_or_add_comment(comments=comments, relevant_flag=relevant, doc_id=doc_id)
# Ideally I would set the update to the cache here (after a successful db update)
cache.set("foo", comments)
return render_template("display.html", form = form)
I tried a few things, but can't seem to query the cache (pickle file?)... I tried adding code to query what is actually in the cache file by doing this:
obj = []
file_name = "./cache/dfaec33f482d83493ed6ae7e87ace5f9"
with open(file_name,"rb") as fileOpener:
while True:
try:
obj.append(pickle.load(fileOpener))
except EOFError:
break
app.logger.info(str(obj))
but I am receiving an error: _pickle.UnpicklingError: invalid load key, '\xfb'.
I am not sure how to interact with the flask-cache.

python loop until length

so I'm having trouble getting some data to my DB.
I'm not that good with python and trying to learn.
so this is the data I'm sending to the Django server:
as you can see I'm getting FILES called doc[i] to the server and I want to save the name of the file in the DB.
but I don't know how to loop through it.
that's what I'm doing for now:
def submit_quality_dept_application(request, application_id):
doc0 = request.FILES['doc0']
length = request.data['length']
application = Application.objects.get(id=application_id)
application_state = application.application_state
application_state['doc0'] = doc0.name
Application.objects.filter(id=application_id).update(
application_state=application_state)
return Response(length, status=status.HTTP_200_OK)
that way it's working for doc0 and I can save its name in the DB.
but I want to loop through every doc[i] and save it in DB.
any suggestions?
You can enumerate over the items with a range(…) [Python-doc]:
def submit_quality_dept_application(request, application_id):
n = int(request.data['length'])
application = Application.objects.get(id=application_id)
application_state = application.application_state
for i in range(n):
doc = request.FILES[f'doc{i}']
application_state[f'doc{i}'] = doc.name
Application.objects.filter(id=application_id).update(application_state=application_state)
return Response(length, status=status.HTTP_200_OK)
But I'm not sure if the is the best way to handle multiple files. It might be better to submit a list of files as request, for example for the same key.

Extract fields from a JSON in Python(Django)

Hello I am new to the python world, and I am learning, I am currently developing a WebApp in Django and I am using ajax for sending requests, what happens is that in the view.py I get a JSON, from which I have not been able to extract the attributes individually to send to a SQL query, I have tried every possible way, I appreciate any help in advance.
def profesionales(request):
body_unicode = request.body.decode('utf-8')
received_json = json.loads(body_unicode)
data = JsonResponse(received_json, safe=False)
return data
Data returns the following to me
{opcion: 2, fecha_ini: "2021-02-01", fecha_fin: "2021-02-08", profesional: "168", sede: "Modulo 7", grafico: "2"}
This is the answer I get and I need to extract each of the values ​​of each key into a variable
You can interpret this as dict.
for key in received_json:
print(key,received_json[key])
# do your stuff here
but if it's always a object with same keys (fixed keys), you can access directly:
key_data = received_json[key]

Passing objects through Flask URL's

I am working on a site using Flask that is pulling data from an API, processing it into JSON, and then dynamically loading it throughout the site as needed. I am having an issue with matching the URL appropriately while at the same time efficiently loading what data I need.
Here is my main file:
import requests
from flask import Flask, render_template
app = Flask(__name__)
url = 'https://omgvamp-hearthstone-v1.p.mashape.com/cards'
myHeaders={
"X-Mashape-Key": 'key-here',
"Accept": "application/json"
}
r = requests.get(url, headers=myHeaders)
cards = r.json()
badSets = ['Promo', 'Hall of Fame', 'Tavern Brawl', 'Hero Skins', ' Missions', 'Credits', 'System', 'Debug']
#app.route('/')
def index():
return render_template('index.html', cards=cards, badSets=badSets)
#app.route('/<setName>', methods=['GET'])
def set(setName):
return render_template('set.html', cards=cards, setName=setName, badSets=badSets)
#app.route('/<setName>/<cardName>', methods=['GET'])
def individualCard(setName, cardName):
return render_template('card.html', cards=cards, setName=setName, cardName=cardName, badSets=badSets)
First, I'd prefer to not have to pass each html page all of my data. Is there some way to pull only what is needed and ignore the rest?
Second, I would like to pass a dictionary object i.e.
if card['name'] == card[setName][--index--][cardName]:
pass card object to html page here
How could this be achieved, and is it possible without having to use a for-loop through all of my data?
I'm happy to load my html pages if needed.
Assuming the basic structure of your parsed json data looks like this (a dictionary with lists of dictionaries):
{
"Basic": [{"cardId": 4711, ...}, {"cardId": 4712, ...}, ...],
"Fancy": [...],
...
}
You could rewrite:
#app.route('/<setName>', methods=['GET'])
def set(setName):
cardset = cards.get(setName)
return render_template('set.html', cardset=cardset)
This extracts the card set we are looking for by the dictionary key, according to the assumed data structure above.
Then in the template, instead of cardName, pass the cardId and rewrite the other route:
#app.route('/<setName>/<cardId>', methods=['GET'])
def individualCard(setName, cardId):
cardset = cards.get(setName)
matches = [x for x in cardset if x['cardId'] == cardId]
card = matches[0]
return render_template('card.html', card=card)
This uses list comprehension to extract a list of matches (everything that has the cardId we are looking for) from our selected cardset, and should be a list with a single element. We return the first element to the template for rendering.
Now this obviously does not do any error checking, for example the dictionary key we passed might be wrong and not be found, the cardId might not be found, or more interestingly there might be more than one result for the cardId we passed.
But this would be the general idea on how to approach this.
Also note I've left out badSets for clarity in the example, I'm assuming this are card sets that are forbidden, or for testing purposes.
For this case, you'd want to check the dictionary key first before looking up the set, and show an error page or something maybe:
#app.route('/<setName>', methods=['GET'])
def set(setName):
if setName in badSets:
return render_template('error.html')
cardset = cards.get(setName)
return render_template('set.html', cardset=cardset)
Disclaimer: This is coming purely from memory and it is late, so there might be an error here or there...

How to convert suds object to xml string

This is a duplicate to this question:
How to convert suds object to xml
But the question has not been answered: "totxt" is not an attribute on the Client class.
Unfortunately I lack of reputation to add comments. So I ask again:
Is there a way to convert a suds object to its xml?
I ask this because I already have a system that consumes wsdl files and sends data to a webservice. But now the customers want to alternatively store the XML as files (to import them later manually). So all I need are 2 methods for writing data: One writes to a webservice (implemented and tested), the other (not implemented yet) writes to files.
If only I could make something like this:
xml_as_string = My_suds_object.to_xml()
The following code is just an example and does not run. And it's not elegant. Doesn't matter. I hope you get the idea what I want to achieve:
I have the function "write_customer_obj_webservice" that works. Now I want to write the function "write_customer_obj_xml_file".
import suds
def get_customer_obj():
wsdl_url = r'file:C:/somepathhere/Customer.wsdl'
service_url = r'http://someiphere/Customer'
c = suds.client.Client(wsdl_url, location=service_url)
customer = c.factory.create("ns0:CustomerType")
return customer
def write_customer_obj_webservice(customer):
wsdl_url = r'file:C:/somepathhere/Customer.wsdl'
service_url = r'http://someiphere/Customer'
c = suds.client.Client(wsdl_url, location=service_url)
response = c.service.save(someparameters, None, None, customer)
return response
def write_customer_obj_xml_file(customer):
output_filename = r'C\temp\testxml'
# The following line is the problem. "to_xml" does not exist and I can't find a way to do it.
xml = customer.to_xml()
fo = open(output_filename, 'a')
try:
fo.write(xml)
except:
raise
else:
response = 'All ok'
finally:
fo.close()
return response
# Get the customer object always from the wsdl.
customer = get_customer_obj()
# Since customer is an object, setting it's attributes is very easy. There are very complex objects in this system.
customer.name = "Doe J."
customer.age = 42
# Write the new customer to a webservice or store it in a file for later proccessing
if later_processing:
response = write_customer_obj_xml_file(customer)
else:
response = write_customer_obj_webservice(customer)
I found a way that works for me. The trick is to create the Client with the option "nosend=True".
In the documentation it says:
nosend - Create the soap envelope but don't send. When specified, method invocation returns a RequestContext instead of sending it.
The RequestContext object has the attribute envelope. This is the XML as string.
Some pseudo code to illustrate:
c = suds.client.Client(url, nosend=True)
customer = c.factory.create("ns0:CustomerType")
customer.name = "Doe J."
customer.age = 42
response = c.service.save(someparameters, None, None, customer)
print response.envelope # This prints the XML string that would have been sent.
You have some issues in write_customer_obj_xml_file function:
Fix bad path:
output_filename = r'C:\temp\test.xml'
The following line is the problem. "to_xml" does not exist and I can't find a way to do it.
What's the type of customer? type(customer)?
xml = customer.to_xml() # to be continued...
Why mode='a'? ('a' => append, 'w' => create + write)
Use a with statement (file context manager).
with open(output_filename, 'w') as fo:
fo.write(xml)
Don't need to return a response string: use an exception manager. The exception to catch can be EnvironmentError.
Analyse
The following call:
customer = c.factory.create("ns0:CustomerType")
Construct a CustomerType on the fly, and return a CustomerType instance customer.
I think you can introspect your customer object, try the following:
vars(customer) # display the object attributes
help(customer) # display an extensive help about your instance
Another way is to try the WSDL URLs by hands, and see the XML results.
You may obtain the full description of your CustomerType object.
And then?
Then, with the attributes list, you can create your own XML. Use an XML template and fill it with the object attributes.
You may also found the magic function (to_xml) which do the job for you. But, not sure the XML format matches your need.
client = Client(url)
client.factory.create('somename')
# The last XML request by client
client.last_sent()
# The last XML response from Web Service
client.last_received()

Categories