I'm working on a app with RBAC and I'm trying to populate a QuerySelectField with data from my Role database model but it doesn't work because I'm constantly getting one of those two errors:
sqlalchemy.exc.OperationalError: <unprintable OperationalError object>
or
TypeError: 'BaseQuery' object is not callable
models.py
class Role(db.Model):
id = db.Column(db.Integer, primary_key=True, autoincrement='auto')
name = db.Column(db.String(50), unique=True)
user = db.relationship('User', backref='role', lazy='dynamic')
not_view = db.Column(db.Text, nullable=False)
not_edit = db.Column(db.Text, nullable=False)
not_add = db.Column(db.Text, nullable=False)
not_delete = db.Column(db.Text, nullable=False)
forms.py
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField
from wtforms.validators import DataRequired, Email, EqualTo, Length
from app.models import Role
from wtforms.ext.sqlalchemy.fields import QuerySelectField
def role_choice():
return Role.query
class AddUserForm(FlaskForm):
username = StringField('Username', validators=[DataRequired(), Length(min=2, max=20)])
email = StringField('Email', validators=[DataRequired(), Email()])
password = PasswordField('Password', validators=[DataRequired()])
confirm_password = PasswordField('Confirm Password', validators=[DataRequired(), EqualTo('password')])
role_id = QuerySelectField(query_factory=role_choice)
I tried a few different ways of passing in data but none of them worked. Can someone help?
Don't bother to answer, I already solved the problem with a SelectField with a dynamic choice.
class UserDetails(Form):
group_id = SelectField(u'Group', coerce=int)
def edit_user(request, id):
user = User.query.get(id)
form = UserDetails(request.POST, obj=user)
form.group_id.choices = [(g.id, g.name) for g in Group.query.order_by('name')]
Related
I have a Django project where I am using Graphql but after writing out only one mutation, the /graphql does not run properly, throwing the following error.
{
"message": "Invalid or incomplete introspection result. Ensure that you are passing \"data\" property of introspection response and no \"errors\" was returned alongside: null.",
"stack": "r#https://cdn.jsdelivr.net/npm/graphiql#1.0.3/graphiql.min.js:1:24583\nur#https://cdn.jsdelivr.net/npm/graphiql#1.0.3/graphiql.min.js:1:326896\nwindow.GraphiQL</</s/value/<#https://cdn.jsdelivr.net/npm/graphiql#1.0.3/graphiql.min.js:7:48325\n"
}
How can I fix this ???
Here is my main schema
import graphene
import accounts.schema
class Query(graphene.ObjectType):
pass
class Mutation(accounts.schema.Mutation, graphene.ObjectType):
pass
schema = graphene.Schema()
Here is my account schema file
import graphene
from graphene_django import DjangoObjectType
from .models import CustomUser
class CustomUserType(DjangoObjectType):
class Meta:
model = CustomUser
class CustomUserInput(graphene.InputObjectType):
full_legal_name = graphene.String(required=True)
title = graphene.String(required=True)
email = graphene.String(required=True)
phone_number = graphene.String(required=True)
physical_address = graphene.String(required=True)
password = graphene.String(required=True)
confirm_password = graphene.String(required=True)
role = graphene.String(required=True)
class CreateUser(graphene.Mutation):
user = graphene.Field(CustomUserType)
class Arguments:
user_data = CustomUserInput(required=True)
def mutate(self, info, user_data=None):
user = CustomUser(
email=user_data.email,
full_legal_name=user_data.full_legal_name,
title=user_data.title,
phone_number=user_data.phone_number,
physical_address=user_data.physical_address,
password=user_data.password,
confirm_password=user_data.confirm_password,
role=user_data.role
)
if user.password != user.confirm_password:
raise Exception("Passwords do not match!")
else:
user.set_password(user_data.password)
user.save()
return CreateUser(user=user)
class Mutation(graphene.ObjectType):
create_user = CreateUser.Field()
And my model.py file which I used to build out the schema.
from django.db import models
from django.contrib.auth.models import AbstractUser
class CustomUser(AbstractUser):
TITLES = (
('Mr', 'Mr'),
('Mrs', 'Mrs')
)
ROLES = (
('school_admin', 'school_admin'),
('app_admin', 'app_admin'),
('school_staff', 'school_staff')
)
email = models.EmailField(blank=False, max_length=255, verbose_name='email address')
full_legal_name = models.CharField(max_length=255, verbose_name='full legal name')
title = models.CharField(max_length=10, verbose_name='title')
phone_number = models.CharField(max_length=20, verbose_name='phone number')
physical_address = models.CharField(max_length=50, verbose_name='physical address')
confirm_password = models.CharField(blank=False, max_length=100, verbose_name='confirmation')
role = models.CharField(max_length=50, choices=ROLES, verbose_name='role')
EMAIL_FIELD = "email"
How can I go about solving this problem?
Add a sample query and pass both the query and the mutation to graphene.Schema as shown below.
class Query(graphene.ObjectType):
hello = graphene.String(default_value="Hi!")
class Mutation(accounts.Mutation, graphene.ObjectType):
pass
schema = graphene.Schema(query=Query, mutation=Mutation)
I have two very simple models. In my Post model there are supposed to be two relationships into the User table. One is for the owner of the post and one is for the last editor of the post. They can be different values, but both refer to the same User table.
My models are set up like this
class Post(Base):
last_editor_id = Column(BigInteger, ForeignKey('users.id'), nullable=True)
last_editor = relationship('User', backref='posts', foreign_keys=[last_editor_id])
owner_id = Column(BigInteger, ForeignKey('users.id'), nullable=False, index=True)
owner = relationship('User', backref='posts', foreign_keys=[owner_id])
class User(Base):
'''This represents a user on the site'''
__tablename__ = 'users'
id = Column(BigInteger, primary_key=True, unique=True)
name = Column(BigInteger, nullable=False)
When I attempt to create these models though, I get the following error
sqlalchemy.exc.ArgumentError: Error creating backref 'posts' on relationship 'Post.owner': property of that name exists on mapper 'Mapper|User|users'
How do I correct this so that I can maintain both forgeign keys in the Post model?
The error is telling you that you've used post as a name more then once for your backrefs, all you need to do is give the backref's unique names. Here's a complete example-- I've added a id primary key to the Post class, and also some __repr__s so we get some readable output.
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, BigInteger, ForeignKey, Integer
from sqlalchemy.orm import relationship, sessionmaker
Base = declarative_base()
engine = create_engine('sqlite://') ## In Memory.
Session = sessionmaker()
Session.configure(bind=engine)
session = Session()
class Post(Base):
__tablename__ = 'post'
id = Column(Integer, primary_key=True)
last_editor_id = Column(BigInteger, ForeignKey('users.id'), nullable=True)
last_editor = relationship('User', backref='editor_posts', foreign_keys=[last_editor_id])
owner_id = Column(BigInteger, ForeignKey('users.id'), nullable=False, index=True)
owner = relationship('User', backref='owner_posts', foreign_keys=[owner_id])
def __repr__(self):
return '<Post: {}>'.format(self.id)
class User(Base):
'''This represents a user on the site'''
__tablename__ = 'users'
id = Column(BigInteger, primary_key=True, unique=True)
name = Column(BigInteger, nullable=False)
def __repr__(self):
return '<User: {}>'.format(self.name)
Base.metadata.create_all(engine)
bob = User(name='Bob', id=1)
alice = User(name='Alice', id=2)
post = Post(owner=alice, last_editor=bob, id=1)
session.add(post)
session.commit()
bob = session.query(User).get(1)
print bob
# <User: Bob>
print bob.editor_posts
# [<Post: 1>]
print bob.owner_posts
# []
post = session.query(Post).get(1)
print post.owner
# <User: Alice>
print post.last_editor
# <User: Bob>
Now when you query a user, you can ask that object user.owner_posts or user.editor_posts.
In general it's a naming Problem of the backref.
Since 1:n relationships are sometimes a bit confusing, I set the relationship attribute
always on the singular site, to avoid confusion.
then the backref name is always singular. and the relationship attribute is always in the Class where the foreignkey is referencing to.
Now to my suggestion for the fixed code:
class Post(Base):
last_editor_id = Column(BigInteger, ForeignKey('users.id'), nullable=True)
owner_id = Column(BigInteger, ForeignKey('users.id'), nullable=False, index=True)
class User(Base):
'''This represents a user on the site'''
__tablename__ = 'users'
id = Column(BigInteger, primary_key=True, unique=True)
name = Column(BigInteger, nullable=False)
owned_posts = relationship('Post', backref='owner')
edited_posts = relationship('Post', backref='last_editor')
Now you can get all the owned posts of a User with User.owned_posts and all owners of a post with Post.owner. Same with the last_edited attribute.
For additional info you could read the docs how to set up relationships
I am creating a Flask app in which 2 types of users can register and log in. In the #login.user_loader function, how can I configure it to check different tables based on the type of user that is logged in?
Here's my models.py code:-
from app import db, login
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import UserMixin
#login.user_loader
def load_user(id):
return Patient.query.get(int(id))
class Patient(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
full_name = db.Column(db.String(64), index=True)
city = db.Column(db.String(20))
email = db.Column(db.String(120), index=True, unique=True)
password_hash = db.Column(db.String(120))
def __repr__(self):
return '<Patient {}>'.format(self.full_name)
def set_password(self, password):
self.password_hash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
class Doctor(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
full_name = db.Column(db.String(64), index=True)
city = db.Column(db.String(20))
qual = db.Column(db.String(20))
fees = db.Column(db.Integer)
phone = db.Column(db.Integer)
address = db.Column(db.String(120))
email = db.Column(db.String(120), index=True, unique=True)
password_hash = db.Column(db.String(120))
def __repr__(self):
return '<Doctor {}>'.format(self.full_name)
def set_password(self, password):
self.password_hash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.password_hash, password)
Currently, it is only configured for the Patient table. How to set it in such a way that whenever a Doctor is logged in, it extracts information from Doctor's table?
P.S:- I do have a choice input which takes the type of user that is logging in on the Login page. Can I use that choice data somewhere in the user_loader function?
Try using Joined Table Inheritance - create a single User class from which the Doctor and Patient classes inherit from. This way they share common properties (like email and password) but have their own distinct properties too. This type of polymorphism in SQLAlchemy uses independent tables for each class, but there are other examples on the page that use different methods.
An example:
class User(UserMixin, db.Model):
email = ...
password_hash = ...
__mapper_args__ = {
'polymorphic_identity':'user',
'polymorphic_on':type
}
class Doctor(User):
fees = ...
__mapper_args__ = {
'polymorphic_identity':'user'
}
Then your user_loader function can look like this:
#login.user_loader
def load_user(id):
return User.query.get(int(id))
I'm trying to retrieve data from user. I have my model like this:
from django.db import models
from django.contrib.auth.models import User
Create your models here.
class informacionFacturacion(models.Model):
usuario = models.ForeignKey(User)
apellidos = models.CharField(max_length=100, default="editar")
nombres = models.CharField(max_length=100, default="editar")
telefono = models.CharField(max_length=100, default="editar")
email = models.EmailField(default="editar", null=False)
direccion_1 = models.CharField(max_length=100, default="editar")
direccion_2 = models.CharField(max_length=100, null=True, blank=True)
provincia = models.CharField(max_length=100, default="editar")
ciudad = models.CharField(max_length=100, default="editar")
codigoPostal = models.CharField(max_length=100, default="editar")
empresa = models.CharField(max_length=100, default="editar")
def __str__(self):
return self.usuario
My form for update user information:
from .models import informacionFacturacion
class informacionFacturacionForm(ModelForm):
class Meta:
model = informacionFacturacion
fields = [
"usuario",
"apellidos",
"nombres",
"telefono",
"email",
"direccion_1",
"direccion_2",
"provincia",
"ciudad",
"codigoPostal",
"empresa",
]
And in my view I have my query like this
from django.contrib.auth.decorators import login_required
from .models import informacionFacturacion
from .forms import informacionFacturacionForm
#login_required
def datosPersonales(request):
form = informacionFacturacionForm(request.POST or None)
if form.is_valid():
instance = form.save(commit=False)
instance.save()
query = informacionFacturacion.objects.filter(usuario=request.user)
context = {
"titulo": "Datos personales | Cadenas Giordanino S.R.L" + request.user.username,
"body_class": "class= sidebar_main_open sidebar_main_swipe",
"form": form,
"infoFacturacion": query,
}
template = "micuenta/datosPersonales.html"
return render(request, template, context)
And this QuerySet is empty.
I need to retrieve this data in the user profile
**UPDATE: ** Full code on post.
**UPDATE 2: ** For displaying the user data on profile, im using a "For loop". This data, is retrieved in "value=" attr of html inputs. If the user has no data, the form dosnt show.
This is the way I wanna show the data. I populated this form from the same form u see here.
Here's when i enter for first time to my profile with no data
Thanks a lot.
Are you sure that request.user is the user you've linked your anotherModel to? If you aren't currently logged in then request.user will be an instance of AnonymousUser. See more in the Documentation: https://docs.djangoproject.com/en/1.11/ref/request-response/#django.http.HttpRequest.user
You can use the Django Shell for testing your models:
$ python manage.py shell
Then make some models:
from django.contrib.auth.models import User
from models import AnotherModel
# Grab a User
user = User.objects.first()
# Create a new anotherModel, linking the user
my_model = AnotherModel(
user=user,
address="whatever"
)
my_model.save()
my_model.user == user
>>> True
My database look like this
from sqlalchemy.ext.declarative import declarative_base
import os
import time
import datetime
import sys
import uuid
from sqlalchemy import Column, ForeignKey, Integer, String
from sqlalchemy.orm import relationship
from sqlalchemy import create_engine
from sqlalchemy import *
from sqlalchemy_utils.types.choice import ChoiceType
from sqlalchemy_utils.types.url import URLType
Base = declarative_base()
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String(250), nullable=False)
fullname = Column(String(250), nullable=False)
password = Column(String(250), nullable=False)
def __repr__(self):
return "<User(name='%s', fullname='%s', password='%s')>" % (self.name, self.fullname, self.password)
class Client(Base):
Grand_choice = [('authorization_code', 'Authorization code')]
Response_choice = [('code', 'Authorization code')]
__tablename__ = 'client'
id = Column(Integer, primary_key=True)
client_id = Column(String(250), default=uuid.uuid4() ,unique=True)
user = Column(Integer, ForeignKey('user.id'))
grant_type = Column(ChoiceType(Grand_choice))
response_type = Column(ChoiceType(Response_choice))
scopes = Column(String(260))
default_scopes = Column(String(260))
redirect_uri = Column(URLType)
default_redirect_uri = Column(URLType)
class Bearer_Token(Base):
__tablename__ = 'Bearer_Token'
id = Column(Integer, primary_key=True)
client = Column(Integer, ForeignKey('client.id'))
user = Column(Integer, ForeignKey('user.id'))
scopes = Column(String(250))
access_token = Column(String(100),unique=True)
refresh_token = Column(String(100),unique=True)
expires_at = Column(DateTime, onupdate=datetime.datetime.now)
class Authorization_Code(Base):
__tablename__ = 'Authorization_code'
id = Column(Integer, primary_key=True)
client = Column(Integer, ForeignKey('client.id'))
user = Column(Integer, ForeignKey('user.id'))
scopes = Column(String(250))
code = Column(String(100),unique=True)
expires_at = Column(DateTime, onupdate=datetime.datetime.now)
engine = create_engine('sqlite:///sqlalchemy_oauth.db')
Base.metadata.create_all(engine)
and my validator look like this
from oauthlib.oauth2 import RequestValidator
from modelsforoauth import User ,Client, Base
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
engine = create_engine('sqlite:///sqlalchemy_oauth.db', echo=True)
Base.metadata.bind = engine
DBSession = sessionmaker()
DBSession.bind = engine
session = DBSession()
#session.query(Client.client_id).first()
class MyRequestValidator(RequestValidator):
def validate_client_id(self, client_id, request):
try:
session.query(Client).filter_by(client_id=client_id).first()
return True
except Client.DoesNotExist:
return False
I wannted to define endpoint for my api in falcon.
from My_validator import MyRequestValidator
from oauthlib.oauth2 import WebApplicationServer
validator = MyRequestValidator()
server = WebApplicationServer(validator)
class AuthorizationView(object):
def __init__(self):
self._authorization_endpoint = server
def on_get(self, req, resp):
When I look at the documentation in the following link oauthlibserver
this clearly says that
uri, http_method, body, headers = extract_params(request)
How do i acheive this in falcon
also i wanted to check if my datamodels are correct as per the requirement in documentaion
I also dont understand what should be scope and uri_redirect
If i have to make some changes in models or code please experts let me know
form a newbee
Thanks in Advance
Your extract param function should look like this:
def extract_params(request):
# returns uri, http_method, body, headers
return request.uri, request.method, request.stream.read(), request.headers