Cliquez ici pour un aperçu de nos efforts.
La dernière fois a terminé jusqu'à 4. Je vais donc faire l'original, qui est le but initial. .. Ce que nous créons est une application qui lit un fichier JSON qui suppose une configuration spécifique et visualise le contenu. Certains produits peuvent générer des fichiers de configuration en JSON pour le travail, il serait donc pratique que je puisse les visualiser (éventuellement dans la sortie Excel). Je sens que ça existe même si je n'y arrive pas, mais je vais le faire comme une pratique.
--Dispose d'un mécanisme pour télécharger des fichiers JSON --Parse le fichier JSON téléchargé et visualiser (une partie de) le contenu
Créons une application qui répond à cette exigence. En fait, il est plus facile d'imaginer utiliser le fichier json que vous souhaitez réellement utiliser, mais comme il contient des informations qui ne peuvent pas être diffusées en dehors de l'entreprise, utilisez plutôt celui publié sur Internet. http://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/gettingstartedguide/samples/moviedata.zip Un fichier JSON qui enregistre les titres de films, les classements, les genres, etc.
Même si vous voulez le visualiser, vous devez d'abord comprendre de quel type de structure il s'agit (je pense ...). Je ne sais pas ce que feront les professionnels, mais en tant qu'amateur, j'utilise cette extension Chrome. http://jsoneditoronline.org/
Il y a un guimon qui se demande si cela convient à la visualisation, mais il y a une volonté de le rendre plus semblable à Excel, ou enfin d'Excel.
L'exemple JSON est un fichier qui résume les informations sur le film. Je voudrais en faire une image de la sortie suivante.
Title | Rating | Genre | Actors |
---|---|---|---|
Prisoners | 8.2 | Crime | Hugh Jackman |
Drama | Jake Gyllenhaal | ||
Thriller | Viola Davis |
Le nombre de genre et d'acteurs est variable.
Comme environnement, utilisez la même VM que celle utilisée jusqu'à Dernière fois et divisez uniquement l'environnement virtuel Python (virtualenv).
Utilisez la structure de répertoires suivante.
Je vais omettre la partie qui est presque la même que la dernière fois.
réduction
Cette fois, la partie qui définit la variable est séparée dans un autre fichier.
config.py
# -*- coding: utf-8 -*-
# configuration
DATABASE = '/root/jsonparser/db/jsonparser.db'
DEBUG = True
UPLOAD_FOLDER = '/root/jsonparser/uploads/'
ALLOWED_EXTENSIONS = set(['json'])
SECRET_KEY = 'development key'
Les variables définies ici sont accessibles à partir du fichier py qui a importé ce fichier par la procédure suivante.
Créez l'instruction SQL suivante et appelez-la depuis app.py comme précédemment pour initialiser la base de données. Le processus d'initialisation de app.py à ce stade est le même que la dernière fois, il est donc omis.
schema.sql
drop table if exists file_entries;
create table file_entries (
id integer primary key autoincrement,
filename string not null,
desc string,
created string
);
Ajoutez la fonction suivante à app.py. Une fonction qui vérifie l'extension des fichiers téléchargés.
def allowed_file(filename):
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in app.config[
'ALLOWED_EXTENSIONS']
Ensuite, la fonction de téléchargement des fichiers et la fonction de suppression (entrée) du fichier téléchargé.
@app.route('/', methods=['GET', 'POST'])
def inputfile():
cur = g.db.execute(
'select filename,desc,created,id from file_entries order by created desc')
entries = [dict(filename=row[0], desc=row[1], created=row[
2], id=row[3]) for row in cur.fetchall()]
if request.method == 'POST':
# check if the post request has the file part
if 'file' not in request.files:
flash('No file part')
return redirect(url_for('inputfile'))
file = request.files['file']
# if user does not select file, browser also
# submit a empty part without filename
if file.filename == '':
flash('No selected file')
return redirect(url_for('inputfile'))
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
current = datetime.now()
g.db.execute('insert into file_entries (filename,desc,created) values (?, ?, ?)',
[file.filename, request.form['desc'], current])
g.db.commit()
message = "File upload finished successfully."
return redirect(url_for('inputfile', message=message))
current = datetime.now().strftime('%Y/%m/%d %H:%M')
message = request.args.get('message', '')
if not message:
message = "Current time is " + current
return render_template('inputfile.html', message=message, entries=entries)
@app.route('/delete', methods=['GET', 'POST'])
def delete():
id = request.args.get('value')
g.db.execute("delete from file_entries where id = ?", [id])
g.db.commit()
return redirect(url_for('inputfile'))
Le modèle original
layout.html
<!doctype html>
<html>
<head>
<title>JSON Parser</title>
<script type="text/javascript" src="../static/js/jquery-3.1.1.min.js"></script>
<link rel=stylesheet type=text/css href="{{ url_for('static', filename='style.css') }}">
{% block head %}{% endblock %}
</head>
<div class=page>
<h1>JSON Parser</h1>
<div class=metanav>
<a href="{{ url_for('inputfile') }}">Home</a>
</div>
{% for message in get_flashed_messages() %}
<div class=flash>{{ message }}</div>
{% endfor %}
{% block body %}{% endblock %}
</div>
</html>
Écran de téléchargement, de liste et de suppression de fichiers.
inputfile.html
{% extends "layout.html" %}
{% block body %}
<p>{{ message }} </p>
<form action="{{ url_for('inputfile') }}" method=post class=add-entry enctype="multipart/form-data">
File: <input type="file" name="file" size="30"/><br>
Description: <input type="text" name="desc" size="30" placeholder="Description"/><br>
<input type="submit" />
</form>
<ul class=entries>
{% for entry in entries %}
<li><h2>{{ entry.filename }}</h2>
<p><a href="{{url_for('delete',value=entry.id)}}">Effacer</a></p>
Description: {{ entry.desc }}<br>
Created: {{ entry.created }}<br>
{% else %}
<li><em>Il n'y a pas encore d'entrées.</em>
{% endfor %}
</ul>
{% endblock %}
Téléchargez le fichier à partir de l'action de l'élément de formulaire. Utilisez url_for pour accéder à la fonction inputfile (URL correspondante) dans app.py.
La feuille de style est omise car elle utilise celle du didacticiel telle quelle.
Lorsque vous arrivez à ce stade, démarrez l'application et accédez-y depuis le navigateur,
[root@cnenarnupgd1c jsonparser]# . env/bin/activate
(env) [root@cnenarnupgd1c jsonparser]#
(env) [root@cnenarnupgd1c jsonparser]# python app.py
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger pin code: 173-472-212
Lorsque vous téléchargez le fichier,
Jusqu'à ce point, c'est OK.
Le kick sera l'écran qui affiche la liste des fichiers téléchargés créés précédemment. Ajoutez un lien appelé «Configurer la confirmation» à l'écran et passez-le à la fonction appelée sortie avec le nom du fichier cible.
inputfile.html(partie)
<ul class=entries>
{% for entry in entries %}
<li><h2>{{ entry.filename }}</h2>
<p><a href="{{url_for('output',value=entry.filename)}}">Vérification de la configuration</a></p>
<p><a href="{{url_for('delete',value=entry.id)}}">Effacer</a></p>
Description: {{ entry.desc }}<br>
Created: {{ entry.created }}<br>
{% else %}
<li><em>Il n'y a pas encore d'entrées.</em>
{% endfor %}
</ul>
La fonction reçue est la suivante. En fonction du nom de fichier passé comme valeur, lisez le fichier json, transmettez-le au module pour analyse et transmettez l'objet renvoyé au modèle.
app.py(partie)
from parse_json import parse_json
@app.route('/output')
def output():
fname = request.args.get('value').replace(' ','_')
fpath = app.config['UPLOAD_FOLDER'] + fname
jsonfile = open(fpath,'r')
config = json.load(jsonfile)
output = parse_json(config)
return render_template('output.html', entries=output)
Vient ensuite le module d'analyse.
parse_json.py
import sys
def parse_json(config):
# Initialize array
# Create (num of movie) * empty {}
arr = []
for i in range(len(config)):
try:
arr[i].append({})
except IndexError:
arr.append({})
except:
print 'Unexpected Error:',sys.exc_info()[0]
# Populate arr
for idx,movie in enumerate(config):
try:
arr[idx].update({'title': movie.get('title')})
arr[idx].update({'rank': movie.get('info').get('rank')})
arr[idx].update({'genres': movie.get('info').get('genres')})
arr[idx].update({'actors': movie.get('info').get('actors')})
if movie.get('info').get('genres') and movie.get('info').get('actors'):
arr[idx].update({'rowspan': max(len(movie.get('info').get('genres')),len(movie.get('info').get('actors')))})
elif not movie.get('info').get('genres') and movie.get('info').get('actors'):
arr[idx].update({'rowspan': len(movie.get('info').get('actors'))})
elif movie.get('info').get('genres') and not movie.get('info').get('actors'):
arr[idx].update({'rowspan': len(movie.get('info').get('genres'))})
else:
arr[idx].update({'rowspan': 1})
except:
print 'Unexpected Error:', sys.exc_info()[0]
pass
return arr
Pour être honnête, je pense qu'il est possible de traiter avec du code Flask (sur HTML) à ce niveau, mais je vais y réfléchir plus tard et le faire de cette façon. De plus, une variable appelée rowspan est calculée en cours de route, mais il s'agit d'une variable qui indique le nombre de lignes nécessaires pour chaque film.
Cliquez ici pour un modèle pour passer l'objet généré.
output.html
{% extends "layout.html" %}
<h1>Movies</h1>
{% block body %}
<table ~~~ style="table-layout:fixed;width:100%;" border = "3">
<colgroup>
<col style="width:25%;">
<col style="width:25%;">
<col style="width:25%;">
<col style="width:25%;">
</colgroup>
<tr bgcolor="skyblue">
<td ~~~ style="word-wrap:break-word;">Title</td>
<td ~~~ style="word-wrap:break-word;">Rank</td>
<td ~~~ style="word-wrap:break-word;">Genres</td>
<td ~~~ style="word-wrap:break-word;">Actors</td>
</tr>
{% for entry in entries %}
{% for i in range(entry.rowspan) %}
<tr>
{% if i == 0 %}
<td ~~~ style="word-wrap:break-word;" rowspan = "{{ entry.rowspan }}">{{ entry.title }}</td>
<td ~~~ style="word-wrap:break-word;" rowspan = "{{ entry.rowspan }}">{{ entry.rank }}</td>
{% endif %}
{% if entry.genres[i] %}
<td ~~~ style="word-wrap:break-word;">{{ entry.genres[i] }}</td>
{% else %}
<td ~~~ style="word-wrap:break-word;" bgcolor="black">Empty</td>
{% endif %}
{% if entry.actors[i] %}
<td ~~~ style="word-wrap:break-word;">{{ entry.actors[i] }}</td>
{% else %}
<td ~~~ style="word-wrap:break-word;" bgcolor="black">Empty</td>
{% endif %}
</tr>
{% endfor %}
{% else %}
<tr><td ~~~ style="word-wrap:break-word;" columnspan="4">No entry here.</td></tr>
{% endfor %}
</table>
{% endblock %}
Pour les entrées qui nécessitent 4 lignes, affichez le titre et le classement ensemble sur 4 lignes. Remplissez les cellules restantes.
En outre, la largeur de cellule est fixe afin que les chaînes de caractères longues soient enveloppées. Il fait référence à ce qui suit. http://qiita.com/n_s_y_m/items/cb29d730e63772b02475
La sortie sera la suivante. Quel que soit le nombre d'éléments, il est proche de l'image.
En fait, ce serait bien de pouvoir trier par colonne, mais une fois que cela est fait. La source entière, etc. est publiée ci-dessous. https://github.com/KI1208/jsonparser.git
À première vue, il y a beaucoup de problèmes et de demandes à l'heure actuelle, mais je vais fermer les yeux et en faire un prochain numéro.
Recommended Posts