Sortable tables in Django - python

I read some of the other posts about this and some recommendations involved javascript and using other libraries. I did something quick by hand, but I'm new to Django and Python for that matter so I'm curious if this isn't a good way to do it.
HTML
<table>
<tr>
<td>To</td>
<td>Date</td>
<td>Type</td>
</tr>
{% for record in records %}
<tr><td>{{record.to}}</td><td>{{record.date}}</td><td>{{record.type}}</td></tr>
{% endfor %}
</table>
View
headers = {'to':'asc',
'date':'asc',
'type':'asc',}
def table_view(request):
sort = request.GET.get('sort')
if sort is not None:
if headers[sort] == "des":
records = Record.objects.all().order_by(sort).reverse()
headers[sort] = "asc"
else:
records = Record.objects.all().order_by(sort)
headers[sort] = "des"
else:
records = Record.objects.all()
return render_to_response("table.html",{'user':request.user,'profile':request.user.get_profile(),'records':records})

Looks good to me. I'd suggest one minor refactoring in the view code:
headers = {'to':'asc',
'date':'asc',
'type':'asc',}
def table_view(request):
sort = request.GET.get('sort')
records = Record.objects.all()
if sort is not None:
records = records.order_by(sort)
if headers[sort] == "des":
records = records.reverse()
headers[sort] = "asc"
else:
headers[sort] = "des"
return render_to_response(...)

My first port of call for sortable tables is usually sorttable.js ( http://www.kryogenix.org/code/browser/sorttable/ )
or sortable-table ( http://yoast.com/articles/sortable-table/ )

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)

python new line from array

I am using Jinja template in the frontend and in my backend I am using python using which I have an array which is of type string:
#app.route('/', methods=['POST'])
def upload_image():
match = ''
if 'files[]' not in request.files:
flash('No file part')
#file stuff
discription = ""
for file in files:
if file and allowed_file(file.filename):
#OCR related stuffs
for i in range(0, output_ocr_len):
#preprocessing
for index, row in df.iterrows():
if cord_len > 0:
height = result_img.shape[0]
width = result_img.shape[1]
for elements in range(0, cord_len):
char_length = []
predicted_pattern_category = numpy.append(
predicted_pattern_category, 'Misdirection')
[char_length.append(x)
for x in predicted_pattern_category if x not in char_length]
your_predicted_pattern_category = str(char_length)
char_length = []
predicted_pattern_type = numpy.append(
predicted_pattern_type, 'Visual Interference')
[char_length.append(x) for x in predicted_pattern_type if x not in char_length]
your_predicted_pattern_type = "" + str(char_length)
for i in range(0,len(char_length)):
print("from ML :-",char_length[i])
index_of_key = key.index(char_length[i])
discription = discription + "" + value[index_of_key]
print(discription)
match = str(match) + " "
else:
char_length = []
[char_length.append(x)
for x in predicted_pattern_category if x not in char_length]
your_predicted_pattern_category = str(char_length)
if len(your_predicted_pattern_category) < 3:
your_predicted_pattern_category=''
char_length = []
[char_length.append(x) for x in predicted_pattern_type if x not in char_length]
your_predicted_pattern_type = str(char_length)
if len(your_predicted_pattern_type) < 3:
your_predicted_pattern_type=''
for i in range(0,len(char_length)):
print("from ML :-",char_length[i])
index_of_key = key.index(char_length[i])
discription = discription + '\r\n' + value[index_of_key]
print(discription)
return render_template('uploads/results.html',
msg='Processed successfully!',
match=match,
discription=discription
filenames=output_results
)
else:
return render_template('uploads/results.html',
msg='Processed successfully!',
match=match,
filenames=file_names)
To display the description, I am using Jinja template:
<tr>
<th class="table-info">Description</th>
<td>{{ description }}</td>
</tr>
I want that the description is printed on a new line whose content is present within the "value" variable.
currently the description renders together and not in a new line:
happy: is an emotionis: an extensionmy mood: relies on people
What I want is (every sentence in a new line)
happy: is an emotionis:
an extensionmy mood:
relies on people
From what I can tell, your code comes out on one line because you're repeatedly appending to the same variable. If you really want it all in one variable description, and on separate lines, I think you need a new line char, but I think HTML may ignore them...
For your fundamental problem, tables are designed to have information on separate rows. If you want the descriptions to be on separate lines, I think separate rows is the way to go. I would personally do the for-loop in the template instead of the backend.
{% for value in values %}
<tr>
<th class="table-info">Description</th>
<td>{{ value }}</td>
</tr>
{% endfor %}

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.

Django render Dictionary

Why cant i acsess the dict that i am making here:
def kalkuler(request):
fotlister = Produkt.objects.filter(under_kategori__navn__iexact="lister")
kalkuler = ProduktKalkureing.objects.all()
beregning = {}
if request.method == "POST":
omkrets = request.POST['omkrets']
print(omkrets)
for i in kalkuler:
kalk = math.ceil((int(omkrets)/i.lengde)*1000)
add = ({'produkt_tittel': i.produkt.produkt_tittel,
'produkt_bilde': i.produkt.produkt_bilde,
'produkt_info': i.produkt.produkt_info,
'produkt_link': i.produkt.produkt_link,
'pris_heltall': i.produkt.pris_heltall,
'antall_kalk': kalk,
'total_kost': kalk * i.produkt.pris_heltall
})
beregning.update(add)
print(beregning)
context = {'kalkuler': kalkuler, 'beregning': beregning}
return render(request, 'frontend/kalkuler/fotlist_kalkuler.html', context)
With the standard django code?
{% for b in beregning %}
{{b.produkt_bilde}}
{% endfor %}
Also when i make the dictionary it only adds the last value. How do i make it so it adds every value.
For what you seem to achieve, you need a list instead of a dict
def kalkuler(request):
...
beregning = []
...
beregning.append(add)
...

Jinja2 Extension Tag within another Tag

I'm tring to do something like this
{% mytag country "italy" year "2014" %}
workday
{% holyday %}
not workday
{% endmytag %}
But the holyday tag is optional.
This must work too:
{% mytag country "italy" year "2014" %}
workday
{% endmytag %}
I wrote the code
class MytagExtension(Extension):
tags = set(['mytag'])
def __init__(self, environment):
super(TranslateExtension, self).__init__(environment)
def parse(self, parser):
lineno = parser.stream.next().lineno
if parser.stream.skip_if('name:country'):
country= parser.parse_primary()
else:
country= nodes.Const(None)
if parser.stream.skip_if('name:year'):
year = parser.parse_primary()
else:
year = nodes.Const(None)
args = [country, year]
# body1 = parser.parse_statements(['name:holyday']) # not working :)
body = parser.parse_statements(['name:endmytag'], drop_needle=True)
return nodes.CallBlock(self.call_method('_helper', args),
[], [], body).set_lineno(lineno)
def _helper(self, country, year, caller):
etc ....
Is similar to a if else endif, but i didn't find the source code of the if tag (if it exists as Extension)
How can i do this?
Obviously in my _helper I need both the first and second branch because is there that I choose which one to show.
ok, here is an answer, it's not perfect and probably not the best, but it's something.
...
body = parser.parse_statements(
['name:endmytag', 'name:holyday'],
drop_needle=True
)
if not parser.stream.current.test('block_end'):
body.extend ( parser.parse_statements(['name:endmytag'], drop_needle=True) )
args = [
country,
year,
nodes.Const([y.data for x in body for y in x.nodes]), #I don't like this line a lot :)
]
return nodes.CallBlock(self.call_method('_helper', args),
[], [], body).set_lineno(lineno)
...
In this way in the _helper you will receive the third parameter (a list) and choose if return the first or the second element of this list.

Categories