Login_user fails to get userid with NotImplementedError - flask-login

My app fails whenever I call login_user with the error
"NotImplementedError: No id attribute - override get_id". Why does this fail?
#app.route('/login', methods=['GET', 'POST'])
def login():
if current_user.is_authenticated:
return redirect(url_for('home'))
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(email=form.email.data).first()
if user and bcrypt.check_password_hash(user.password, form.password.data):
login_user(user, remember=True)
else:
flash('Login Unsuccessful. Please check email and password', 'danger')
return redirect(url_for('login'))
return render_template('login.html', title='login', form=form)
#login_manager.user_loader
def load_user(userid):
return User.query.get(userid)
class User(UserMixin):
def get_id(self):
return self.userid
class User(UserMixin, db.Model):
userid = db.Column(db.String(50), primary_key=True)
name = db.Column(db.String(200), nullable=False)
username = db.Column(db.String(200), unique=True, nullable=False)
designation = db.Column(db.String(200), nullable=False)
password = db.Column(db.String(200), nullable=False)
dateofjoin = db.Column(db.DateTime, nullable=True)
email = db.Column(db.String(200), unique=True, nullable=False)
address = db.Column(db.String(200), nullable=False)
mobile = db.Column(db.String(200), nullable=False)
def __repr__(self):
return f"User('{self.userid}','{self.username}', '{self.email}', '{self.designation}', '{self.password}')"

In your User model rename primary_key 'userid' to 'id'. Update the db and try again. The get_id method looks for 'id'. It is hardcoded into flask-login. Or you can edit get_id method itself in flask_login's mixin.py module. But I am not sure it won't break somewhere else.
def get_id(self):
try:
return text_type(self.id) # Rename 'id' to 'userid'
except AttributeError:
raise NotImplementedError('No `id` attribute - override `get_id`')

Related

Nested one-to-many relations in flask-admin

I have such models in my project:
class Ingredient(Base):
__tablename__ = 'ingredient'
id = Column(Integer, primary_key=True, index=True)
name = Column(String)
measurement_unit = Column(String)
ingredient_amount = relationship('IngredientAmount', back_populates='ingredient')
def __str__(self):
return self.name
class IngredientAmount(Base):
__tablename__ = 'ingredient_amount'
id = Column(Integer, primary_key=True, index=True, nullable=True)
ingredient_id = Column(Integer, ForeignKey('ingredient.id'))
recipe_id = Column(Integer, ForeignKey('recipe.id'))
amount = Column(Integer)
ingredient = relationship('Ingredient', back_populates='ingredient_amount')
recipes = relationship(
'Recipe',
back_populates='ingredients',
cascade='all, delete'
)
class Recipe(Base):
__tablename__ = 'recipe'
id = Column(Integer, primary_key=True, index=True)
text = Column(String)
name = Column(String, unique=True)
author_id = Column(Integer, ForeignKey('user.id'))
ingredients = relationship(
'IngredientAmount',
back_populates='recipes',
cascade='all, delete'
)
So when I look at recipe in flask-admin i'd like to see ingredients which loads IngredientAmount instance and IngredientAmount instance loads Ingredient instance. I tried to implement view as:
class RecipeView(ModelView):
can_edit = True
can_create = True
can_delete = True
can_view_details = True
column_auto_select_related = True
column_display_pk = True
column_display_all_relations = True
column_display_actions = True
def get_query(self):
return self.session.query(Recipe).order_by(Recipe.id).options(
joinedload(Recipe.ingredients).joinedload(IngredientAmount.ingredient)
).options(joinedload(Recipe.tags)).options(
joinedload(Recipe.author)
)
But I see <models.IngredientAmount object at 0x7f6e7b7edd80>. Is it possible to do what I want?

Flask SQLAlchemy, IntegrityError, ForeignKeyViolation - Creating relationships between tables

I'm trying to create a Flask app where I can return a list of 'workspaces' from a postgresql database, a list of 'categories and a list of 'projects'.
In projects.py, when a GET method is called, the database will return all of the 'workspaces' and all of the 'categories' and get both the id and name for each, I can then put this in a dropdown button for the user to select. This part of the code works fine.
When a POST method is called, this should add a new row to the 'projects' table to define a new project, along with this should be the workspace_id and the categories_id that the user selected.
This part of the code is not working, I get the following error message:
sqlalchemy.exc.IntegrityError: (psycopg2.errors.ForeignKeyViolation) insert or update on table "projects" violates foreign key constraint "workspace_id"
DETAIL: Key (id)=(19) is not present in table "workspaces".
[SQL: INSERT INTO projects (name, description, category_id, workspace_id, visibility_level, slug) VALUES (%(name)s, %(description)s, %(category_id)s, %(workspace_id)s, %(visibility_level)s, %(slug)s) RETURNING projects.id]
[parameters: {'name': 'Brand New Project', 'description': 'gfhfghfg', 'category_id': '1', 'workspace_id': '1', 'visibility_level': '1', 'slug': 'brand-new-project'}]
models.py:
from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import relationship
from taskmanagement.database import Base
class Projects(Base):
__tablename__ = 'projects'
id = Column(Integer, primary_key=True)
name = Column(String(140), unique=True)
description = Column(String(140), unique=True)
category_id = Column(Integer, ForeignKey('categories.id'), unique=False, nullable=False)
category = relationship('Categories', lazy=True, uselist=False, primaryjoin="Categories.id == Projects.category_id")
workspace_id = Column(Integer, ForeignKey('workspaces.id'), unique=False, nullable=False)
workspace = relationship('Workspaces', lazy=True, uselist=False, primaryjoin="Projects.workspace_id == Workspaces.id")
visibility_level = Column(Integer, unique=False)
slug = Column(String(240), unique=True)
def __init__(self, name=None, description=None, category_id=None, workspace_id=None, visibility_level=None, slug=None):
self.name = name
self.description = description
self.category_id = category_id
self.workspace_id = workspace_id
self.visibility_level = visibility_level
self.slug = slug
def __repr__(self):
return f'<Projects {self.name!r}>'
class Workspaces(Base):
__tablename__ = 'workspaces'
id = Column(Integer, primary_key=True)
name = Column(String(50), unique=True)
def __init__(self, name=None):
self.name = name
def __repr__(self):
return f'<Workspaces {self.name!r}>'
class Categories(Base):
__tablename__ = 'categories'
id = Column(Integer, primary_key=True)
name = Column(String(50), unique=True)
def __init__(self, name=None):
self.name = name
def __repr__(self):
return f'<Workspaces {self.name!r}>'
Projects.py
#projects.route('/projects/add', methods = ['POST', 'GET'])
def project_add():
if request.method == 'GET':
categories = Categories.query.all()
workspaces = Workspaces.query.all()
categories_results = [
{
"id": category.id,
"name": category.name
} for category in categories]
workspaces_results = [
{
"id": workspace.id,
"name": workspace.name
} for workspace in workspaces]
results = {"categories": categories_results, "workspaces": workspaces_results}
return render_template('project_add.html', title='Add Project', results=results)
else:
name = request.form['project_name']
slug = request.form['project_slug']
description = request.form['project_desc']
visibility_level = request.form['project_visibility']
category_id = request.form['category_id']
workspace_id = request.form['workspace_id']
form_results = {
"name": request.form['project_name'],
"slug": request.form['project_slug'],
"description": request.form['project_desc'],
"visibility_level": request.form['project_visibility'],
"category_id": request.form['category_id'],
"workspace_id": int(request.form['workspace_id'])
}
#return form_results
results = Projects(name, description, category_id, workspace_id, visibility_level, slug)
db_session.add(results)
db_session.commit()
I'm completely stuck of this problem. Can anyone tell me what I'm doing wrong?

Return Django ORM union result in Django-Graphene

I am trying to query two separate objects and return them as a single result set. I've tried using a Union and an Interface, but not sure what I'm doing wrong there.
My model:
class BaseActivity(models.Model):
class Meta:
abstract = True
name = models.CharField(db_column="activity_type_name", unique=True, max_length=250)
created_at = CreationDateTimeField()
modified_at = ModificationDateTimeField()
created_by = models.UUIDField()
modified_by = models.UUIDField()
deleted_at = models.DateTimeField(blank=True, null=True)
deleted_by = models.UUIDField(blank=True, null=True)
class Activity(BaseActivity):
class Meta:
db_table = "activity_type"
ordering = ("sort_order",)
id = models.UUIDField(
db_column="activity_type_id",
primary_key=True,
default=uuid.uuid4,
editable=False,
)
sort_order = models.IntegerField()
def __str__(self):
return self.name
class CustomActivity(BaseActivity):
class Meta:
db_table = "organization_custom_activity_type"
id = models.UUIDField(
db_column="organization_custom_activity_type",
primary_key=True,
default=uuid.uuid4,
editable=False,
)
farm = models.ForeignKey("farm.Farm", db_column="organization_id", on_delete=models.DO_NOTHING, related_name="custom_activity_farm")
My schema:
class FarmActivities(graphene.ObjectType):
id = graphene.String()
name = graphene.String()
class ActivityType(DjangoObjectType):
class Meta:
model = Activity
fields = ("id", "name", "requires_crop", "sort_order")
class CustomActivityType(DjangoObjectType):
class Meta:
model = CustomActivity
fields = ("id", "name", "farm")
And the query:
class Query(graphene.ObjectType):
get_farm_activities = graphene.Field(FarmActivities, farm=graphene.String(required=True))
def resolve_get_farm_activities(self, info, farm):
farm_activities = Activity.objects.values("id", "name").filter(
farmtypeactivityrel__farm_type__farm=farm, deleted_at=None
)
custom_activities = CustomActivity.objects.values("id", "name").filter(farm=farm, deleted_at=None)
return list(chain(farm_activities, custom_activities))
With this, I do get a list back from the query, but it's not going thru the resolver when I call getFarmActivities.
Literally the list returns:
ExecutionResult(data={'getFarmActivities': {'id': None, 'name': None}}, errors=None)
How to resolve graphene.Union Type?
That provided the hint I needed to get this working. I had to build a Union that would parse the model and not the schema type.
class FarmActivities(graphene.Union):
class Meta:
types = (ActivityType, CustomActivityType)
#classmethod
def resolve_type(cls, instance, info):
if isinstance(instance, Activity):
return ActivityType
if isinstance(instance, CustomActivity):
return CustomActivityType
return FarmActivities.resolve_type(instance, info)
Which then allowed me to run the query like so:
def resolve_get_farm_activities(self, info, farm):
farm_activities = Activity.objects.filter(
farmtypeactivityrel__farm_type__farm=farm
)
custom_activities = CustomActivity.objects.filter(farm=farm)
return list(chain(farm_activities, custom_activities))
And the API query:
query farmParam($farm: String!)
{
getFarmActivities(farm: $farm)
{
... on CustomActivityType
{
id
name
}
... on ActivityType
{
id
name
}
}
}

Why are default values for PostgreSQL on insert not working?

I have a PostgreSQL database on Heroku and I've connected to that using PopSQL. Here is the model for the table (using Flask + SQLAlchemy) -
class User(db.Model):
__tablename__ = 'users'
email = Column(String, primary_key=True)
group = Column(String)
age = Column(String)
gender = Column(String)
category = Column(String)
isEnrolled = Column(Boolean)
logCount = Column(Integer, default=0)
logged = Column(ARRAY(Boolean), default=[None]*14)
medMin = Column(ARRAY(Integer), default=[None]*14)
def __init__(self, email, age, group ,gender, category):
self.email = email
self.age = age
self.group = group
self.gender = gender
self.category = category
The table was created using db.create_all()
In PopSQL, when I do an INSERT of the form:
INSERT INTO users(email,"group",age,gender,category)
VALUES('abc#gmail.com','other','20-30','Female','intrinsic');
The columns of logCount, logged and medMin are set to null and not their default values. Why is this happening?

Apex - Test class adding Chatter Free users

I'm a newbie trying to build a test class for a registration handler that allows new chatter free users to be created for an org. To create the chatter free user, the working trigger checks a new user's email domain against a predefined list of acceptable email domains that are stored in a custom object named DomainList.
Looking for suggestions on how to better structure a test class for code coverage. Any ideas appreciated, thanks!
global class RegHandlerDomain implements Auth.RegistrationHandler {
global User createUser(Id portalId, Auth.UserData data) {
String domain = data.email.split('#')[1];
List<DomainList__c> listedDomains = [SELECT id,
name
FROM DomainList__c
WHERE Email_Domain__c = : domain];
if (listedDomains.size() == 1) {
User u = new User();
Profile p = [SELECT Id
FROM profile WHERE name = 'Chatter Free User'];
// Use incoming email for username
u.username = data.email;
u.email = data.email;
u.lastName = data.lastName;
u.firstName = data.firstName;
u.alias = (data.username != null) ? data.username : data.identifier;
if (u.alias.length() > 8) {
u.alias = u.alias.substring(0, 8);
}
u.languagelocalekey = UserInfo.getLocale();
u.localesidkey = UserInfo.getLocale();
u.emailEncodingKey = 'UTF-8';
u.timeZoneSidKey = 'America/Los_Angeles';
u.profileId = p.Id;
System.debug('Returning new user record for ' + data.username);
return u;
} else return null;
}
global void updateUser(Id userId, Id portalId, Auth.UserData data) {
User u = new User(id = userId);
u.email = data.email;
u.lastName = data.lastName;
u.firstName = data.firstName;
System.debug('Updating user record for ' + data.username);
update(u);
}
}
Test class is looking for a '}' before the insert
#isTest(SeeAllData = true)
public class RegHandlerTest {
public void myTestMethod1() {
//CREATE CHATTER FREE TEST USER
Profile p = [select id
from profile where name = 'Chatter Free User'];
User u1 = new User(alias = 'chfree01',
email = 'chatterfreeuser101#testorg.com',
emailencodingkey = 'UTF-8',
lastname = 'Testing',
companyname = 'testorg',
languagelocalekey = 'en_US',
localesidkey = 'en_US',
profileId = p.Id,
timezonesidkey = 'America/Los_Angeles',
username = 'chatterfreeuser101#testorg.com');
insert u1;
}
//CHECK NEW USER EMAIL DOMAIN TO SEE IF IN CUSTOM OBJECT DOMAINLIST
List<DomainList__c> listedDomains = [select id, email_domain__c
from DomainList__c
where name = 'testorg' LIMIT 1];
if (listedDomains.size() == 1) System.debug('WORKS');
}
Fir of all you need create a proper unit test, because your is not correct.
#isTest(SeeAllData = true)
public class RegHandlerTest {
#isTest private static void verifyInsertChatterFreeUser() {
//CREATE CHATTER FREE TEST USER
Profile p = [SELECT id
FROM profile
WHERE name = 'Chatter Free User'];
User u1 = new User(alias = 'chfree01',
email = 'chatterfreeuser101#testorg.com',
emailencodingkey = 'UTF-8',
lastname = 'Testing',
companyname = 'testorg',
languagelocalekey = 'en_US',
localesidkey = 'en_US',
profileId = p.Id,
timezonesidkey = 'America/Los_Angeles',
username = 'chatterfreeuser101#testorg.com');
insert u1;
// perform some assertions regarding expected state of user after insert
//CHECK NEW USER EMAIL DOMAIN TO SEE IF IN CUSTOM OBJECT DOMAINLIST
List<DomainList__c> listedDomains = [SELECT id, email_domain__c
FROM DomainList__c
WHERE name = 'testorg' LIMIT 1];
// as you've annotated class with SeeAllData=true, this assertion always will be true
System.assertEquals(1, listedDomains.size());
}
#isTest private static void verifyUpdateChatterFreeUser() {
//CREATE CHATTER FREE TEST USER
Profile p = [SELECT id
FROM profile
WHERE name = 'Chatter Free User'];
User u1 = new User(alias = 'chfree01',
email = 'chatterfreeuser101#testorg.com',
emailencodingkey = 'UTF-8',
lastname = 'Testing',
companyname = 'testorg',
languagelocalekey = 'en_US',
localesidkey = 'en_US',
profileId = p.Id,
timezonesidkey = 'America/Los_Angeles',
username = 'chatterfreeuser101#testorg.com');
insert u1;
// perform some assertion regarding expected state of user after insert
// change something on user
u1.email = 'test.chatter.free#gmail.com';
update u1;
// perform some assertions regarding expected state of user after update
// System.assertEquals('expected value', u1.field);
}
}