How to prevent some variables from showing up in python Class object? - python

I have a class that contains some variables for users, inside the shell i want to fetch the first user from the database, i am using __dict__ attribute to see all the user data, there is some data that i don't want them to show up inside the dictionary like his password and credentials, here is my code :
class User(db.Model):
__tablename__ = 'user'
id = db.Column(db.Integer(), primary_key=True)
username = db.Column(db.String())
password = db.Column(db.String())
public_id = db.Column(db.String(), default=uuid.uuid4)
my_code = db.Column(db.String())
credential = db.Column(db.String())
def __repr__(self):
return '{}'.format(self.username)
def set_password(self, password):
self.password = generate_password_hash(password)
def check_password(self, value):
return check_password_hash(self.password, value)
def check_code(self, code):
return True if code == self.my_code else False
#property
def get_id(self):
return "{id}".format(id=self.public_id)
How to prevent password and credential from showing up inside the dictionary if i used __dict__ attribute ??

You should try to filter User.__dict__ getting from it only the data you want to show. There is no way a class attribute to be out of Class.__dict__, this is the way Python map all the attributes.

Related

Attribute encapsulation - Flask

I'm creating a basic CRUD with Flask and using SQLAlchemy as ORM. So, I'm trying encapsulate the database attributes as follows but the request data is returning NULL. How can I do this and make the attributes accessible only inside my User class and get the request body correctly?
class User(db.Model):
__tablename__ = "users"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(200))
email = db.Column(db.String(200))
date_created = db.Column(db.DateTime, default=datetime.utcnow)
def __init__(self, name, email):
self.__name = name
self.__email = email
#classmethod
def search_user(cls, name):
user = cls.query.filter_by(name=name).first()
if user:
return user
return None
def save_user(self):
db.session.add(self)
db.session.commit()
class Register(Resource):
def post(self):
request =reqparse.RequestParser()
request.add_argument("name", type=str, required=True, help="Cannot be blank")
request.add_argument("email", type=str, required=True, help="Cannot be blank")
data = request.parse_args()
if User.search_user(data["name"]):
return jsonify(f"The user {data['name']} already exists")
user = User(**data)
user.save_user()
return jsonify(f"User {data['name']} successfully registered")

Flask-SQLAlchemy append not working for a many to many relationship

I am attempting to use the append method to add to a reference table for a many-to-many relationship between class User and class App (also referred to as 'plus' throughout the code). The idea is that there will be many users who use a single app and many apps used by a single user so I thought a many to many relationship would be appropriate. I am able to get a valid user object and a valid app/plus object but when I use plus.append(user), nothing happens. I don't get an error and nothing is added to the reference table. I am guessing I did not set up the relationship correctly?
Things I've tried:
Changing the direction of the relationship so User is the left side entity.
Making it into a one to many relationship.
The bi-directional example given in the documentation here.
The solution here.
Reference table definition:
plusses = db.Table(
'plusses',
db.Column('plus_id', db.Integer, db.ForeignKey('app.id')),
db.Column('user_id', db.Integer, db.ForeignKey('user.id')))
Definition of 'User' class
class User(UserMixin, 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))
about_me = db.Column(db.String(140))
last_seen = db.Column(db.DateTime, default=datetime.utcnow)
Definition of 'App' class:
class App(db.Model):
id = db.Column(db.Integer, primary_key=True)
icon = db.Column(db.String(140))
link = db.Column(db.String(140))
name = db.Column(db.String(140))
args = db.Column(db.Text())
description = db.Column(db.String(220))
pluses_user = db.relationship(
'User', secondary=plusses,backref=db.backref('plusses', lazy='dynamic'), lazy='dynamic')
def __repr__(self):
return '<App {}>'.format(self.body)
def getApp(self, name):
return App.query.filter_by(name=name).first()
# if app is None:
# Create app here if
def add_plus(self, user):
if not self.has_plus(user):
self.pluses_user.append(user)
def remove_plus(self, user):
if self.has_plus(user):
self.pluses_user.remove(user)
def has_plus(self, user):
return self.pluses_user.filter(
plusses.c.plus_id == user.id).count() > 0
Route that uses the function:
#bp.route('/add/<plusname>')
#login_required
def add_plus(plusname):
plus=App.query.filter_by(name=plusname).first()
if plus is None:
flash('App not found')
return redirect(url_for('main.index'))
plus.add_plus(current_user)
return redirect(url_for('main.apps'))
I'm new here so please let me know how I can improve my question :) Any help at all would be appreciated.
I was able to solve this by adding db.session.commit() to my add_plus and remove_plus functions. They now look like this:
def add_plus(self, user):
if not self.has_plus(user):
self.pluses_user.append(user)
db.session.commit()
def remove_plus(self, user):
if self.has_plus(user):
self.pluses_user.remove(user)
db.session.commit()

How to set form element name?

I have a web application written in Flask that uses WTForms, SQLAlchemy and corresponding Flask extensions, Flask-SQLAlchemy, Flask-WTF and WTForms-Alchemy.
For the following model:
class User(db.Model, UserMixin):
"""
Represents a registered user.
#TODO Override setter for password so it is always encrypted.
#TODO Add last_login column
"""
__tablename__ = 'User'
def __init__(self, username=None, password=None, email=None):
self.username = username
self.email = email
self.password = encrypt(password)
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, nullable=False, default=u'Anonymous Lifter')
username = db.Column(db.String, nullable=False)
password = db.Column(db.String, nullable=False)
I try to create a Form the following way:
class LoginForm(ModelForm):
""" Form used to login a user that does not use social login. """
class Meta:
model = User
only = [u'username', u'password']
field_args = {u'password': {'widget': PasswordInput()}}
remember_me = BooleanField(u'Remember me')
My problem is that when I display the form on my page both username and password appear lower-cased. How can I set their labels(?)/names(?) to upper-case?
Use the info property when defining your columns in your model. For example:
class User(db.Model, UserMixin):
"""
Represents a registered user.
#TODO Override setter for password so it is always encrypted.
#TODO Add last_login column
"""
__tablename__ = 'User'
def __init__(self, username=None, password=None, email=None):
self.username = username
self.email = email
self.password = encrypt(password)
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, nullable=False, default=u'Anonymous Lifter', info={'label': 'Name'})
username = db.Column(db.String, nullable=False, info={'label': 'Username'})
password = db.Column(db.String, nullable=False, info={'label': 'Password'})
Or use the field_args when defining your form:
class LoginForm(ModelForm):
""" Form used to login a user that does not use social login. """
class Meta:
model = User
only = [u'username', u'password']
field_args = {
u'password': {
'widget': PasswordInput(),
'label': 'PASSWORD'
},
u'username': {'label': 'USERNAME'},
}
remember_me = BooleanField(u'Remember me')

Querying a database in Flask

I'm getting AttributeError: 'BaseQuery' object has no attribute 'check_password' when I attempt to call check_password on the User object I create in forms.py below. Here are the two lines where the problem occurs:
user = User.query.filter_by(userID = self.userID.data)
if user and user.check_password(self.password.data):
...
The relevant source code is below. I know the check_password() method works because I can call it from within models.py. I'm not sure why I have access to the User model but not the check_password function.
forms.py
...
from .models import User
class LoginForm(Form):
...
def validate(self):
if not Form.validate(self):
return False
***user = User.query.filter_by(userID = self.userID.data)***
***if user and user.check_password(self.password.data)***:
return True
else:
self.userID.errors.append("Invalid user ID or password")
return False
models.py
from app import db
from flask.ext.login import LoginManager, UserMixin
from werkzeug import generate_password_hash, check_password_hash
class User(UserMixin, db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
social_id = db.Column(db.String(64), nullable=False) #could have duplicate
userID = db.Column(db.String(64), nullable=False)
email = db.Column(db.String(64), nullable=True)
pwdhash = db.Column(db.String(54), nullable=True)
posts = db.relationship('Post', backref='author', lazy='dynamic')
def __init__(self, social_id, userID, email, password):
if social_id:
self.social_id = social_id #not required if not using Facebook login
if userID:
self.userID = userID
self.email = email.lower()
if password:
self.set_password(password)
assert self.check_password(password)
def set_password(self, password):
self.pwdhash = generate_password_hash(password)
def check_password(self, password):
return check_password_hash(self.pwdhash, password)
User.query.filter_by() will return the query. If you want the first result of the query you need to call first(), i.e.
User.query.filter_by(...).first()

TypeError: editProfile() got an unexpected keyword argument 'obj'

I want to edit my user profile, here is my model, the form and view. After the transfer of 'obj' to form (in view) this message appears:
"TypeError: editProfile() got an unexpected keyword argument 'obj'"
Please for hint.
Model:
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), index=True, unique=True)
age = db.Column(db.Integer, index=True)
email = db.Column(db.String(120), index=True, unique=True)
def __repr__(self):
return '<User %r>' % (self.name)
Form:
class editProfile(Form):
name = StringField('name', validators=[DataRequired()])
age = IntegerField('age', validators=[DataRequired()])
email = StringField('email', validators=[Email()])
View:
#app.route('/edit/<int:id>')
def editProfile(id):
post = User.query.get(id)
form = editProfile(obj=post)
if form.validate_on_submit():
form.populate_obj(post)
db.session.commit()
flash("Profile was updated")
return redirect(url_for('index'))
return render_template('editProfile.html', form=form)
You're calling the editProfile function, not the class, ie, you're doing recursion.
Your editProfile function does not take any arguments named obj therefore you're getting that error.
This is because they are named exactly the same.
Change to
def editProfile(id):
post = User.query.get(id)
form = EditProfileForm(obj=post)
And you'll see that it'll work.

Categories

Resources