User login on Flask? - python-3.x

I've been working through chapters 3 and 4 of the Flask mega-tutorial (https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-iv-database). I'm trying to set up user logins on my flask webpage that I have hosted at pythonanywhere. I'm able to register an account successfully (I can see the record added to my database), however, when I try to login, Flask is unable to find the record when searching for the username and it returns None. I'm not sure why this is happening. Complicating things a bit is that I'm using a MySQL database rather than a SQLLite database that the tutorial uses.
config.py:
import os
basedir = os.path.abspath(os.path.dirname(__file__))
class Config(object):
SECRET_KEY = os.environ.get('SECRET_KEY') or 'something'
SQLALCHEMY_DATABASE_URI = 'mysql+mysqlconnector://username:password#jplank.mysql.pythonanywhere-services.com/jplank$default'
SQLALCHEMY_TRACK_MODIFICATIONS = False
flask_app.py:
from config import Config
from flask_sqlalchemy import SQLAlchemy
from werkzeug.urls import url_parse
from flask import Flask, render_template, flash, redirect, url_for, request
from pandas import DateOffset, DataFrame, date_range, to_datetime
from flask_login import current_user, login_user, logout_user, login_required, LoginManager
import MySQLdb
from flask_bootstrap import Bootstrap
from numpy import nan
from dateutil.relativedelta import relativedelta
import datetime
import math
from yearfrac import CalcYearFrac
import decimal
from sqlalchemy import create_engine
app = Flask(__name__)
app.config.from_object(Config)
db = SQLAlchemy(app)
login = LoginManager(app)
login.login_view = 'login'
Bootstrap(app)
from forms import NameForm, LoginForm, RegistrationForm
import routes, models
#app.route('/table', methods=('GET', 'POST'))
#login_required
def calculatetable():
[...]
models.py:
from flask_app import db, login
from werkzeug.security import generate_password_hash, check_password_hash
from flask_login import UserMixin
class User(UserMixin, db.Model):
__tablename__ = "user"
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))
def __repr__(self):
return '<User {}>'.format(self.username)
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)
#login.user_loader
def load_user(id):
return User.query.get(int(id))
routes.py:
from flask import render_template, flash, redirect, url_for, request
from flask_login import login_user, logout_user, current_user
from werkzeug.urls import url_parse
from flask_app import app, db
from forms import LoginForm, RegistrationForm
from models import User
from config import Config
#app.route('/logout')
def logout():
logout_user()
return redirect(url_for('index'))
#app.route('/login', methods=['GET', 'POST'])
def login():
if current_user.is_authenticated:
return redirect(url_for('index'))
form = LoginForm()
if form.validate_on_submit():
user =
User.query.filter_by(username=form.username.data).first()
if user is None:
flash('user is none')
flash(form.username.data)
return redirect(url_for('login'))
elif not user.check_password(form.password.data):
flash('not hash match')
return redirect(url_for('login'))
login_user(user, remember=form.remember_me.data)
next_page = request.args.get('next')
if not next_page or url_parse(next_page).netloc != '':
next_page = url_for('calculatetable')
return redirect(next_page)
return render_template('login.html', title='Sign In', form=form)
#app.route('/register', methods=['GET', 'POST'])
def register():
if current_user.is_authenticated:
return redirect(url_for('index'))
form = RegistrationForm()
if form.validate_on_submit():
user = User(username=form.username.data, email=form.email.data)
user.set_password(form.password.data)
db.session.add(user)
db.session.commit()
flash('Congratulations, you are now a registered user!')
return redirect(url_for('login'))
return render_template('register.html', title='Register', form=form)

I managed to solve this. There was a problem with the way I'd set up my MySQL table and I didn't have certain columns identified as index. Recreating the table solved the issue.

Related

Django DeleteView Not Saving Changes

I'm using django DeleteView to delete user account. when i set the user's is_active property to False, it doesn't get saved in the database. it's still set to True
here's my views.py
from django.shortcuts import get_object_or_404
from django.urls import reverse_lazy
from django.http import HttpResponseRedirect
from django.views.generic.edit import DeleteView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.messages.views import SuccessMessageMixin
class DeleteAccount(LoginRequiredMixin, SuccessMessageMixin, DeleteView):
"""
DeleteAccount: view to delete user account
"""
model = User
template_name = 'registration/delete_account.html'
success_url = reverse_lazy('core:index')
success_message = 'Account Successfully Deleted!'
def form_valid(self, form):
"""
Delete account and logout current user
"""
account = self.get_object()
# verify if user is the rightful owner of this account
if not account.id == self.request.user.id:
return HttpResponseRedirect(reverse_lazy('accounts:index'))
account.is_active = False # DOESN'T GET SAVED
account.save() # EVEN AFTER CALLING MODEL.SAVE() METHOD
logout(self.request)
return super().form_valid(form)
def get_object(self):
return get_object_or_404(User, pk = self.request.user.id)

UserWarning: Neither SQLALCHEMY_DATABASE_URI nor SQLALCHEMY_BINDS is set. Defaulting SQLALCHEMY_DATABASE_URI to "sqlite:///:memory:"

I have been trying to solve an issue related to SQLALCHEMY in Flask as my db is not getting created even though I set the SQLACHEMY_DATABASE_URI to "app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db'".
In the warning it says the 'sqlite:///:memory:'. When db.create_all() is call test.sql file is not created and also in the UI I see errors as mentioned bellow:
Instance of 'SQLAlchemy' has no 'Column' memberpylint(no-member) and 3 others
Please help in resolving this issue and generating the db and SQL file.
from flask import Flask, render_template, url_for
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
#Initializing database
app = Flask(__name__)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db'
db = SQLAlchemy(app)
#Creating model
class Todo(db.Model):
id = db.Column(db.Integer, primary_key=True)
content = db.Column(db.String(200), nullable=False)
completed = db.Column(db.Integer, default=0)
date_created = db.Column(db.DateTime, default=datetime.utcnow)
def __repr__(self):
return '<Task %r>' % self.id
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
if __name__ == "__main__":
app.run(debug=True)

Im not receiving the email verification in order to activate the user created

Please I've created an authentication system where a user can login with both username and email address.
The account is deactivated when it is created. I want the user to confirm his email before the account is
activated. I used the django email verification but although the user is created successfully, I dont receive
the email. Please help.
models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.utils.translation import gettext_lazy as _
class CustomUser(AbstractUser):
email = models.EmailField(_('email address'), unique=True)
backend.py
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth import get_user_model
from django.db.models import Q
UserModel = get_user_model()
class EmailBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
try:
user = UserModel.objects.get(
Q(username__iexact=username) | Q(email__iexact=username))
except UserModel.DoesNotExist:
UserModel().set_password(password)
except MultipleObjectsReturned:
return User.objects.filter(email=username).order_by('id').first()
else:
if user.check_password(password) and self.user_can_authenticate(user):
return user
def get_user(self, user_id):
try:
user = UserModel.objects.get(pk=user_id)
except UserModel.DoesNotExist:
return None
return user if self.user_can_authenticate(user) else None
forms.py
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm
from django.contrib.auth import get_user_model
from django import forms
from django.dispatch import receiver
from django.db.models.signals import pre_save
from .models import CustomUser
from django_email_verification import send_email
from django.views.generic.edit import FormView
class RegisterForm(UserCreationForm):
class Meta:
model = get_user_model()
fields = ('email', 'username', 'password1', 'password2')
#receiver(pre_save, sender=CustomUser)
def set_new_user_inactive(sender, instance, **kwargs):
if instance._state.adding is True:
instance.is_active = False
else:
pass
class MyClassView(FormView):
def form_valid(self, form):
CustomUser = form.save()
returnVal = super(MyClassView, self).form_valid(form)
send_email(CustomUser)
return returnVal
class LoginForm(AuthenticationForm):
username = forms.CharField(label='Email / Username')
project url
from django.contrib import admin
from django.urls import path,include
from django.conf import settings
from django.conf.urls.static import static
from django.views.generic import RedirectView
#new
from django_email_verification import urls as email_urls
urlpatterns = [
path('admin/', admin.site.urls),
path('accounts/', include('accounts.urls')),
path('email/', include(email_urls)),
]+static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
settings.py
STATIC_URL = '/static/'
AUTH_USER_MODEL = 'accounts.CustomUser' # new
AUTHENTICATION_BACKENDS = ['accounts.backends.EmailBackend'] # new
LOGIN_REDIRECT_URL = '/'
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = "smtp.gmail.com"
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = ''
EMAIL_HOST_PASSWORD = ''
DEFAULT_FROM_EMAIL = ''
def verified_callback(CustomUser):
CustomUser.is_active = True
EMAIL_VERIFIED_CALLBACK = verified_callback
EMAIL_FROM_ADDRESS = 'noreply#aliasaddress.com'
EMAIL_MAIL_SUBJECT = 'Confirm your email'
EMAIL_MAIL_HTML = 'mail_body.html'
EMAIL_MAIL_PLAIN = 'mail_body.txt'
EMAIL_TOKEN_LIFE = 60 * 60
EMAIL_PAGE_TEMPLATE = 'confirm_template.html'
EMAIL_PAGE_DOMAIN = ''

Basic Flask SQLAlchemy Context Issue

I've read many of the other posts on having models separated from the main app but I can't get it to work with just app.py (my actual app) and models.py (my database models).
If I do the following I get an app.db file with no tables:
from app import db
db.create_all()
If I do the following I get a RuntimeError: No application found. Either work inside a view function or push an application context.:
from app import db
db.create_all()
I have also looked at Introduction into Contexts page and can't work out where I put def create_app():, none of it seemed to work in my case.
Here is my app.py:
from flask import Flask, render_template, request
from flask_sqlalchemy import SQLAlchemy
from models import userTable
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
#app.route('/', methods=['GET', 'POST'])
def home():
return "home"
if __name__ == '__main__':
app.run(debug=True)
Here is my models.py:
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class userTable(db.Model):
__tablename__ = "userTable"
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
Perhaps you could try the following:
app.py
from flask import Flask, render_template, request
from flask_sqlalchemy import SQLAlchemy
import models
from models import initialize_db
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
initialize_db(app)
#app.route('/', methods=['GET', 'POST'])
def home():
return "home"
if __name__ == '__main__':
app.run(debug=True)
models.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
def initialize_db(app):
app.app_context().push()
db.init_app(app)
db.create_all()
class userTable(db.Model):
__tablename__ = "userTable"
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
The key is creating a database initialization function within models.py which takes the application instance as a parameter. This function only creates the database tables once it has its application instance. This will allow you to import the models module initially without an application instance and still have a modular design.

Syntax error def __repr__(self)

I'm just working my way through the book Flask Web Development. I'm stuck now and can't help myself.
This is the part of my code which makes the problem.
import os
from flask_script import Manager
from flask import Flask, render_template, session, redirect, url_for, flash
from flask_wtf import FlaskForm
from flask_bootstrap import Bootstrap
from flask_moment import Moment
from wtforms import StringField, SubmitField, validators
from wtforms.validators import Required
from flask_sqlalchemy import SQLAlchemy
class NameForm(FlaskForm):
name = StringField('What is your name?', validators=[Required()])
submit = SubmitField('Submit')
class Role(db.Model):
__tablename__ = 'roles'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True)
users = db.Column('User',backref='role')
def __repr__(self):
return '<Role %r>' % self.name
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), unique=True, index=True)
role_id = db.Column(db.Interger, db.ForeignKey('roles.id')
def __repr__(self):
return '<User %r>' % self.username
When I try to start the shell, I get the following error message:
line 30
def __repr__(self):
^
SyntaxError: invalid syntax
Guys where is the problem?
You are missing a closing brace ()) in this line:
role_id = db.Column(db.Interger, db.ForeignKey('roles.id')

Resources