added new generic rss fetch and parse functions and setup to store not only today value but all values in file and update if new are available.

This commit is contained in:
Ivan Hörler 2018-01-21 21:31:26 +01:00
parent b53f52cac1
commit dba76057b3
6 changed files with 184 additions and 190 deletions

View File

@ -11,134 +11,99 @@ Key:Value pairs of new currencys.
"""
def get_exchange_rate():
# zweitweise kann die resource nicht geladen werden.
# https://stackoverflow.com/a/43523497/4061870
# During weekends there are no updates.
# To develop i need a testresource.
# In that case i comment the Online Resource block and uncomment the
# development Block...
# ~~~~~~~~~~~~~~~~~~~~~
# Online Resource block:
# ~~~~~~~~~~~~~~~~~~~~~
today = datetime.now().strftime("%Y-%m-%d")
SNB_URL = 'https://www.snb.ch/selector/de/mmr/exfeed/rss'
def get_rss(url):
urlsocket = ''
try:
urlsocket = urllib.request.urlopen(SNB_URL)
urlsocket = urllib.request.urlopen(url)
return(urlsocket)
except urllib.error.URLError as e:
print('err: urllib.request.urlopen: ', e.reason)
def parse_rss(urlsocket):
if urlsocket:
root = ET.parse(urlsocket)
root = ET.ElementTree(root)
# ~~~~~~~~~~~~~~~~~~~~~
# development block:
# ~~~~~~~~~~~~~~~~~~~~~
# today = "2018-01-08"
# try:
# root = ET.ElementTree(file='rss')
# except Exception as e:
# print('exchange_rates.py_urlsocket failed %s (
# %s) on date: %s for %s'
# % (e, type(e), root))
# ~~~~~~~~~~~~~~~~~~~~~
rss_tree = ET.ElementTree(root)
return(rss_tree)
# Namespaces
ns = {'rdf': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
'none': 'http://purl.org/rss/1.0/',
'dc': 'http://purl.org/dc/elements/1.1/',
'dcterms': 'http://purl.org/dc/terms/',
'cb': 'http://www.cbwiki.net/wiki/index.php/Specification_1.2/'
}
# Pathvariables to XML Namespaces
rate_path = 'cb:statistics/cb:exchangeRate/'
observation_path = 'cb:statistics/cb:exchangeRate/cb:observation/'
exchange_rates = {}
for item in root.findall('none:item', ns):
# for eatch item n the list we grab the release date
# to evaluate if its fresh data or old:
# THE CURRENCY DATE:
datetime_str = item.find('dc:date', ns).text
# convert string to date object:
# https://stackoverflow.com/a/12282040/4061870
# seams like snb striked the microsecond somewhere
# between Nov. and Dez. 2017 so maybe first check
# time type is with milliseconds:
def get_exchange_rate(rss_tree, ns):
# Pathvariables to XML Namespaces with
rate_path = 'cb:statistics/cb:exchangeRate/'
observation_path = 'cb:statistics/cb:exchangeRate/cb:observation/'
exchange_rates = []
for item in rss_tree.findall('none:item', ns):
datetime_str = item.find('dc:date', ns).text
try:
date = datetime.strptime(''.join(
datetime_str.rsplit(':', 1)),
"%Y-%m-%dT%H:%M:%S%z").strftime(
"%Y-%m-%d")
except Exception as e:
print('%s (%s)' % (e, type(e)))
try:
date = datetime.strptime(''.join(
datetime_str.rsplit(':', 1)),
"%Y-%m-%dT%H:%M:%S%z").strftime(
"%Y-%m-%dT%H:%M:%S.%f%z").strftime(
"%Y-%m-%d")
continue
except Exception as e:
print('%s (%s)' % (e, type(e)))
try:
date = datetime.strptime(''.join(
datetime_str.rsplit(':', 1)),
"%Y-%m-%dT%H:%M:%S.%f%z").strftime(
"%Y-%m-%d")
continue
except Exception as e:
print('%s (%s)' % (e, type(e)))
continue
# Print dates for development:
# print("date:", date, "today:", today)
# only the values of today are used so check for date in XML:
if date == today:
# now search for the currency exchange rate:
target_currency = item.find(rate_path +
'cb:targetCurrency', ns).text
value = float(item.find(observation_path +
'cb:value', ns).text)
value = float(value) # convert to float
foreign_value = value # copy to new value to have both.
if item.find(observation_path + 'cb:unit_mult', ns) is None:
# because it's dangerous to check for present,
# i check for none here and have to set the target
# to 1. as im multiplying it later.
unit_mult = float("1.0")
else:
# shift left by 2 digits with "/"
# https://stackoverflow.com/questions/8362792/
# because some currencys differ widly from CHF
unit_mult = item.find(observation_path +
'cb:unit_mult', ns).text
# unit_mult defaults to '0' so we check for 8 decimal
# values (2..-6) they represent the fracton value to
# calculate the correct decimalpoint.
if unit_mult == '2': # thinking of Bitcoins
unit_mult = '0.01'
if unit_mult == '1':
unit_mult = '0.10'
if unit_mult == '-1':
unit_mult = '10'
if unit_mult == '-2': # Japan Yen
unit_mult = '100'
if unit_mult == '-3':
unit_mult = '1000'
if unit_mult == '-4':
unit_mult = '10000'
if unit_mult == '-5':
unit_mult = '100000'
if unit_mult == '-6': # indian rupies
unit_mult = '1000000'
unit_mult = float(unit_mult) # convert to float
# calculate the Currency to CHF:
foreign_value = 1 / value
foreign_value *= unit_mult
value = value / unit_mult
# truncate it to decimal values provided by the xml:
foreign_value_round = round(foreign_value, 5)
# Print nice setup of all calculated currencys for development:
# print("date:", date, " 1 ", target_currency, " costs: ",
# CHFvalue, "CHF and 1 ", base_currency, " costs: ",
# FOREIGNvalue_round, target_currency)
exchange_rates.update(
{target_currency: foreign_value_round})
# Print the Dictionary:
# print(exchange_rates)
else:
continue
return(exchange_rates, today)
# now search for the currency exchange rate:
target_currency = item.find(rate_path +
'cb:targetCurrency', ns).text
value = float(item.find(observation_path +
'cb:value', ns).text)
value = float(value) # convert to float
foreign_value = value # copy to new value to have both.
if item.find(observation_path + 'cb:unit_mult', ns) is None:
# because it's dangerous to check for present,
# i check for none here and have to set the target
# to 1. as im multiplying it later.
unit_mult = float("1.0")
else:
# shift left by 2 digits with "/"
# https://stackoverflow.com/questions/8362792/
# because some currencys differ widly from CHF
unit_mult = item.find(observation_path +
'cb:unit_mult', ns).text
# unit_mult defaults to '0' so we check for 8 decimal
# values (2..-6) they represent the fracton value to
# calculate the correct decimalpoint.
if unit_mult == '2': # thinking of Bitcoins
unit_mult = '0.01'
if unit_mult == '1':
unit_mult = '0.10'
if unit_mult == '-1':
unit_mult = '10'
if unit_mult == '-2': # Japan Yen
unit_mult = '100'
if unit_mult == '-3':
unit_mult = '1000'
if unit_mult == '-4':
unit_mult = '10000'
if unit_mult == '-5':
unit_mult = '100000'
if unit_mult == '-6': # indian rupies
unit_mult = '1000000'
unit_mult = float(unit_mult) # convert to float
# calculate the Currency to CHF:
foreign_value = 1 / value
foreign_value *= unit_mult
value = value / unit_mult
# truncate it to decimal values provided by the xml:
foreign_value_round = round(foreign_value, 5)
# Print nice setup of all calculated currencys for development:
# print("date:", date, " 1 ", target_currency, " costs: ",
# CHFvalue, "CHF and 1 ", base_currency, " costs: ",
# FOREIGNvalue_round, target_currency)
data = [{'date': date,
'currency': target_currency,
'exchangerate': foreign_value_round}]
exchange_rates.append(data)
# Print the Dictionary:
print(exchange_rates)
return(exchange_rates)

View File

@ -6,6 +6,7 @@ register = template.Library()
@register.filter()
def boldcoffee(value):
# currency_of_customer = request.session['currency']
return '%s !!gefiltert!!' % value
# excample filter: {{ article.price_in_chf|boldcoffee }}

View File

@ -1,5 +1,5 @@
from django.shortcuts import render
import datetime
from datetime import datetime
from django.views.generic.edit import UpdateView
from django.core.urlresolvers import reverse_lazy
from currencies.models import (ExchangeRate,
@ -25,82 +25,111 @@ def currency_update(request):
def currencies(request):
# this function fetches the data from exchange_rates.py
# evaluates if the values are already stored and
# prepares the view all dynamicaly.
# It can grow in terms of more Currencies over time automaticaly.
today = ''
raw_data = []
"""this function fetches the data from swiss national bank
evaluates if the values are already stored and
prepares a view all dynamicaly.
It can grow in terms of more Currencies over time automaticaly."""
# Namespaces
ns = {'rdf': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
'none': 'http://purl.org/rss/1.0/',
'dc': 'http://purl.org/dc/elements/1.1/',
'dcterms': 'http://purl.org/dc/terms/',
'cb': 'http://www.cbwiki.net/wiki/index.php/Specification_1.2/'
}
SNB_URL = 'https://www.snb.ch/selector/de/mmr/exfeed/rss'
try:
raw_data, today = exchange_rates.get_exchange_rate()
urlsocket = exchange_rates.get_rss(SNB_URL)
except Exception as e:
print('views raw_data: ', raw_data, 'error:', e) # assert False
message_no = "Already querried today: "
print('currencies/views get_rss(): ', urlsocket, 'error:', e)
try:
rss_tree = exchange_rates.parse_rss(urlsocket)
except Exception as e:
print('currencies/views parse_rss(): ', rss_tree, 'error:', e)
try:
raw_data = exchange_rates.get_exchange_rate(rss_tree, ns)
except Exception as e:
print('currencies/views get_exchange_rate(): ', raw_data, 'error:', e)
today = datetime.now().strftime("%Y-%m-%d")
message_no = "Already querried: "
length_of_message_no = len(message_no)
message_yes = " Updated successfully: "
length_of_message_yes = len(message_yes)
# raw_data can be empty. In this case skip:
if raw_data:
# if raw_data is not empty iterate over items in it:
for currency, rate in raw_data.items():
# check for already existing exrates per day and add
# to message that its already been saved.
if ExchangeRate.objects.filter(
date__date=today,
name__name=currency):
message_no += currency + ", "
else:
if ExchangeRate_date.objects.filter(date=today)[:1]:
# if data and currency is not yet present, save it.
try:
# A: https://stackoverflow.com/a/27802801/4061870
# lustigerweise gibt .values() den value und die id
# zurück. Ohne .values() gibts nur den "value"
date_dict = ExchangeRate_date.objects.filter(
date=today).values()
except Exception as e:
print('exdate_exists %s (%s) on %s'
% (e, type(e), today))
for one_obj_of_list in raw_data:
for exchange_rate_of_one_day in one_obj_of_list:
date = exchange_rate_of_one_day['date']
currency = exchange_rate_of_one_day['currency']
exchangerate = exchange_rate_of_one_day['exchangerate']
# check for already existing exrates per day and add
# to message that its already been saved.
if ExchangeRate.objects.filter(
date__date=date,
name__name=currency):
message_no += currency + ' on ' + date + ", "
else:
if ExchangeRate_date.objects.filter(date=date)[:1]:
# if data and currency is not yet present, save it.
try:
# A: https://stackoverflow.com/a/27802801/4061870
# lustigerweise gibt .values() den value und die id
# zurück. Ohne .values() gibts nur den "value"
date_dict = ExchangeRate_date.objects.filter(
date=date).values()
except Exception as e:
print('currencies/views/exdate_exists \
%s (%s) on %s'
% (e, type(e), today))
else:
try:
exdate = ExchangeRate_date.objects.create(
date=date)
exdate.save()
except Exception as e:
print('currencies/views/exdate_not_exists \
%s (%s) for %s'
% (e, type(e), date))
if ExchangeRate_name.objects.filter(
name=currency)[:1]:
# if data and currency is not yet present, save it.
try:
name_dict = ExchangeRate_name.objects.filter(
name=currency).values()
except Exception as e:
print('currencies/views/exname_exists \
%s (%s) on %s'
% (e, type(e), currency))
else:
try:
exname = ExchangeRate_name.objects.create(
name=currency)
exname.save()
except Exception as e:
print('currencies/views/exname_not_exists \
%s (%s) on %s'
% (e, type(e), currency))
try:
exdate = ExchangeRate_date.objects.create(
date=today)
exdate.save()
except Exception as e:
print('exdate_not_exists %s (%s) for %s'
% (e, type(e), today))
if ExchangeRate_name.objects.filter(
name=currency)[:1]:
# if data and currency is not yet present, save it.
try:
name_dict = ExchangeRate_name.objects.filter(
name=currency).values()
except Exception as e:
print('exname_exists %s (%s) on %s'
% (e, type(e), currency))
else:
try:
exname = ExchangeRate_name.objects.create(
name=currency)
exname.save()
except Exception as e:
print('exname_not_exists %s (%s) on %s'
% (e, type(e), currency))
try:
# save item to where id's match.
exrate = ExchangeRate.objects.create(
# name_id=name_id,
name_id=ExchangeRate_name.objects.get(
name=currency).id,
# date_id=date_id,
date_id=ExchangeRate_date.objects.get(
date=today).id,
exchange_rate_to_chf=rate,
)
exrate.save()
message_yes += currency + ", "
# save item to where id's match.
exrate = ExchangeRate.objects.create(
# name_id=name_id,
name_id=ExchangeRate_name.objects.get(
name=currency).id,
# date_id=date_id,
date_id=ExchangeRate_date.objects.get(
date=date).id,
exchange_rate_to_chf=exchangerate,
)
exrate.save()
message_yes += currency + ' on ' + date + ", "
except Exception as e:
print('exrate_create %s (%s) on %s for %s'
% (e, type(e), currency, today))
except Exception as e:
print('currencies/views/exrate_create \
%s (%s) on %s for %s'
% (e, type(e), currency, date))
# prepare messages:
# python can not swap a char insinde a sting so i have
@ -112,11 +141,12 @@ def currencies(request):
message_yes = message_yes.replace(",", "!", 1) # replace f. , with !
message_yes = message_yes[::-1] # invert the string back
# here we evaluate what kind of message is valid:
if len(message_no) > 24 and len(message_yes) > 23:
if len(message_no) > length_of_message_no\
and len(message_yes) > length_of_message_yes:
message = message_no + message_yes
elif len(message_no) > 24:
message = message_no
elif len(message_yes) > 23:
elif len(message_yes) > 18:
message = message_yes
elif datetime.datetime.today().isoweekday() == 6:
message = """Die Abfrage wurde ohne ergebniss beendet.
@ -130,8 +160,6 @@ def currencies(request):
"""
else:
message = """Die Abfrage wurde ohne ergebniss beendet.
Kann es sein dass die SNB aufgrund eines Feiertages
geschlossen ist?
"""
# know we can query our data for presentaton:
currency_list = ExchangeRate.objects.all()

View File

@ -22,7 +22,7 @@
</td>
<td scope="col">{{ article.category }}</td>
<td scope="col">{{ article.stock }}</td>
<td scope="col">{{ article.price_in_chf|boldcoffee }}</td>
<td scope="col">{{ article.price_in_chf }}</td>
</tr>
{% endfor %}
</table>