Unable to insert data into MySQL DB using flask-SQLAlchemy - flask

I have a flask app that connects to a MySQL DB and retrieves the data but it cannot insert anything into it. I am using flask-SQLAlchemy and the form is generated using flaskwtforms. Below is the model
class Name(db.Model):
__tablename__ = 'names'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(45), nullable=False)
password = db.Column(db.String(45), nullable=False)
def __init__(self, id, name, password):
self.id = id
self.name = name
self.password = password
def __rep__(self):
return '<User %r>' % self.username
Below is the form itself
class AddUser(FlaskForm):
name = StringField(label= 'username', validators = [InputRequired('Username is required')])
password = StringField(label = 'password', validators = [InputRequired('Password is required')])
Below is the view function
#app.route('/add_user', methods=['GET','POST'])
def add_user():
form = AddUser()
if request.method == 'POST' and form.validate_on_submit():
name = form.name.data
password = form.password.data
name = Name(name,password)
db.session.add(name)
db.session.commit()
return render_template('add-user.html')
else:
return render_template('add-user.html', form=form)

I found the solution to my problem. So in my database, the id is set as the primary key and is auto-generated hence it does not need to be passed in the constructor since my query would also require me to pass an id.

Related

creating a flask form which uses data from another table as input

I am just beginning with python and flask and am looking to create an app. The app allows users to enter their favourite artists in one page. In the next page then allows the user to enter favourite tracks using SelectField where the artist names are given as the options.
I have the following
models:
from application import db
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField, BooleanField, IntegerField, SelectField
class Artist(db.Model):
id = db.Column(db.Integer, primary_key=True)
artist_name = db.Column(db.String(45), nullable=False)
music_artist = db.relationship('Music', backref='musicbr')
def __repr__(self):
return 'Choose {}'.format(self.artist_name)
class Music(db.Model):
id = db.Column(db.Integer, primary_key=True)
track_name = db.Column(db.String(45), nullable=False)
artist_id = db.Column(db.Integer, db.ForeignKey('artist.id'), nullable=False)
class AddArtistForm(FlaskForm):
artist_name = StringField('Artist Name')
submit = SubmitField('Add Artist!')
class AddMusicForm(FlaskForm):
track_name = StringField('Track Name')
artist_name = SelectField('Artist Name', coerce=int)
submit = SubmitField('Add Track!')enter code here
and the following routes
#app.route('/')
def home():
return render_template('index.html')
#app.route('/add_artist', methods = ['GET', 'POST'])
def add_artist():
form = AddArtistForm()
if form.validate_on_submit():
new_artist = Artist(artist_name =form.artist_name.data)
db.session.add(new_artist)
db.session.commit()
return render_template('index.html', message="Artist Added!")
else:
return render_template('add_artist.html', form=form)
#app.route('/add_music', methods = ['GET', 'POST'])
def add_music():
form = AddMusicForm()
if form.validate_on_submit():
new_track = Music(track_name =form.track_name.data)
artist_choice = Artist.query.all(artist_name=form.artist_name.data)
db.session.add(new_track)
db.session.commit()
return render_template('index.html', message="Track Added!")
else:
return render_template('add_music.html', form=form)
Is someone able to help me to understand what code I need to implement here?

Wtform nested fields not populated with populate_obj

So I have this DemandeForm with nested FormField:
AdressePrivee = FormField(AdresseForm, default=AdressePrivee())
with Demande model:
AdressePrivee = db.relationship(AdressePrivee, backref='Demande', lazy=False, uselist=False)
I have nested fields submitted in the HTML form:
AdressePrivee-RueEtNumero: Boulevard Bonivard 11
AdressePrivee-ComplementNom:
AdressePrivee-ComplementAdresse:
AdressePrivee-CasePostale: 01420
AdressePrivee-NPA:
AdressePrivee-Localite: Seyssel
AdressePrivee-Pays: 2
And I call it with:
form = DemandeForm(data=request.form)
if form.validate():
form.populate_obj(demande) # Here, demande.AdressePrivee should be populated
db.session.add(demande)
db.session.commit()
flash('Enregistré', 'success')
return redirect(url_for('main.index'))
But if I print it there, all entries are set to None, as if demande.AdressePrivee is only equal to AdressePrivee() empty object (log: <AdressePrivee None None None>), while FormFields should be set, with the nested fields logic, shouldn't they?
Am I missing something?
I think you can't use the constructor directly, you should use a factory.
AdressePrivee = FormField(AdresseForm, default=lambda: AdressePrivee())
I also think the attribute for transferring the form data of the request is called "formdata" not "data".
form = DemandeForm(formdata=request.form)
In the following a small example that worked for me.
class Address(db.Model):
id = db.Column(db.Integer, primary_key=True)
street = db.Column(db.String, nullable=False)
class Inquiry(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String, nullable=False)
address_id = db.Column(db.Integer,
db.ForeignKey('address.id', ondelete='cascade'),
nullable=False
)
address = db.relationship('Address', backref='inquiry', lazy=False, uselist=False)
class AddressForm(FlaskForm):
street = StringField('street', validators=[DataRequired()])
def __init__(self, csrf_enabled=False, *args, **kwargs):
super().__init__(csrf_enabled=csrf_enabled, *args, **kwargs)
class InquiryForm(FlaskForm):
title = StringField('title', validators=[DataRequired()])
address = FormField(AddressForm, default=lambda: Address())
#app.route('/new', methods=['GET', 'POST'])
def create():
item = Inquiry()
form = InquiryForm(request.form)
if form.validate_on_submit():
form.populate_obj(item)
db.session.add(item)
db.session.commit()
items = Inquiry.query.all()
return render_template('create.html', **locals())
I wish you every success in implementing your project and hope I was able to help you.

flask-login check user_loader between three tables

I am using Flask==1.0.2 and Flask-Login==0.4.1, I need to check the login (email and password) between three tables in Postgres Database, we are using SQLAlchemy, the three tables have the fields (email and password).
tbl_employees
tbl_clients
tbl_partners
But I'm having trouble using the three tables with:
#login_manager.user_loader
def load_user (user_id):
return UserModel.get (user_id)
I had a similar problem. I have 2 tables that contain user authentication info and was having trouble implementing user_loader. I used session to solve this problem:
models.py
from flask_login import UserMixin
class lab_login(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(100), nullable=False, unique=True)
password = db.Column(db.String(512), nullable=False)
lab_name = db.Column(db.String(100), nullable=False)
phone = db.Column(db.String(15))
class regular_login(db.Model, UserMixin):
id = db.Column(db.Integer, primary_key=True)
email = db.Column(db.String(100), nullable=False, unique=True)
password = db.Column(db.String(100), nullable=False)
first_name = db.Column(db.String(100), nullable=False)
last_name = db.Column(db.String(100), nullable=False)
phone = db.Column(db.String(15))
In the code below, the most important part is the session['type'] = 'lab' and session['type'] = 'regular'. For your case, you could swap out these values for employees/clients/partners.
auth.py
#auth_bp.route("/lab", methods=['GET', 'POST'])
def lab_login():
if request.method == 'POST':
email = request.form["email"]
password = request.form["password"]
lab = lab_login.query.filter_by(email = email).first()
if lab:
if check_password_hash(lab.password, password):
login_user(lab, remember = False)
session.permanent = True
session['type'] = 'lab'
flash('Login successful!', category='success')
return redirect(url_for('views.index'))
else:
flash('Incorrect password. Please try again.', category = 'error')
else:
flash('That email is not associated with an account.', category = 'error')
return render_template('lab_login.html', user = current_user)
#auth_bp.route("/regular", methods=['GET', 'POST'])
def regular_login():
if request.method == 'POST':
email = request.form["email"]
password = request.form["password"]
user = regular_login.query.filter_by(email = email).first()
if user:
if check_password_hash(user.password, password):
login_user(user, remember = True)
session.permanent = True
session['type'] = 'regular'
flash('Login successful!', category = 'success')
return redirect(url_for('views.index'))
else:
flash('Incorrect password. Please try again.', category = 'error')
else:
flash('That email is not associated with an account.', category = 'error')
return render_template('user_login.html', user = current_user)
And now for the revised user_loader function:
config.py
from flask import session
from flask_login import LoginManager
#login_manager.user_loader
def load_user(id):
type = session.get('type')
if type == 'lab':
user = lab_login.query.filter_by(id = id).first()
elif type == 'regular':
user = regular_login.query.filter_by(id = id).first()
else:
user = None
return user

Flask is not loading user id from model

I am trying to write login app using flask.
My View.py look like
#lm.user_loader
def load_user(id):
if id is None or id == 'None':
id =-1
print 'ID: %s, leaving load_user' % (id)
return Users.query.get(int(id))
and another login method is
#app.route('/login',methods=['GET','POST'])
def login():
form = LoginForm()
if request.method == 'GET':
return render_template('login.html',
title = 'Sign In',\
form = form)
username = form.username
password = form.password
user = Users(nickname = form.username, email = 'sanjeev_yadav248#yahoo.com', role =
ROLE_USER)
if user is None:
flash('Username or Password is invalid' , 'error')
return redirect(url_for('login'))
remember_me = False
if 'remember_me' in session:
remember_me = session['remember_me']
session.pop('remember_me', None)
login_user(user)
flash("Logged in successfully.")
return redirect(request.args.get("next") or url_for("index"))
My model(model.py) class is
class Users(db.Model):
id = db.Column(db.Integer, primary_key = True)
nickname = db.Column(db.String(64), unique = True)
email = db.Column(db.String(120), index = True, unique = True)
role = db.Column(db.SmallInteger, default = ROLE_USER)
posts = db.relationship('Post', backref = 'author', lazy = 'dynamic')
def is_authenticated(self):
return True
def is_active(self):
return True
def is_anonymous(self):
return False
def get_id(self):
return unicode(self.id)
def __repr__(self):
return '<User %r>' % (self.nickname)
My databsase users table is having id,nickname,emailid and role.
This nick name is having sanjeev as a value and associated id with it for example 3. But when I run it, load_user() method id is not populated. i.e it is 'None'. When I hardcode id in load_user method its work fine. for example if I put return Users.query.get(3). Let me know if you guys have any clue in this regard.

Adding ForeignKey to UserProfile giving foreign key constraint fails

I've been trying to figure this out for hours, and believe me, I really looked everywhere on Stack Overflow.
In my UserProfile, I have a ForeignKey reference to another model (called "Company"), and upon registration, I create a new Company and point my UserProfile ForeignKey to that Company.
models.py is as follows:
class UserProfile(models.Model):
company = models.ForeignKey(Company)
title = models.CharField(max_length = 50, default = '')
user = models.OneToOneField(User, default = 0, null = True)
class Company(models.Model):
"""A company profile."""
name = models.CharField(max_length = 50)
I use a Form to do the signing up. Here's the form:
class SignupForm(ModelForm):
name = forms.CharField(label = "Name")
company = forms.CharField(max_length = 50)
email = forms.EmailField(label = "Email")
password = forms.CharField(widget=forms.PasswordInput)
class Meta:
model = User
fields = ("name", "company", "email", "password")
def save(self, commit=True):
user = super(SignupForm, self).save(commit=False)
name = self.cleaned_data["name"].split()
if len(name) == 1:
# User did not enter a last name.
user.first_name = name
else:
user.first_name, user.last_name = name
user.email = self.cleaned_data["email"]
user.set_password(self.cleaned_data["password"])
user.username = user.email
if commit:
user.save()
return user
and here's the signup view:
def signup(request):
if request.method == 'POST':
form = SignupForm(request.POST)
if form.is_valid():
# Check if email has already been used for an account.
email = request.POST['email']
existing_account = User.objects.filter(email = email)
if existing_account:
form = SignupForm()
return render_to_response('registration/signup.html',
{ 'form': form,
'error': 'duplicate_email',
})
# Otherwise, save the form and create a new user.
new_user = form.save()
company = Company(name=request.POST['company'])
company.save()
user_profile = new_user.get_profile()
user_profile.company = company
user_profile.save()
new_user = authenticate(
username = email,
password = request.POST['password']
)
# Log the user in automatically.
login(request, new_user)
# Redirect user to Thank You page.
return HttpResponseRedirect('/thanks')
else:
form = SignupForm()
return render_to_response('registration/signup.html', {
'form': form,
})
The error I am getting is telling me that company_id cannot be null. I clearly add a new Company. Please let me know what you think might be wrong.
Thanks
I've had this exact error today, with no reason, except that it was caused by SQLite. With SQLite, the id field of one table went from INTEGER PRIMARY KEY to INTEGER. If you're using SQLite, try deleting the offending table and recreate it with a syncdb.
What is the value of
user_profile = new_user.get_profile()
?
Not sure if this feels too hackish for your tastes but perhaps you could create/save the Company object and pass it in to your SignupForm.save() method as a positional/keyword argument.
The issue you'd get there is that you'd be expecting a CharField and you'd be passing in a company object. So you'd probably want to give company.pk to the company field in your form.