Flask Error sqlalchemy.exc.OperationalError: (psycopg2.OperationalError) FATAL: role "admin" does not exist - flask-sqlalchemy

I cant make out what am doing wrong on flask webapp. I think it has to do with the database. I have postgres as the database below is the:
from flask_sqlalchemy import SQLAlchemy
from werkzeug import generate_password_hash, check_password_hash
db = SQLAlchemy()
# db.init_app(app)
class User(db.Model):
__tablename__ = 'users'
uid = db.Column(db.Integer, primary_key=True)
firstname = db.Column(db.String(100))
lastname = db.Column(db.String(100))
email = db.Column(db.String(120), unique=True)
passwdhash = db.Column(db.String(54))
def __init__(self, firstname, lastname, email, password):
self.firstname = firstname.title()
self.lastname = lastname.title()
self.email = email.lower()
self.set_password(password)
def set_password(self, password):
self.passwdhash = generate_password_hash(password)
def check_password_hash(self, password):
return check_password_hash(self.passwdhash, password)
Then I get this error...
sqlalchemy.exc.OperationalError
sqlalchemy.exc.OperationalError: (psycopg2.OperationalError) FATAL: role "pipi" does not exist
(Background on this error at: http://sqlalche.me/e/e3q8)

Related

drf-yasg Swagger documentation does not recognize authorized users

I've set up DRF-YASG documentation for my Django project, but the endpoints that require authentication show no parameters (fields to fill) even when logged as an authorized user.
swagger ui
In fact, none of my endpoints show their respective parameter fields in the UI.
Here are my REST_FRAMEWORK settings in settings.py :
REST_FRAMEWORK = {
"NON_FIELD_ERRORS_KEY": "errors",
"DEFAULT_AUTHENTICATION_CLASSES":(
"rest_framework.authentication.SessionAuthentication",
"rest_framework.authentication.TokenAuthentication"
),
"DEFAULT_PERMISSON_CLASSES":(
"rest_framework.permissions.IsAuthenticated"
)
}
and urls.py:
from django.contrib import admin
from django.urls import path, include, re_path
from EmployeeApp import views
from rest_framework import permissions
from drf_yasg.views import get_schema_view
from drf_yasg import openapi
schema_view = get_schema_view(
openapi.Info(
title="Snippets API",
default_version='v1',
description="Test description",
terms_of_service="https://www.google.com/policies/terms/",
contact=openapi.Contact(email="contact#snippets.local"),
license=openapi.License(name="BSD License"),
),
public=True,
permission_classes=[permissions.AllowAny],
)
urlpatterns = [
re_path(r'^swagger(?P<format>\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0),
name='schema-json'),
path('', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
re_path(r'^redoc/$', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),
path('admin/', admin.site.urls),
path('', views.api_home),
path('api/', include('EmployeeApp.urls')),
path('api/auth/', include('accounts.urls')),
]
I am using standard token authentication and here are my views.
from django.contrib.auth import authenticate
from .serializers import SignUpSerializer, UserSerializer
from rest_framework import generics, status
from rest_framework.response import Response
from rest_framework.request import Request
from rest_framework.views import APIView
from drf_yasg.utils import swagger_auto_schema
class SignUpView(generics.GenericAPIView):
serializer_class = SignUpSerializer
def post(self, request: Request):
data = request.data
serializer = self.serializer_class(data=data)
if serializer.is_valid():
serializer.save()
response = {
"message": "User Created Successfully",
"data": serializer.data
}
return Response(data=response, status=status.HTTP_201_CREATED)
return Response(data=serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class LoginView(APIView):
#swagger_auto_schema(request_body=UserSerializer)
def post(self, request: Request):
email = request.data.get('email')
password = request.data.get('password')
user = authenticate(email=email, password=password)
if user:
response = {
"message": "Login Successful",
"token": user.auth_token.key
}
return Response(data=response, status=status.HTTP_200_OK)
else:
return Response(data={"message": "Invalid username or password"},
status=status.HTTP_401_UNAUTHORIZED)
def get(self, request: Request):
content = {
"user": str(request.user),
"auth": str(request.auth)
}
return Response(data=content, status=status.HTTP_200_OK)
In Postman everything works as expected, but in the Swagger documentation the authenticated user is not being recognized and the parameter fields on endpoints are missing.
Not sure if these two issues are connected, but I would apprechiate any type of helpful input on this!
I have tested the endpoints with direct Postman requests and everything works as expected.
Here is the endpoint to Create(POST) a company as a logged User:
class CompanyCreate(APIView):
permission_classes = [IsAuthenticated]
#swagger_auto_schema(
operation_summary="Create a company",
operation_description="This allows logged-in user to create a company"
)
def post(self, request):
company_name_exists = Companies.objects.filter(company_name=request.data['company_name']).exists()
if company_name_exists:
raise ValidationError("Company with the same name already exists")
data = {**request.data, 'user_id': request.auth.user_id}
serializer = CompanySerializer(data=data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
and it's serializer:
class CompanySerializer(serializers.ModelSerializer):
user_id = serializers.IntegerField(write_only=True)
class Meta:
model = Companies
fields = ('user_id', 'company_name', 'company_description', 'company_logo')
def create(self, validated_data):
company, is_created = Companies.objects.get_or_create(
company_name=validated_data['company_name'],
company_description=validated_data['company_description'],
company_logo=validated_data['company_logo'],
user_id=validated_data['user_id'],
)
return company
I've attached `
#swagger_auto_schema(request_body=UserSerializer)
`
to my login endpoint and it gives me a filed to put the request body data in a JSON format.
enter image description here
that works, but it still does not show the Swagger UI parameter fields and the auth does not persist when I try to test endpoints that require it.

I am trying to authenticate the the USER model for Register and Login API in Django REST framework. I am getting the following error msg

"detail": "Authentication credentials were not provided."
I have tried all the available internet solutions, added the
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES':(
'knox.auth.TokenAuthentication',
'rest_framework.authentication.TokenAuthentication',
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
),
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAdminUser',
'rest_framework.permissions.IsAuthenticated',
]
}
But nothing worked in my favor. I am adding the serilizers.py and api.py files below. Please review them and tell me if there is some other way to fix this.
Following is the serializers.py file code
from rest_framework import serializers
from django.contrib.auth.models import User
from django.contrib.auth import authenticate
# User Serializer
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'username', 'email')
# Register Serializer
class RegisterSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'username', 'email', 'password')
extra_kwargs = {'password': {'write_only': True}}
def create(self, validated_data):
user = User.objects.create_user(validated_data['username'], validated_data['email'], validated_data['password'])
return user
# Login Serializer
class LoginSerializer(serializers.Serializer):
username = serializers.CharField()
password = serializers.CharField()
def validate(self, data):
user = authenticate(**data)
if user and user.is_active:
return user
raise serializers.ValidationError("Incorrect Credentials")
api.py is given as:
from rest_framework import generics, permissions
from rest_framework.response import Response
from knox.models import AuthToken
from .serializers import UserSerializer, RegisterSerializer, LoginSerializer
# Register API
class RegisterAPI(generics.GenericAPIView):
serializer_class = RegisterSerializer
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.save()
_, token = AuthToken.objects.create(user)[1]
return Response({
"user": UserSerializer(user, context=self.get_serializer_context()).data,
"token": token
})
# Login API
class LoginAPI(generics.GenericAPIView):
serializer_class = LoginSerializer
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.validated_data
_, token = AuthToken.objects.create(user)
return Response({
"user": UserSerializer(user, context=self.get_serializer_context()).data,
"token": token
})
# Get User API
class UserAPI(generics.RetrieveAPIView):
permission_classes = [
permissions.IsAuthenticated,
]
serializer_class = UserSerializer
def get_object(self):
return self.request.user
Urls.py
from django.urls import path, include
from .api import RegisterAPI, LoginAPI, UserAPI
from knox import views as knox_views
urlpatterns = [
path('api/auth/', include('knox.urls')),
path('api/auth/register', RegisterAPI.as_view()),
path('api/auth/login', LoginAPI.as_view()),
path('api/auth/user', UserAPI.as_view()),
path('api/auth/logout', knox_views.LogoutView.as_view(), name='knox_logout')
]
Please help me solve the issue. I am unable to make any post request on Postman and without Register, Login API won't work too.
To make the API public, you need to override your permissions in your settings. You should update your Views.
from rest_framework.permissions import AllowAny
# Register API
class RegisterAPI(generics.GenericAPIView):
serializer_class = RegisterSerializer
permission_classes = [AllowAny]
authentication_classes=() # To make sure no check if you send Authorization header to server
...
Apply for your Login view too.
Update your Register view to allow non logged in since you have 'rest_framework.permissions.IsAuthenticated' as a default permission
from rest_framework.permissions import AllowAny
# Register API
class RegisterAPI(generics.GenericAPIView):
serializer_class = RegisterSerializer
permission_classes = [AllowAny]
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = serializer.save()
_, token = AuthToken.objects.create(user)[1]
return Response({
"user": UserSerializer(user, context=self.get_serializer_context()).data,
"token": token
})

Why is SQLALCHEMY_DATABASE_URI set to "sqlite:///:memory:" when I set it to a path in my Config?

I am learning Flask by following Miguel Ginsberg mega tutorial chapter 4. When I run any Flask command from the Anaconda command panel I get an error that includes "Neither SQLALCHEMY_DATABASE_URI nor SQLALCHEMY_BINDS is set." and as a result an SQLite database is created in memory.
But I have created a Config object that sets SQLALCHEMY_DATABASE_URI, SECRET_KEY and SQLALCHEMY_TRACK_MODIFICATIONS, and have tested the python separately, and it all works.
I have tried everything I can think of including testing snippets of code separately, at least 8 hours searching the web, and trawling though Ginsberg's posts, nothing works. One person Graham (post #29) seems to have had the same problem but Ginsberg does not give a useful answer.
Here is my app init code
__init__
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from config import Config
app = Flask(__name__)
app.config.from_object(Config)
db = SQLAlchemy(app)
migrate = Migrate(app, db)
from app import routes, models
Here is my config, it works when run separately.
import os
basedir = os.path.abspath(os.path.dirname(__file__))
class Config(object):
SECRET_KEY = os.environ.get('SECRET_KEY') or 'you-will-never-guess'
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \
'sqlite:///' + os.path.join(basedir, 'app.db')
SQLALCHEMY_TRACK_MODIFICATIONS = False
For completeness here are my routes and models
from flask import render_template, flash, redirect, url_for
from app import app
from app.forms import LoginForm
#app.route('/')
#app.route('/index')
def index():
user = {'username': 'Miguel'}
posts = [
{
'author': {'username': 'John'},
'body': 'Beautiful day in Portland!'
},
{
'author': {'username': 'Susan'},
'body': 'The Avengers movie was so cool!'
}
]
return render_template('index.html', title='Home', user=user, posts=posts)
#app.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if form.validate_on_submit():
flash('Login requested for user {}, remember_me={}'.format(
form.username.data, form.remember_me.data))
return redirect(url_for('index'))
return render_template('login.html', title='Sign In', form=form)
and
from datetime import datetime
from app import db
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), index=True, unique=True)
email = db.Column(db.String(120), index=True, unique=True)
password_hash = db.Column(db.String(128))
posts = db.relationship('Post', backref='author', lazy='dynamic')
def __repr__(self):
return '<User {}>'.format(self.username)
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
body = db.Column(db.String(140))
timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
def __repr__(self):
return '<Post {}>'.format(self.body)
What should happen is that when I run a command like
> flask db init
or
> flask db migrate -m "users table"
the command should complete successfully because SQLALCHEMY_DATABASE_URI should equal the path of the app and the SQLite database should be app.db.
Instead I get error messages stating SQLALCHEMY_DATABASE_URI is not set and that therefore SQLALCHEMY_DATABASE_URI has been set to "sqlite:///:memory:"
My app needs a persistent database! Why isn't SQLALCHEMY_DATABASE_URI and SQLALCHEMY_TRACK_MODIFICATIONS being set?
this problem has gone away by itself, but since others may experience it I decided to describe the work-around I used to save them some frustration. I think the original problem may have been due to the sequence in which I was importing packages/modules and initiating classes/objects into my __init__ method.
The workaround is to comment out the original config statement and directly set the config variables, including the SQLite database, in __init__.
### app.config.from_object(Config)
app.config["SECRET_KEY"] = os.environ.get('SECRET_KEY') or 'you-will-never-guess'
app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get('DATABASE_URL') or \
'sqlite:///' + 'C:\\...path...\\app.db'
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
...
The workaround can probably be backed off a little by using
import os
basedir = os.path.abspath(os.path.dirname(__file__))
...
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \
'sqlite:///' + os.path.join(basedir, 'app.db')
...

How to make Flask Requests module authenticate?

I built my own API with flask, but now I'm trying to write a script to consume the API and the Requests module won't make it past the log in.
The Form
The form has jut a 'username' input, 'password', and I'm also using flask-wtf to implement csrf protection, so there is a 'csrf_token' hidden input.
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField
from wtforms.validators import DataRequired, Length
class LoginForm(FlaskForm):
username = StringField('Username', validators=[DataRequired(), Length(min=1, max=20)])
password = PasswordField('Password', validators=[DataRequired(), Length(min=1, max=25)])
The Route
#auth.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if request.method == 'GET':
return render_template('login.html', form=form)
elif request.method == 'POST':
if form.validate_on_submit():
credentials = {'username': request.form['username'],
'password': request.form['password']}
try:
r = requests.post('http://api.domain.com:80/authenticate', data=credentials)
response = r.json()
except Exception as e:
print('JSON Auth Error: {}'.format(e))
else:
if r.status_code is 200:
session['access_token'] = response['access_token']
session['refresh_token'] = response['refresh_token']
return redirect('/')
return render_template('login.html', form=form, error='invalid')
The API Endpoint
#api.route('/authenticate', methods=['POST'])
def authenticate():
# form data
username = request.form['username']
password = request.form['password']
# check if user exists
try:
user = User.query.filter_by(username=username).first()
except exc.SQLAlchemyError as e:
print(e)
if user and password == user.password:
tokens = generate_tokens()
return jsonify({'access_token': tokens['access'], 'refresh_token': tokens['refresh']}), 200
else:
return jsonify({'message': 'invalid login'}), 401
The API Resource Endpoint I am trying to access
#api.route('/pending', methods=['GET'])
#login_required
def pending():
The #login_required verification method
def tokens_valid():
if 'access_token' and 'refresh_token' in session:
# retrieve access and refresh tokens from session cookie
tokens = {'access_token': session['access_token'],
'refresh_token': session['refresh_token']}
# validate token endpoint
try:
r = requests.post('http://api.domain.com/validate', data=tokens)
response = r.json()
except Exception as e:
print('JSON Token Error: {}'.format(e))
else:
if r.status_code is 200:
if response['message'] == 'valid access token':
return True
elif response['message'] == 'new access token':
#set new tokens
session['access_token'] = response['access_token']
session['refresh_token'] = response['refresh_token']
return True
return False
What I have tried
v.1
def login():
credentials = {'username': 'username',
'password': 'password'}
s = requests.Session()
r = s.post('http://sub.domain.com/auth/login', data=credentials)
return s
v.2
def login():
login_form = requests.get('http://sub.domain.com/auth/login')
soup = BeautifulSoup(login_form.text, "html.parser")
csrf = soup.find('input', id='csrf_token').get('value')
credentials = {'username': 'username',
'password': 'password',
'csrf_token': csrf}
s = requests.Session()
r = s.post('http://sub.domain.com/auth/login', data=credentials)
return s
v.3
from flask import Flask, session
def login():
credentials = {'username': 'username',
'password': 'password'}
r = requests.post('http://api.domain.com/authenticate', data=credentials)
tokens = r.json()
session['access_token'] = tokens['access_token']
session['refresh_token'] = tokens['refresh_token']
So far I can get the '/authenticate' api endpoint to return my session tokens, but i can't access the protected resource because i can't seem to save them to my session any how.
Can anyone help me figure this out?

How use XML-RPC in odoo 9 version

I need simple example (module) how use odoo XML-RPC.
Does anyone have an example except on odoo web documentation.
Tnx
Below is the example for xml RPC, hope it will help you.
import xmlrpclib
username = 'admin' #the user
pwd = 'admin' #the password of the user
dbname = 'test' #the database
# odoo Common login Service proxy object
sock_common = xmlrpclib.ServerProxy ('http://localhost:8069/xmlrpc/common')
uid = sock_common.login(dbname, username, pwd)
#replace localhost with the address of the server
# odoo Object manipulation service
sock = xmlrpclib.ServerProxy('http://localhost:8069/xmlrpc/object')
partner = {
'name': 'Fabien Pinckaers',
'lang': 'fr_FR',
}
#calling remote ORM create method to create a record
partner_id = sock.execute(dbname, uid, pwd, 'res.partner', 'create', partner)