Restful API Python Flask Postman

Django, Flask, Bottle, WSGI, CGI…
Antworten
mignoncharly
User
Beiträge: 8
Registriert: Freitag 6. September 2019, 07:23

Donnerstag 19. September 2019, 08:05

Moin!
schon seit 1 Woche versuche ich eine einfache CRUD RESTful API zu bauen ohne Erfolg. Also wenn ich in im cmd User und Post anlegen kann ich die wieder listen (User.query.all()) aber wenn ich versuche alle Users via meine Function get_all_users() erhalte ich diese Fehlermeldung: TypeError: 'Engine' object is not callable
hier ist mein user data-Model


in init.py

Code: Alles auswählen

#modules importieren

# Create Flask app
app = Flask(__name__)

# Flask-SQLAlchemy settings
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db' # File-based SQL database
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # Avoids SQLAlchemy warning

# Initialize Flask-SQLAlchemy
db = SQLAlchemy(app)

# Initialize Flask-API
api = Api(app)

# Import routes
from webapp import routes
models.py

Code: Alles auswählen

class User(db.Model, UserMixin):
    
   # __tablename__ = 'user' (habe auch damit versucht aber ändert sich nicht)

    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(20), unique=True, nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)
    image_file = db.Column(db.String(20), nullable=False, default='default.jpg')
    password = db.Column(db.String(60), nullable=False)
    posts = db.relationship('Post', backref='author', lazy=True)

    def __repr__(self):
        return f"User('{self.username}', '{self.email}', '{self.image_file}')"
and hier in routes.py

Code: Alles auswählen

@app.route('/api/users/', methods = ['GET'])
def get_all_user():
    
    engine = create_engine(app.config['SQLALCHEMY_DATABASE_URI'])
    
    conn = engine.connect()
    
    #metadata = db.Metadata()
    
    user = db.engine('user', autoload=True, autoload_with=engine, engine_options=None)

    req = db.select([user])
    
    result = conn.execute(req)
    
    row_result = result.query.all()
    
    return jsonify(row_result)

    conn.close()
in Postman mit dem URL : http://127.0.0.1:5000/api/users/
erhalte ich diese Fehlermeldung : TypeError: 'Engine' object is not callable // Werkzeug Debugger

Danke für Ihre Hilfe

LG
mignoncharly
Sirius3
User
Beiträge: 10595
Registriert: Sonntag 21. Oktober 2012, 17:20

Donnerstag 19. September 2019, 09:11

Wenn Du Fehlermeldungen hier postest, dann bitte mit komplettem Traceback, sonst muß man raten, wo der Fehler wahrscheinlich auftritt. Auch wäre es praktisch, alle Importe mit anzugeben und nicht nur einen Kommentar.

Warum glaubst Du denn, das Du db.engine benutzen mußt und was soll diese Zeile machen? Woher hast Du das?

Die Funktion `get_all_user` ist wegen der vielen Leerzeilen extrem schlecht lesbar. Alles was nach `return` kommt, wird nie ausgeführt.

Das `password`-Feld in `User` ist mit 60 Zeichen etwas kurz. Mit Salt und 128Bit Hash belegen, hex-kodiert schon 64 Zeichen und eigentlich will man heutzutage 256bit verwenden, dazu noch Method, Iterationen, etc., da ist man leicht bei 150 Zeichen. Naja, mit base64-Kodierung sind es ein paar weniger.
mignoncharly
User
Beiträge: 8
Registriert: Freitag 6. September 2019, 07:23

Donnerstag 19. September 2019, 10:45

Sirius3 hat geschrieben:
Donnerstag 19. September 2019, 09:11
"Wenn Du Fehlermeldungen hier postest, dann bitte mit komplettem Traceback, sonst muß man raten, wo der Fehler wahrscheinlich auftritt. Auch wäre es praktisch, alle Importe mit anzugeben und nicht nur einen Kommentar."
------>
ok alles klar.

Traceback (most recent call last):
File "C:\Users\..\Desktop\flask_app\env\lib\site-packages\flask\app.py", line 2463, in __call__
return self.wsgi_app(environ, start_response)
File "C:\Users\..\Desktop\flask_app\env\lib\site-packages\flask\app.py", line 2449, in wsgi_app
response = self.handle_exception(e)
File "C:\Users\..\Desktop\flask_app\env\lib\site-packages\flask_restful\__init__.py", line 269, in error_router
return original_handler(e)
File "C:\Users\..\Desktop\flask_app\env\lib\site-packages\flask\app.py", line 1866, in handle_exception
reraise(exc_type, exc_value, tb)
File "C:\Users\..\Desktop\flask_app\env\lib\site-packages\flask\_compat.py", line 39, in reraise
raise value
File "C:\Users\..\Desktop\flask_app\env\lib\site-packages\flask\app.py", line 2446, in wsgi_app
response = self.full_dispatch_request()
File "C:\Users\..\Desktop\flask_app\env\lib\site-packages\flask\app.py", line 1951, in full_dispatch_request
rv = self.handle_user_exception(e)
File "C:\Users\..\Desktop\flask_app\env\lib\site-packages\flask_restful\__init__.py", line 269, in error_router
return original_handler(e)
File "C:\Users\..\Desktop\flask_app\env\lib\site-packages\flask\app.py", line 1820, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "C:\Users\..\Desktop\flask_app\env\lib\site-packages\flask\_compat.py", line 39, in reraise
raise value
File "C:\Users\..\Desktop\flask_app\env\lib\site-packages\flask\app.py", line 1949, in full_dispatch_request
rv = self.dispatch_request()
File "C:\Users\..\Desktop\flask_app\env\lib\site-packages\flask\app.py", line 1935, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "C:\Users\..\Desktop\flask_app\webapp\routes.py", line 264, in get_all_user
user = db.engine('user', autoload=True, autoload_with=engine, engine_options=None)
TypeError: 'Engine' object is not callable


import in routes.py

Code: Alles auswählen

import io, json, os, secrets, requests
from flask import (abort, flash, jsonify, make_response, redirect,
                   render_template, request, send_file, url_for)
from PIL import Image
from sqlalchemy.exc import IntegrityError
from werkzeug.security import check_password_hash, generate_password_hash
from werkzeug.utils import secure_filename
from flask_httpauth import HTTPBasicAuth
from flask_login import current_user, login_required, login_user, logout_user
from flask_restful import Api, Resource, abort, reqparse
from pygal.style import DefaultStyle as DS
from pygal.style import LightenStyle as LS
from webapp import app, bcrypt, db
from flask_sqlalchemy import SQLAlchemy
from webapp.forms import (LoginForm, PostForm, RegistrationForm,
                          UpdateAccountForm)
from webapp.models import Post, User
from sqlalchemy import *
import in init.py

Code: Alles auswählen

import os
from flask import Flask
from flask_babelex import Babel
from flask_bcrypt import Bcrypt
from flask_login import LoginManager
from flask_mail import Mail, Message
from flask_restful import Api, Resource, abort, reqparse
from flask_sqlalchemy import SQLAlchemy
from lepl.apps.rfc3696 import Email
from werkzeug.utils import secure_filename
import in models.py

Code: Alles auswählen

from datetime import datetime
from webapp import db, login_manager
from flask_login import UserMixin
#import sqlalchemy as db
import flask_sqlalchemy
from flask_sqlalchemy import SQLAlchemy

"Warum glaubst Du denn, das Du db.engine benutzen mußt und was soll diese Zeile machen? Woher hast Du das?"
------>
to execute raw SQL in Flask-SQLAlchemy app laut Documentation


"Die Funktion `get_all_user` ist wegen der vielen Leerzeilen extrem schlecht lesbar. Alles was nach `return` kommt, wird nie ausgeführt."
------>
verstehe nicht was du mit "vielen Leerzeilen" meinst! coonect.close ist wie session.commit() und muss nach return ausgeführt

"Das `password`-Feld in `User` ist mit 60 Zeichen etwas kurz. Mit Salt und 128Bit Hash belegen, hex-kodiert schon 64 Zeichen und eigentlich will man heutzutage 256bit verwenden, dazu noch Method, Iterationen, etc., da ist man leicht bei 150 Zeichen. Naja, mit base64-Kodierung sind es ein paar weniger."
------>
danke , ich ändere es
Benutzeravatar
__blackjack__
User
Beiträge: 4243
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Donnerstag 19. September 2019, 11:14

@mignoncharly: Nach einem ``return`` wird das ``conn.close()`` aber nicht mehr ausgeführt. Das `Connection`-Objekt kann man aber mit ``with`` zusammen verwenden.

Und `engine` ist halt nicht aufrufbar. Das steht auch nirgends in der Dokumentation. Woher hast Du das denn? Da sollte dann auch stehen auf welchem Objekt/Datentyp eine Methode mit den angegeben Argumenten existiert.
“Give a man a fire and he's warm for a day, but set fire to him and he's warm for the rest of his life.”
— Terry Pratchett, Jingo
DasIch
User
Beiträge: 2519
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Donnerstag 19. September 2019, 15:15

Du solltest auf keinen Fall eine Engine für jeden Request erstellen. Die sollte man einmal erstellen und für jeden Request wiederverwenden. Flask-SQLAlchemy tut dies für dich auch implizit. Dahinter verbirgt sich nämlich ein Connection Pool. Es ist recht teuer eine Verbindung zu einer Datenbank zu erstellen (involviert einen fork bei postgres, erstellen eines threads bei MySQL) und damit wird die CPU auf dem Datenbankserver sehr schnell zum Bottleneck, deswegen tut man dies nur selten und hält offene Verbindungen in einem Pool zur späteren Wiederverwendung.
Benutzeravatar
__blackjack__
User
Beiträge: 4243
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Donnerstag 19. September 2019, 15:29

Den `password`-Wert vom User möchte man vielleicht auch nicht über die API herausgeben. Und wenn man zum `User` bzw. der Tabelle Werte Attribute/Spalten hinzufügt, dann werden die auch automatisch von dem API-Endpunkt verschickt. An der Stelle sollte man expliziter sein was genau man von dem Ergebnis an den Client ausliefert.

So etwas wie `marshmallow` kann da hilfreich sein.
“Give a man a fire and he's warm for a day, but set fire to him and he's warm for the rest of his life.”
— Terry Pratchett, Jingo
mignoncharly
User
Beiträge: 8
Registriert: Freitag 6. September 2019, 07:23

Donnerstag 19. September 2019, 16:01

Danke an @Daslch für diesen Hinweis
Danke auch an @__blackjack__ natürlich will ich nicht das Password via API abfragen nur username and email ...
Antworten