Asevastos Δημοσ. 2 Ιανουαρίου 2019 Δημοσ. 2 Ιανουαρίου 2019 (επεξεργασμένο) Καλησπέρα, έχω εδώ μία βάση Mongo και με Flask εμφανίζω στον Browser τα περιεχόμενα της. class Get1(Resource): def get(self): self.db = pymongo.MongoClient("mongodb://127.0.0.1:27017")["NickDB"]["coll"] return dumps(self.db.find()) Ο κώδικας είναι απλός και μικρός. Το πρόβλημα; Αυτή η άτιμη η dumps μου πετάει στο browser output αντίστροφες καθέτους ('\') σε όλα τα σημεία του αρχείου. Δηλαδή, το αρχικό JSON αρχείο έχει αυτό: { "_id" : { "$oid" : "5b0847b2e866f42f049b741a" }, "retweeted_status" : { "extended_tweet" Στον browser το output που βγάζει είναι αυτό: "[{\"_id\": {\"$oid\": \"5b0847b2e866f42f049b741a\"}, \"retweeted_status\": {\"extended_tweet\" Γενικά, η μορφή που τα εμφανίζει είναι πολύ άσχημη και θα ήθελα γενικότερα να κάνω κάποιου είδους μορφοποίηση για να εμφανίζονται πιο ωραία τα documents στο collection. Ο φίλος μου που δουλεύει Django το έκανε γράφοντας(και διόρθωσε και το πρόβλημα με τις καθέτους έτσι) HttpResponse(dumps(res), content_type="application/json", status=200) Εγώ όμως δε ξέρω πώς κάνω κάτι αντίστοιχο. Any ideas για το πώς μπορώ να εμφανίσω τη DB μου στον Browser(φτιάχνω REST API) χωρίς προβλήματα; Επεξ/σία 2 Ιανουαρίου 2019 από Asevastos
Predatorkill Δημοσ. 2 Ιανουαρίου 2019 Δημοσ. 2 Ιανουαρίου 2019 (επεξεργασμένο) 12 λεπτά πριν, Asevastos είπε Καλησπέρα, έχω εδώ μία βάση Mongo και με Flask εμφανίζω στον Browser τα περιεχόμενα της. class Get1(Resource): def get(self): self.db = pymongo.MongoClient("mongodb://127.0.0.1:27017")["NickDB"]["coll"] return dumps(self.db.find()) Ο κώδικας είναι απλώς και μικρός. Το πρόβλημα; Αυτή η άτιμη η dumps μου πετάει στο browser output αντίστροφες καθέτους ('\') σε όλα τα σημεία του αρχείου. Δηλαδή, το αρχικό JSON αρχείο έχει αυτό: { "_id" : { "$oid" : "5b0847b2e866f42f049b741a" }, "retweeted_status" : { "extended_tweet" Στον browser το output που βγάζει είναι αυτό: "[{\"_id\": {\"$oid\": \"5b0847b2e866f42f049b741a\"}, \"retweeted_status\": {\"extended_tweet\" Γενικά, η μορφή που τα εμφανίζει είναι πολύ άσχημη και θα ήθελα γενικότερα να κάνω κάποιου είδους μορφοποίηση για να εμφανίζονται πιο ωραία τα documents στο collection. Ο φίλος μου που δουλεύει Django το έκανε γράφοντας(και διόρθωσε και το πρόβλημα με τις καθέτους έτσι) HttpResponse(dumps(res), content_type="application/json", status=200) Εγώ όμως δε ξέρω πώς κάνω κάτι αντίστοιχο. Any ideas για το πώς μπορώ να εμφανίσω τη DB μου στον Browser(φτιάχνω REST API) χωρίς προβλήματα; Γιατι θες να δειξεις raw json στον browser? Εκτος απο καποιες πολυ συγκεκριμενες περιπτωσεις δεν θα χρειαστει ποτε να κανεις κατι τετοιο. Το backslash το βγαζει για να κανει escape τα ““. Επισης γιατι σου επιστρεφει $oid μεσα στο _id; Επεξ/σία 2 Ιανουαρίου 2019 από Predatorkill
Asevastos Δημοσ. 2 Ιανουαρίου 2019 Μέλος Δημοσ. 2 Ιανουαρίου 2019 (επεξεργασμένο) Βασικά, με ενδιαφέρει να δείχνει τα contents της βάσης (τα οποία είναι imported json) στον browser. Υποτίθεται ότι είναι tweets και όταν βάζω στο browser το endpoint /tweets πρέπει να μου τα εμφανίζει. Είχα καταφέρει να τα εμφανίζω όμορφα, διαχωρισμένα σε μορφή MongoDB(εγγραφές η μία κάτω από την άλλη) με αυτόν τον κώδικα: def get(self): db = client.NickDB output = [] str = db.coll.find num = 1 for q in str(): output.append('{tweet_%d'%num) num+=1 output.append({ola_ta_fields_tou_kathe_tweet}) return jsonify(output) εδώ το πρόβλημα είναι άλλο. Ενώ εμφανίζονται όμορφα και ωραία, εάν υπάρχουν σε μία εγγραφή fields χωρίς τιμή, πετάει error. Όπως στη παρακάτω εικόνα στη 2η στήλη υπάρχουν πεδία retweeted_status χωρίς value. Αν πάω μέσα στην output.append να τα περάσω, πετάει κατευθείαν error ο browser. Πώς μπορώ να το διορθώσω αυτό με το '\' ξέρεις; Αυτό με το $oid δε το ξέρω, στην δεύτερη μορφή που σου αναφέρω δεν έχω τέτοιο θέμα(2η φωτό). 2η εικόνα Επεξ/σία 2 Ιανουαρίου 2019 από Asevastos
pmav99 Δημοσ. 2 Ιανουαρίου 2019 Δημοσ. 2 Ιανουαρίου 2019 First things first: Όταν ζητάς βοήθεια, να ποστάρεις ολόκληρο τον κώδικα μέσα σε code tags ή σε κάποιο gist. Όταν παίρνεις μήνυμα λάθους να ποστάρεις όλο το Traceback. Από εκεί και πέρα, ο κώδικας που πόσταρες έχει διάφορα θεματάκια, τόσο όσον αφορά την python όσο και γενικότερες πρακτικές. Googl-αρε με τη σειρά: How to enumerate in python https://stackoverflow.com/questions/9109333/is-it-bad-practice-to-use-a-built-in-function-name-as-an-attribute-or-method-ide What is connection pooling and why should I use it Pymongo + Connection pooling μετά από αυτά, για να έρθουμε στο 1o πρόβλημα σου. Έχεις ένα web server στον οποίο κάνεις Requests. O web server σου επιστρέφει Responses. Από τι αποτελείται ένα response; Εδώ η απάντηση. Ο client του API σου, ο browser δηλαδή στην περίπτωσή σου, χρησιμοποιεί ένα header από το Response για να αποφασίσει ποιο representation που θα σου δείξει. Ποιο header είναι αυτό; Το ίδιο ακριβώς που έθεσε και ο φίλος σου. Αν διαβάσεις λίγο θα δεις ότι η συνάρτηση jsonify(), που είναι ένα wrapper γύρω από το json.dumps(), θέτει το content-type από μόνη της. Για αυτό και η δεύτερη εκδοχή δουλεύει ενώ η πρώτη όχι. Για να το καταλάβεις ακόμα καλύτερα, φτιάξε μια 2η μέθοδο που θα επιστρέφει τα ίδια data με την πρώτη αλλά με διαφορετικό content-type για να δεις διαφορές. Για το δεύτερο πρόβλημά σου, πόσταρε traceback και sample data. ΥΓ. Άμα έχεις χρόνο, διάβασε και το RFC: https://www.w3.org/Protocols/rfc2616/rfc2616.html 1
Asevastos Δημοσ. 2 Ιανουαρίου 2019 Μέλος Δημοσ. 2 Ιανουαρίου 2019 (επεξεργασμένο) Ευχαριστώ πολύ για το αναλυτικό post. Μου έχει μείνει από το SO λίγους μήνες πριν που έβαλα ολόκληρο τον κώδικα και μου το έκαναν edit γιατί είχε περιττές λεπτομέρειες(imports κ.λπ). Για αυτό και εστίασα τώρα μόνο στο συγκεκριμένο κομμάτι. Εν πάσει περιπτώσει, πριν από τη προαναφερθείσα κλάση υπάρχουν imports και τα εξής δύο για το initialization του Flask: app = Flask(__name__) api = Api(app) Είδα τις 4 αναφορές που πρότεινες, το 2ο είναι pretty clear. Άθελα, μπορεί να χρησιμοποίησα κάποιο name που καλό είναι να μη χρησιμοποιείται. Για το 1, αναφέρεσαι στον counter που έβαλα στη for loop; Για τα 3-4, κατάλαβα την έννοια αλλά δε καταλαβαίνω το λάθος μου. Η κλήση στη βάση γίνεται μία φορά συνολικά, δεν είναι ότι καλώ δύο φορές ξεχωριστά επειδή έχω 2 διαφορετικούς τρόπους κλήσης. Κατάλαβα και το κομμάτι με τα requests, ευχαριστώ. Αν και τα είχα δει ήδη πριν ξεκινήσω αλλά πολύ επιφανειακά. Τώρα, για το δεύτερο πρόβλημα, ο κώδικας είναι ο εξής: from bson import json_util from flask import Flask, request from flask_restful import Resource, Api from pymongo import MongoClient import pymongo import simplejson as json from bson.json_util import dumps from flask import jsonify from pprint import pprint import requests app = Flask(__name__) api = Api(app) class Get1(Resource): def get(self): db = client.NickDB output = [] str = db.coll.find num = 1 for q in str(): output.append('{tweet_%d'%num) num+=1 output.append({'_id':q['id'],'id_str': q['id_str'],'truncated':q['truncated'],'in_reply_to_status_id':q['in_reply_to_status_id'],'quote_count':q['quote_count'],'retweeted':q['retweeted'],'retweet_count':q['retweet_count'],'timpestamp_ms':q['timestamp_ms'],'favorite_count':q['favorite_count'],'created_at':q['created_at'],'coordinates':q['coordinates'],'in_reply_to_user_id':q['in_reply_to_user_id'],'favorited':q['favorited'],'entities':q['entities'],'in_reply_to_screen_name':q['in_reply_to_screen_name'],'id':q['id'],'contributors':q['contributors'],'user':q['user'],'source':q['source'],'is_quote_status':q['is_quote_status'],'in_reply_to_status_id_str':q['in_reply_to_status_id_str'],'reply_count':q['reply_count'],'filter_level':q['filter_level'],'place':q['place'],'in_reply_to_user_id_str':q['in_reply_to_user_id_str'],'geo':q['geo'],'text':q['text'],'lang':q['lang']}) return jsonify(output) api.add_resource(Get1, '/tweets') if __name__ == '__main__': app.run(debug=True) Τέσσερα πράγματα: Τα imports είναι πολλά γιατί δοκίμασα πολλά πράγματα και δε τα "καθάρισα" ακόμη. Κατάφερα να το λύσω, πάλι με append αλλά αυτή τη φορά αντί να περνάω ένα-ένα τα fields απλώς πέρασα ως όρισμα το documents (όπου documents=db.find()). Ο τρόπος που εισάγω στην output τα δεδομένα είναι τρομερά μπακάλικος, I know. Αλλά το tutorial που κοιτούσα έτσι το έκανε(μόνο που αυτός είχε να εμφανίσει 2 fields, όχι καμιά 25αριά). Για το traceback, παραθέτω τι μου εμφανίζει εάν στο κώδικα μου γράψω output.append({...,'retweet_status':q['retweet_status'],...}) Spoiler Traceback (most recent call last): File "C:\Users\Nick\PycharmProjects\untitled4\venv\newenv\newempty\lib\site-packages\flask\app.py", line 2309, in __call__ return self.wsgi_app(environ, start_response) File "C:\Users\Nick\PycharmProjects\untitled4\venv\newenv\newempty\lib\site-packages\flask\app.py", line 2295, in wsgi_app response = self.handle_exception(e) File "C:\Users\Nick\PycharmProjects\untitled4\venv\newenv\newempty\lib\site-packages\flask_restful\__init__.py", line 269, in error_router return original_handler(e) File "C:\Users\Nick\PycharmProjects\untitled4\venv\newenv\newempty\lib\site-packages\flask\app.py", line 1741, in handle_exception reraise(exc_type, exc_value, tb) File "C:\Users\Nick\PycharmProjects\untitled4\venv\newenv\newempty\lib\site-packages\flask\_compat.py", line 34, in reraise raise value.with_traceback(tb) File "C:\Users\Nick\PycharmProjects\untitled4\venv\newenv\newempty\lib\site-packages\flask\app.py", line 2292, in wsgi_app response = self.full_dispatch_request() File "C:\Users\Nick\PycharmProjects\untitled4\venv\newenv\newempty\lib\site-packages\flask\app.py", line 1815, in full_dispatch_request rv = self.handle_user_exception(e) File "C:\Users\Nick\PycharmProjects\untitled4\venv\newenv\newempty\lib\site-packages\flask_restful\__init__.py", line 269, in error_router return original_handler(e) File "C:\Users\Nick\PycharmProjects\untitled4\venv\newenv\newempty\lib\site-packages\flask\app.py", line 1718, in handle_user_exception reraise(exc_type, exc_value, tb) File "C:\Users\Nick\PycharmProjects\untitled4\venv\newenv\newempty\lib\site-packages\flask\_compat.py", line 34, in reraise raise value.with_traceback(tb) File "C:\Users\Nick\PycharmProjects\untitled4\venv\newenv\newempty\lib\site-packages\flask\app.py", line 1813, in full_dispatch_request rv = self.dispatch_request() File "C:\Users\Nick\PycharmProjects\untitled4\venv\newenv\newempty\lib\site-packages\flask\app.py", line 1799, in dispatch_request return self.view_functions[rule.endpoint](**req.view_args) File "C:\Users\Nick\PycharmProjects\untitled4\venv\newenv\newempty\lib\site-packages\flask_restful\__init__.py", line 458, in wrapper resp = resource(*args, **kwargs) File "C:\Users\Nick\PycharmProjects\untitled4\venv\newenv\newempty\lib\site-packages\flask\views.py", line 88, in view return self.dispatch_request(*args, **kwargs) File "C:\Users\Nick\PycharmProjects\untitled4\venv\newenv\newempty\lib\site-packages\flask_restful\__init__.py", line 573, in dispatch_request resp = meth(*args, **kwargs) File "C:\Users\Nick\PycharmProjects\untitled4\Projectia.py", line 35, in get output.append({'_id':q['retweet_status'],'id_str': q['id_str'],'truncated':q['truncated'],'in_reply_to_status_id':q['in_reply_to_status_id'],'quote_count':q['quote_count'],'retweeted':q['retweeted'],'retweet_count':q['retweet_count'],'timpestamp_ms':q['timestamp_ms'],'favorite_count':q['favorite_count'],'created_at':q['created_at'],'coordinates':q['coordinates'],'in_reply_to_user_id':q['in_reply_to_user_id'],'favorited':q['favorited'],'entities':q['entities'],'in_reply_to_screen_name':q['in_reply_to_screen_name'],'id':q['id'],'contributors':q['contributors'],'user':q['user'],'source':q['source'],'is_quote_status':q['is_quote_status'],'in_reply_to_status_id_str':q['in_reply_to_status_id_str'],'reply_count':q['reply_count'],'filter_level':q['filter_level'],'place':q['place'],'in_reply_to_user_id_str':q['in_reply_to_user_id_str'],'geo':q['geo'],'text':q['text'],'lang':q['lang']}) KeyError: 'retweet_status' Επεξ/σία 2 Ιανουαρίου 2019 από Asevastos
pmav99 Δημοσ. 2 Ιανουαρίου 2019 Δημοσ. 2 Ιανουαρίου 2019 (επεξεργασμένο) how to ask good questions 101 Πρέπει να μάθεις να φτιάχνεις ένα Minimal Working Example (mwe). Η έμφαση είναι εξίσου στο minimal όσο και στο working. Για το minimal, όση περισσότερη εμπειρία αποκτάς τόσο πιο εύκολο θα είναι να καταλαβαίνεις τι αποτελεί χρήσιμο context και τι όχι. Αν δεν είσαι σίγουρος, καλύτερα περισσότερο context παρά λιγότερο. Παρόλα αυτά είναι good manners να δείξεις ότι έκανες προσπάθεια να το κρατήσεις minimal και ότι δεν αντέγραψες απλά ό,τι είχες στον editor σου. https://en.wikipedia.org/wiki/Minimal_working_example https://stackoverflow.com/help/mcve Το παράδειγμα που έβαλες στο προηγούμενο post δεν είναι ούτε minimal, αλλά ούτε και working. Που ορίζεται πχ το "client"? Μόλις παει ο κώδικας στο db = client.NickDB θα πετάξει NameError 1. ναι για το counter λεω. H function που θες είναι η enumerate() 2. 99% όταν βλέπω str() σκέφτομαι ένα κενό string και όχι το wrapper object του cursor της mongo. 3-4. Αυτό ξεφεύγει λίγο από το πλαίσιο της άσκησης σου, αλλά στο ανέφερα γιατί είναι bad practice και γιατί φαίνεσαι να ψάχνεσαι λίγο. H απάντηση είναι στο FAQ της pymongo. Εσύ φτιάχνεις ένα νεό instance της pymongo.MongoClient() αντί να χρησιμοποιεις το ίδιο. Σκέψου πως θα το κάνεις να ξαναχρησιμοποιείται το ίδιο instance. Για να ελέγξεις αν είναι το ίδιο instance ή όχι μπορείς να χρησιμοποιήσεις την συνάρτηση id(). Πχ client1 = pymongo.MongoClient(...) client2 = pymongo.MongoClient(...) print(id(client1)) print(id(client2)) Tα Requests/Responses και γενικότερα το HTTP κοίτα να τα καταλάβεις καλά. Αν κάτι έχεις να πάρεις από τις ασκήσεις αυτές, αυτό είναι. Τα υπόλοιπα (flask, python κτλ) είναι implementation details (χωρίς να σημαίνει ότι δεν έχουν την αξία τους). 41 λεπτά πριν, Asevastos είπε output.append('{tweet_%d'%num) αυτή η αγκύλη τι είναι; edit Για να καταλάβεις γιατί παίρνεις KeyError δώσε ένα print(q.keys()) πριν το δεύτερο append() Επεξ/σία 2 Ιανουαρίου 2019 από pmav99
Asevastos Δημοσ. 6 Ιανουαρίου 2019 Μέλος Δημοσ. 6 Ιανουαρίου 2019 Understood το μήνυμα για το mwe. Για την enumerate έχεις δίκιο απλώς εκείνη τη στιγμή εφάρμοζα ότι ήξερα από τις άλλες γλώσσες για να έχω τον counter. Για το όνομα συμφωνώ ότι ήταν φάουλ το str. Γενικά, όπως ίσως καταλαβαίνεις, απλώς θέλω να τελειώνω με την εργασία για να περάσω το μάθημα. Ωστόσο, συμφωνώ ότι η γνώση για τα requests (πέραν των πλαισίων της εργασίας) είναι MUST και ήταν καλή αφορμή η εργασία για να δουλέψω λίγο με αυτά στη πράξη (και να καταλάβω επιτέλους τι είναι το API). Η αγκύλη αφορά το συγκεκριμένο format με το οποίο πρέπει να εμφανίζονται τα data μου στο browser
pmav99 Δημοσ. 6 Ιανουαρίου 2019 Δημοσ. 6 Ιανουαρίου 2019 3 ώρες πριν, Asevastos είπε Η αγκύλη αφορά το συγκεκριμένο format με το οποίο πρέπει να εμφανίζονται τα data μου στο browser Δεν θα πρέπει να κλείνει; Υπόψιν, ενα ζεύγος από αγκύλες σε string έχει ειδικό νόημα στην python. θα χρειαστεί να το κάνεις escape.
Asevastos Δημοσ. 6 Ιανουαρίου 2019 Μέλος Δημοσ. 6 Ιανουαρίου 2019 Θα πρέπει να κλείνει στο τέλος των tweets. Αλήθεια; Δε ξέρω Oython, αναγκαστικά τη χρησιμοποιώ για την εργασία. Ευχαριστώ για τη διευκρίνιση.
Προτεινόμενες αναρτήσεις
Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε
Πρέπει να είστε μέλος για να αφήσετε σχόλιο
Δημιουργία λογαριασμού
Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!
Δημιουργία νέου λογαριασμούΣύνδεση
Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.
Συνδεθείτε τώρα