For example, I have a table called BlackList in the database which looks like this:
and the model of the table is:
class BlackList(models.Model):
list = models.CharField(max_length=1000, null=True, blank=True)
What I try to do is:
if request.method == "POST":
username = request.POST.get('username') # Get username input first
password = request.POST.get('password')
user = authenticate(request, username=username, password=password)
BL = BlackList.objects.values_list('list', flat=True) # Read all data into array
if username in BL: # Check if the username is in blacklist
# Remove this username from the BlackList table
So my question is how to delete the special data for a special, for example, if 'aaa' try to log in, then 'aaa' will be removed or deleted from the BlackList table.
There is .delete method. I. e. try this:
if BlackList.filter(list=username).exists():
BlackList.objects.get(list=username).delete()
instead of:
BL = BlackList.objects.values_list('list', flat=True) # Read all data into array
if username in BL: # Check if the username is in blacklist
# Remove this username from the BlackList table
You can read more about that on https://docs.djangoproject.com/en/3.0/topics/db/queries/#deleting-objects and https://docs.djangoproject.com/en/3.0/ref/models/querysets/#exists
You can use filter() in combination with first() to get the exist username:
blacklist = Blacklist.objects.filter(username=username).first()
(This will return None if there is no match. If you use get(), you will get DoesNotExist error instead -- which is not preferred.)
After that, you can just delete it:
blacklist.delete()
It will take 2 queries (get and delete) to achieve your goal.
An alternative way is to delete it without getting the object:
Blacklist.objects.filter(username=username).delete()
This statement will be execute with only one query which is equals DELETE FROM ... WHERE username='username'
Related
I am trying to implement a function to change the user's password. I am storing only the hash in DB not the password and I want to ask the user to enter the old password first then the new one. I want to check if the old password's hash is matching the one stored in DB and if so, to update it with the new one. I am doing something wrong as the code is not passing the validation checks and I am having an error: "Invalid password".
Any help, would be appreciated.
#app.route("/change_password", methods=["GET", "POST"])
#login_required
def change_password():
user_id=session["user_id"]
if request.method=="POST":
password = request.form.get("password")
hash = generate_password_hash(password)
new_password = request.form.get("new_password")
confirm_new_password = request.form.get("confirm_new_password")
new_hash = generate_password_hash(new_password)
#Validations:
if not password:
return apology("must provide password", 400)
if not new_password:
return apology("must provide a new password", 400)
#Ensure password confirmation is provided
if not confirm_new_password:
return apology("must confirm new password", 400)
#Check if new password matches
if new_password!= confirm_new_password:
return apology("password does not match", 400)
# Query database for the current password
rows = db.execute("SELECT * FROM users WHERE hash = ?", hash)
# Ensure username exists and password is correct
if len(rows) != 1:
return apology("invalid password", 400)
#Update DB with the new_hash
else:
db.execute ("UPDATE users SET hash=:new_hash WHERE id=:id", new_hash = new_hash, id = user_id)
return redirect("/")
else:
return render_template("change_password.html")
There are quite some problems with your code...
The biggest problem
rows = db.execute("SELECT * FROM users WHERE hash = ?", hash)
You have to search for the user name, not for the hash!!! Imagine, two users have the same password, or a user enters the wrong password, but that is the password of another user...
I never used direct access to sqlite, only via sqlalchemy, but from a quick look at the docs ( https://docs.python.org/3/library/sqlite3.html#sqlite3.Cursor.executemany ) db.execute does not return e.g. rows, but you need to query it.
e.g. after your db.execute you need to do a db.fetchone or db.fetchall, see above linked documentation.
Also, the order of your code could be improved.
e.g. first, you generate the hash of a new password, and then afterwards you check whether there is a password at all - this should be switched.
Speaking of validation, much of it could be done via e.g. flask-wtforms, so you don't need so much validation code on your own.
I am running a website using Flask microframework and sqlite3 to store user logins. Currently, I am having trouble with matching the username and password entered by the user from an HTML form, with the existing records within my database.
I am using the flask-login extension to help me with this, and when I try and match, I am receiving a TypeError:
list indices must be integers or slices, not str
here is my python code that is turning the SQLite table into a variable:
con = sql.connect("table.db")
cur = con.cursor()
cur.execute('SELECT * FROM users')
names = cur.fetchall()
I then have this code which is taking the password from the HTML form, and trying to match it with the password linked to the username in the table
user_name = request.form['username']
if request.form['password'] == names[user_name]['password']:
user = User()
user.id = user_name
flask_login.login_user(user)
this is what 'names' returns:
[(7, 'ValidName', 'ValidTest', 'User#test.com'), (8, 'User2', 'password2', 'User#test2.com')]
What needs to happen is the program will check the form input for 'password' and will match it with the 'password' that is related to the username. So as an example, if ValidName and ValidTest were entered into the form, they would be requested by the program, and matched with the records found in 'names'.
I assume you have not hashed your password which is something you should do. Without security in mind
here is my dirty approach
cur.execute('SELECT * FROM users WHERE name = %s AND password = %s', (request.form['username'], request.form['password']))
user = cur.fetchone()
This can be helpful
Here is the guilty: names[user_name]['password']
names is the return value of fetchall and hence is a plain list. To use it in above expression, it should be a mapping of mappings.
You should construct it that way:
names = {row[1]: {'id': row[0], 'password': row[2], 'mail': row[3]}
for row in cur.fetchall()}
But beware: this loads the full user database in memory. It only makes sense if you have few users...
Here is my signup form,
class SignupForm(forms.ModelForm):
class Meta:
model = User
fields = ['first_name', 'last_name','username', 'email', 'password']
def clean_username(self):
username = self.cleaned_data.get('username')
email = self.cleaned_data.get('email')
if username and User.objects.filter(username=username).exclude(email=email).count():
raise forms.ValidationError('This username has already been taken!')
return username
This works well to check if there is same username presents or not. However it does not check for case insensitivity. If there is a username e.g. 'userone', then it also accepts a username with 'Userone'. Although it does not break any functionality, but looks very unprofessional.
My question is how can I check for case insensitive right in the forms, and raise error?
Sometimes I faced the same issue. Django considers username unique different in lower or upper case. Like if I enter John, it a unique username and if I enter john, it's a new username. I need to consider John and john not in the database. As simple as facebook do, both uppercase and lower case username name is same, unique.
So I achieve this just changing my signup code like this.
username = self.cleaned_data.get('username').lower()
Also, in my login code, I convert my username to lower.
So that, all time it saves username lower in the database and log in with lower case username. Although a user tries to login with upper case username, then it saves to the database by converting to lower case.
You can use __iexact here:
User.objects.filter(username__iexact=username).exclude(email=email).exists() # instead of count, used exists() which does not make any DB query
Simplest method I think is:
Use .exists() method, if true then validation error else return ❤
I'm working on a light login, and have a tabled titled Users. I'm trying to take my login form POST body and verify it across the database.
Values from form:
user = request.form['username']
password = request.form['password']
SQL Statement:
conn = sqlite3.connect(db)
cur = conn.cursor()
cur.execute("SELECT * FROM Users WHERE Username LIKE '(%s)'" % user)
row = cur.fetchone()
Users Table:
So on a POST request from my form, here is what is printed:
Print(user, password) = ph104694 Password123
Print(row) = None
So you can see the row is being returned as None when the data absolutely exists. If I change user to something I know is incorrect, I'm getting the same results, but if I change the table from Users to something like Users2 I'm met with a no table exists error which is fine. So despite matching data existing something about my statement isn't allowing it to produce that row. Any ideas?
You're search expression is evaluating to (ph104694) which clearly doesn't exist in the data you showed.
There is no reason to use the LIKE operator here and it probably runs counter to what you want to do (match the single record exactly matching the user ID that was entered).
This is the classic example of code that is subject to an SQL injection attack. You should never, never, ever use string interpolation to build an SQL string like this. Instead, use parameter substitution.
Taken all together, you want something like this:
cur.execute("SELECT * FROM Users WHERE Username = ?", [user])
Your query string evaluates to "SELECT * FROM Users WHERE Username LIKE '(ph104694)'".
Note the parentheses which aren't in the actual username.
Also, you almost certainly don't want to use LIKE.
What you want is "SELECT * FROM Users WHERE Username = 'ph104694'"
Which would create with "SELECT * FROM Users WHERE Username = '{user}'".format(user=user)
Also, you can (and should) parameterize this as
cur.execute("SELECT * FROM Users WHERE Username = :user", {user: user})
I am trying to register a new user on the site,
class UserInfo(models.Model):
user = models.ForeignKey(User,primary_key=True)#user profile
email_id=models.CharField(max_length=32, null=True, blank=True)
When I am registering the user, I am getting stuck by Integrity Error, please help me to resolve the problem.
def registration(request):
registration_dict = {}
if 1==1 :
#if request.POST:
#username=request.POST['email']
#password=request.POST['password']
username="admin#admin.com"
password='123456'
#try:
UserInfo.objects.get_or_create(email_id=username,user__username=username,user__email=username,user__password=password)
#except:
# registration_dict["status"]="0"
# registration_dict["message"]="Username already present"
# return HttpResponse(simplejson.dumps(registration_dict),content_type="application/json")
registration_dict["status"]="1"
registration_dict["message"]="Thank You for registering"
return HttpResponse(simplejson.dumps(registration_dict),content_type="application/json")
else:
registration_dict["status"]="0"
registration_dict["message"]="Unable to process the request"
return HttpResponse(simplejson.dumps(registration_dict),content_type="application/json")
EDIT 1
I have tried changing
UserInfo.objects.get_or_create(email_id=username,user__username=username,user__email=username,user__password=password,user_id=1)
and then the error changes, to
'Cannot add or update a child row: a foreign key constraint fails (`app_info`.`appdata_userinfo`, CONSTRAINT `user_id_refs_id_b0fd803b` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`))')
From the limited information I would say the problem is
it does not find a UserInfo that matches. It then tries to create a new UserInfo, but it has no User to assign to the User ForeignKey. I would suggest the following:
user = authenticate(username=email, password=password)
if user is None:
user = User(username=email, password=password, email=email)
user_info = UserInfo.objects.get_or_create(user=user, email_id=email)
If the original User object doesn't exist, you'll run into all kinds of problems. So, you need to break the process down into two steps.
Check if a User object exists or not, if it doesn't create it.
Check if a UserInfo object exists for that user, if it doesn't create it.
As there is a ForeignKey, you cannot do it in one step:
username = "admin#admin.com"
password = '123456'
obj, created = User.objects.get_or_create(username=username)
obj.set_password(password) # the proper way to set the password
obj.save()
# Now fetch or create a UserInfo object
info, created = UserInfo.objects.get_or_create(email_id=username,user=obj)
I cant understand why you need UserInfo because email is already there in User.
Issue can be corrected by splitting the fetching process
username = "admin#admin.com"
password = '123456'
user,status = User.objects.get_or_create(username=username, password=password)
user_info = UserInfo.objects.get_or_create(user=user,email_id=username)