How to store python script data into Django model - python

I've already written a script that parses JSON data from a particular url and stores them into a list. After that I'm able to pass that as an argument to be displayed in my template.
My end goal is to display a table on the template from this JSON data (of which I have currently included only one parameter), for which I believe I need to pass that list into a Django Model.
def index(request):
is_cached = ('raw_json' in request.session)
print(is_cached)
if not is_cached:
# g = {'starttime': '2014-01-01', 'endtime': '2014-01-02', 'minmagnitude': '5'}
g=''
url1 = ul.urlencode(g)
# print(url1)
main_api = 'https://earthquake.usgs.gov/fdsnws/event/1/query?format=geojson&'
final_url = main_api + url1
# print(final_url)
raw_json = requests.get(final_url).json()
string_json = json.dumps(raw_json)
# print(raw_json)
with open('test.txt', 'w') as file:
file.write(string_json)
count = raw_json['metadata']['count']
print('Count: ' + str(count))
maglist = []
placelist = []
for cou in range(0, count):
mag = (raw_json['features'][cou]['properties']['mag'])
maglist.append(mag)
# magdict = dict(list(enumerate(maglist)))
place = (raw_json['features'][cou]['properties']['place'])
placelist.append(place)
# placedict = dict(list(enumerate(placelist)))
# print(placedict)
with open('test2.txt', 'w+') as t1:
for features in raw_json['features']:
coordinates = (features['geometry']['coordinates'])
id = (features['id'])
t1.write("id: %s \n" % (id))
t1.write("coordinates: %s \n" % (coordinates))
# print(singfeature)
for properties, value in features['properties'].items():
t1.write("%s : %s \n" % (properties, value))
# t1.write("\n")
# print (maglist)
args = {'magni': maglist}
print (args)
return render(request, 'earthquake/index.html', args)
The template receives this data with a simple for loop as follows:
{% block content %}
{% for item in magni %}
<p>{{ item }}</p>
{% endfor %}
{% endblock %}
To which the result shows up as follows:
As mentioned previously, I need to display a filterable/sortable table with this parameter (along with other parameters too), so that the end-user may view the data as needed.
I'm quite new to Django.

Related

in flask, give user a list of options to select from with arbitrary length

i'm new to flask, and python in general so let me know if i'm doing anything wrong...
i'm learning by building a web-app. my current goal is to make playlists on spotify from user input. everything i'm trying to do here i have already made work for myself in pycharm scripts, it's the web-dev and interacting with the user part i'm struggling with atm.
i want to:
take input (artist name) from user (done)
send artist name as search term to spotify and return a list of dictionaries of matching artists. these dictionaries have a bunch of info including 'name' and 'id'. (done)
display the names in the result dicts to the user who will select which to include in their playlist. (please help!)
use the list of ids which match the selected artists to interogate spotify for all the tracks by those artists and create a playlist.
i just need help with #3
i have a functioning flask / bootstrap web-app that allows user to authenticate via spotify and input the artist name and which conducts the search and returns the list of dicts. i'm using flask forms to take the input, and assume i'll use another to display the results as radio-button fields for user to select one/many from but the list is of arbitrary length and i don't know how to pass this dynamically to the html. the dictionary i make from the spotify response has names as keys and ids as values - i only want to pass the names to the user to select from, but i'll need to maintain acces to the dictionaries so i can retrieve the ids for the spotify search later...
i've added the code i use to make and populate the playlists in case anyone likes/wants it/has any comments.
my code:
python
class ArtistTracksForm(FlaskForm):
artist = StringField('Who are you searching for?')
submit = SubmitField('search')
...
#app.route('/artist_playlist', methods=['GET', 'POST'])
def artist_playlist():
# prepare spotify
cache_handler = sp.cache_handler.CacheFileHandler(cache_path=session_cache_path())
auth_manager = sp.oauth2.SpotifyOAuth(cache_handler=cache_handler)
if not auth_manager.validate_token(cache_handler.get_cached_token()):
return redirect('/')
spotify = sp.Spotify(auth_manager=auth_manager)
#get form
form = ArtistTracksForm()
if form.validate_on_submit():
artist = form.artist.data
results = spotify.search(q=artist, type='artist')
items = results['artists']['items']
#make a dictionary of results
names_list = {}
for item in items:
artist_name=item['name']
artist_id = item['id']
names_list.update({artist_name:artist_id})
# temp. make a string of keys (artist names) by unpacking the dict
name_string = ''
for name in [*names_list]:
name_string = name_string + name + ", "
return name_string
#app.route('/handle_data')
def handle_data():
data_handler = request.form['APform']
i don't really know what i'm doing with the 'action=' and handle_data(): parts but can work that out, it's the dynamically sized list of fields and interacting between python and html i'm really perplexed by
html.j2:
{% extends "layout.html.j2" %}
{% block content %}
<div class="content-section">
<form method="POST" action="{{ url_for('handle_data')}}" name=APform>
{{ form.hidden_tag() }}
<fieldset class="form-group">
<legend class="border-bottom mb-4">Artist Playlists</legend>
<div class="form-group">
{{ form.artist.label(class="form-control-label") }}
{{ form.artist(class="form-control form-control-lg") }}
</div>
</fieldset>
<div class="form-group">
{{ form.submit(class="btn btn-outline-info") }}
</div>
</form>
</div>
{% endblock content %}
any input greatly appreciated, i've been searching google and SO for hours now...
thanks
here's the python code i use to get all the tracks from all the albums that an artist has at least one track on, and make a playlist on my spotify account for each artist.... max tracks is 10k so it makes multiple if that is exceeded... in case that's of interest to anyone who read this far... i've been making sql databases and inserting huge spotify playlists into my account. XD
def get_releases(list_of_artist_dicts, form='dict'):
"""takes list of artist dicts
return list of dicts (form = 'dict)
or list of id strings 'form='list'"""
album_list = []
for artist_dict in list_of_artist_dicts: # iterate artist dicts
artist = artist_dict['artist']
artist_id = artist_dict['artist_id']
results = sp.artist_albums(artist_id) # call spotify for artist_album details
releases = results['items']
while results['next']: # check for more pages
results = sp.next(results)
releases.extend(results['items'])
for release in releases:
album_group = release['album_group']
album_type = release['album_type']
album = release['name']
album_id = release['id']
spotify_album_url = release['external_urls']['spotify']
release_date = release['release_date']
release_date_precision = release['release_date_precision']
release_date = date_stripper(release_date,
release_date_precision) # convert date string to datetime obj, insert spurious 1s if precision < day
album_artist = release['artists'][0]['name'] # get (first) album artist details
album_artist_id = release['artists'][0]['name']
release_dict = {
'artist': artist,
'artist_id': artist_id,
'album_artist': album_artist,
'album_artist_id': album_artist_id,
'album': album,
'album_id': album_id,
'album_group': album_group,
'album_type': album_type,
'release_date': release_date,
'release_date_precision': release_date_precision,
'spotify_album_url': spotify_album_url
}
if form == 'dict':
album_list.append(release_dict)
if form == 'list':
album_list.append(release_dict['album_id'])
return album_list
def get_tracks(list_of_artist_dicts, form=dict):
""" takes list of artist dicts, returns a list of track dicts, or track ids if form=list """
track_dicts_list = []
for artist_dict in list_of_artist_dicts:
album_list = []
artist = artist_dict['artist']
artist_id = artist_dict['artist_id']
artist_dict = [artist_dict]
release_list = get_releases(artist_dict, 'dict')
for release in release_list:
album_id = release['album_id']
album_list.append(album_id)
for offset in range(0, len(album_list), 20):
batch = album_list[offset:offset + 20]
result = sp.albums(batch)
albums_batch = result['albums']
for batched_album in albums_batch:
album = batched_album['name']
album_id = batched_album['id']
# release_date = batched_album['release_date'] tracks dont have release dates?
album_type = batched_album['album_type']
track_count = len(batched_album['tracks']['items'])
for act in batched_album['artists']:
album_artist = act['name']
album_artist_id = act['id']
track_id_list = []
for track in batched_album['tracks']['items']:
track_artist = track['artists'][0]['name']
track_artist_id = track['artists'][0]['id']
title = track['name']
spotify_track_url = track['external_urls']['spotify']
track_id = track['id']
track_id_list.append(track_id)
track_dict = {
'artist': artist,
'artist_id': artist_id,
'album_artist': album_artist,
'album_artist_id': album_artist_id,
'album': album,
'album_id': album_id,
'track_artist': track_artist,
'track_artist_id': track_artist_id,
'title': title,
'track_id': track_id,
'album_type': album_type,
'spotify_track_url': spotify_track_url
}
track_dicts_list.append(track_dict)
if form == 'list':
return track_id_list
return track_dicts_list
def make_playlist(playlist_name='python_play'):
"""creates a playlist on user account, returns playlist_id"""
user = sp.me()['id']
return sp.user_playlist_create(user=user,name=playlist_name)['id']
def add_to_playlist(playlist_id, track_list):
sp.playlist_add_items(items=track_list, playlist_id=playlist_id)
def check_playlist_exists(term):
""" searches current user's playlists for playlist_name = term returns true if exists"""
limit = 50
offset = 0
current_names = []
for step in range (0,1000,50):
current_playlists = sp.current_user_playlists(limit=limit, offset=offset)['items']
for playlist in current_playlists:
current_names.append(playlist['name'])
offset += 50
if term in current_names:
return True
def get_alpha(my_dict):
sorter = my_dict['name']
sortering = sorter.lower()
return sortering
def create_playlist_all_artist_tracks(artist_list):
artist_list.sort(reverse=True, key=get_alpha) # reverse sort list so playlists will be front-sorted in spotify
already = []
making = []
for artist in artist_list:
artist_name = artist['name']
artist_id = artist['id']
playlist_name = f"{artist_name} and friends - all tracks from all releases including features_on- made in python"
if check_playlist_exists(playlist_name):
print (f"ALREADY EXISTS - {playlist_name}")
already.append(playlist_name)
else:
print (f'PLAYLIST NOT FOUND making playlist "{playlist_name}"')
making.append(playlist_name)
artist_tracks = get_track_id_list_artist(artist_id)
if len(artist_tracks) < 10000:
playlist_id = make_playlist(playlist_name)
start = 0
for step in range(start, len(artist_tracks), 100):
batch = artist_tracks[start:start + 100]
add_to_playlist(playlist_id, batch)
start += 100
else:
count = 1
begin = 0
start=0
for section in range(begin, len(artist_tracks), 10000):
playlist_id = make_playlist(f"{playlist_name} number {count}")
chunk = artist_tracks[begin:begin + 10000]
for step in range(start, len(chunk), 100):
batch = artist_tracks[start:start + 100]
add_to_playlist(playlist_id, batch)
start += 100
count+=1
begin += 10000
print ("PLAYLISTS ALREADY MADE:")
pprint (already)
print ("NEW PLAYLISTS CREATED :")
pprint (making)

Passing list dict to template not working django

I am trying to pass a list called eligable so that I can display on my website but when I run my website it does not display the list. I do not understand what is wrong.
code:
def specificDate(response):
empName = employeeName.objects.all()
eligable = []
if 'checkEmployee' in response.POST:
n = response.POST.get("nameEmployee")
specDate = response.POST.get("date")
if employeeName.objects.filter(employee=n).exists() and Name.objects.filter(date=specDate).exists():
emp = employeeName.objects.get(employee=n)
t = Name.objects.get(name=emp, date=specDate)
overT = Name.objects.filter(name=emp, overtime=True)
for item in overT:
eligable.append(item.date)
checkIn = t.timeIn.strftime("%H:%M:%S")
checkOut = t.timeOut.strftime("%H:%M:%S")
datee = datetime.strptime(specDate,'%Y-%m-%d')
print("Here:: ",t.date)
print("Month:: ",datee.month)
messages.info(response, checkIn + ' - ' + checkOut)
return redirect('/specificDate')
else:
messages.info(response, 'Name does not exist')
else:
pass
return render(response, "main/specificDate.html", context={"empName":empName, "eligable":eligable})
This is the html to print my list:
{% for item in eligable %}
<div class="pad3">
{{item}}
</div>
{% endfor %}
There are two return statements in your code:
return redirect('/specificDate')
and
return render(response, "main/specificDate.html", context={"empName":empName, "eligable":eligable})
The first one is just redirecting without populating context.
The second one does populate context but is reached only when eligable is empty.
I think changing the first return to the second one should solve it.
edit: and you are missing {% endfor %} here. But it should give you an error if you miss it in your complete code.

Render variables from a file

There is a file api.yml containing a config for ansible:
config/application.properties:
server.port: 6081
system.default.lang: rus
api.pdd.url: "http://{{ stage['PDD'] }}"
api.policy.alias: "integration"
api.order.url: "http://{{ stage['Order'] }}
api.foo.url: "http://{{ stage['FOO'] }}
There is a stage.yml containing the key and the stage values:
default_node:
Order: '172.16.100.40:8811'
PDD: '172.16.100.41:8090'
FOO: '10.100.0.11:3165
In fact, these files are larger and the 'stage' variables are also many.
My task is to parse api.yml and turn it into properties-config. The problem is that I can not pull up the values ​​{{stage ['value']}} I'm trying to do it this way:
stream = yaml.load(open('api.yml'))
result={}
result.update(stream['config/application.properties'])
context= yaml.load(open('stage.yml'))
stage={}
stage.update(context['default_node'])
text = '{% for items in result | dictsort(true)%} {{ items[0] }} = {{
items[1] }} {%endfor%}'
template = Template(text)
properti = (template.render(result=result, stage=stage))
At the output I get this:
server.port = 6081
system.default.lang = rus
api.pdd.url = http://{{ stage['PDD'] }}
api.policy.alias = integration
api.order.url = http://{{ stage['Order'] }}
api.foo.url = http://{{ stage['FOO'] }}
And you need to get this:
server.port = 6081
system.default.lang = rus
api.pdd.url = 172.16.100.41:8090
api.policy.alias = "integration"
api.order.url = 172.16.100.40:8811
api.foo.url = 10.100.0.11:3165
Can I do it with jinja or ansible lib?
Sorry for my bad english
Following this approach, you would need to treat api.yml as a template itself and render it. Otherwise, jinja2 will treat it as a simple value of the property. Something like this would do:
import yaml
from jinja2 import Environment, Template
import json
stream = yaml.load(open('api.yml'))
result={}
result.update(stream['config/application.properties'])
context= yaml.load(open('stage.yml'))
stage={}
stage.update(context['default_node'])
text = """{% for items in result | dictsort(true)%} {{ items[0] }} = {{ items[1] }} {%endfor%}"""
#Then render the results dic as well
resultsTemplate = Template(json.dumps(result))
resultsRendered = json.loads( resultsTemplate.render(stage=stage) )
template = Template(text)
properti = (template.render(result=resultsRendered, stage=stage))
After this you will see the wanted values in the properti var:
' api.foo.url = http://10.100.0.11:3165 api.order.url = http://172.16.100.40:8811 api.pdd.url = http://172.16.100.41:8090 api.policy.alias = integration server.port = 6081 system.default.lang = rus'
It would be nice though if jinja2 was able to render recursively. Maybe spending some time working out with the globals and shared modes of the Environment this can be achieved.
Hope this helps.

pass data from Django to amchart JS with JSON

I want to pass data from my Django view to my html and then take the data to my chart js or pass the data directly to my amchart.
views.py:
def nodo_detail(request,nodo_id):
El_Nodo = Nodo.objects.get(pk=nodo_id)
all_nodos = Nodo.objects.order_by('pk').all()
var = Variable()
v = dir(var)
elemento = El_Nodo.variable_set.order_by('pk').all()
watts = elemento.last().Watts
prefix = ''
chartData = "["
for t in elemento:
chartData += prefix
chartData += "{\n"
chartData += " date: "
chartData += '"' + str(t.Data_time.year) + "-"
chartData += str(t.Data_time.month) + "-"
chartData += str(t.Data_time.day) + " "
chartData += str(t.Data_time.hour) + ":"
chartData += str(t.Data_time.minute) + ":"
chartData += str(t.Data_time.second) + '"' + ",\n"
chartData += " value:"
chartData += str(t.Watts) + ",\n"
chartData += " volume: "
chartData += str(t.Watts) + "\n }"
prefix = ", "
chartData += "]"
context = {'El_Nodo': El_Nodo,
'all_nodos': all_nodos,
'v': v,
'watts': watts,
'chartData':chartData,
"asdf":json.dumps(chartData)}
return render(request, 'inicio/detail.html', context)
The data that I want to pass is chartData, with the for loop I try to do the JSON format also I try the JSON python librery.
detail.html:
{% block Stock %}
<input type="hidden" id="stock" value="{{chartData}}"> <!-- or asdf-->
{% endblock%}
amchartjs:
var chartData = JSON.parse(document.getElementById("stock").value);
// or directly
var chartData = JSON.parse('{{ chartData }}');//or asdf
I understand that with this way it is necessary refresh the whole web page to view new data, Also like to know how to do it dynamic? Thanks and sorry for bad english
Make an AJAX call that returns an array, and you populate this in JavaScript. This implies to make a JSON view that returns a JSON array. Like this:
class QueryResultsView(generic.TemplateView):
template_name='your_template.html'
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super(QueryResultsView, self).get_context_data(**kwargs)
# Create a variable you fill
context['my_big_sql'] = MyModel.objects.filter(blabla=blibli)
return context
And from there, in your template file (this is your template file, not a JavaScript file) general_study_results.html add something like:
<script>
var myData =
{% for row in my_big_sql %}
{{ row.column }}{% if not forloop.last %},{% endif %}
{% endfor %};
</script>
And then you have all your data in your HTML file ready to be used via amchartjs or any library you want.

Write reusable view

I have this function that takes a QuerySet and renders a CSV. I would like to write a view that renders a template with options to download different CSV files (Basically for anything defined in models.py)
# Exports CSV file using a QuerySet
def export(qs, fields=None, file_name='data'):
model = qs.model
response = HttpResponse(mimetype='text/csv')
response['Content-Disposition'] = 'attachment; filename={0}-{1}.csv'.format(file_name, str(datetime.date.today()))
writer = csv.writer(response)
# Write headers to CSV file
if fields:
headers = fields
else:
headers = []
for field in model._meta.fields:
headers.append(field.name)
writer.writerow(headers)
# Write data to CSV file
for obj in qs:
row = []
for field in headers:
if field in headers:
val = getattr(obj, field)
if callable(val):
val = val()
row.append(val)
writer.writerow(row)
# Return CSV file to browser as download
return response
Currently I am writing a NON-reusable view:
def csv_of_surveys(request):
r = export(Survey.objects.all(), file_name='surveys')
return r
What can I do? My only idea was to send a code over and write a switch statement, so
{% url "csv_of" 0 %}
{% url "csv_of" 1 %}
{% url "csv_of" 2 %}
{% url "csv_of" 3 %}
Where 0, 1, 2 and 3 would correspond to downloading different things.
The new view would look something like:
def csv_of(request, code):
if code == 0:
r = export(Survey.objects.all(), file_name='surveys')
return r
elif code == 1:
r = export(User.objects.all(), file_name='teachers')
return r
elif code == 2:
r = export(Student.objects.all(), file_name='students')
return r
# ...
else:
return HttpResponseRedirect('/')
Is there a better way?
Create a dictionary that maps the given code to the associated object, then reduce all the if statements you have into one if. For the file name, it looks like you're doing the same thing each time, which is pluralizing and lowercasing it, in which case you should set it in model._meta.verbose_name_plural, then access that when you need it:
file_codes = {0:Survey,1:User...}
def csv_of(request, code):
if int(code) in file_codes.keys():
obj = file_codes[int(code)]
return export(obj.objects.all(), file_name = obj._meta.verbose_name_plural.title())
else:
return HttpResponseRedirect('/')

Categories