SQLAlchemy error "on delete" - database

i´m new to Flask and i´m trying to delete a user.
I can already create a user, it is saying that 1 argument is missing:
add_user.html
<form method="POST" action="/del_user">
<label> ID: </label>
<input id="id" name ="id" type="text" />
<input type="submit" value="Delete"/>
</form>
app.py
from flask import Flask, render_template, request, redirect, url_for
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
#Set the application in debug mode so that the server is reloaded on any code change & helps debug
app.config['DEBUG'] = True
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://postgres:********#localhost/projetofinal'
db = SQLAlchemy(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
email = db.Column(db.String(120), unique=True)
def __init__(self, username, email):
self.username = username
self.email = email
def __repr__(self):
return '<User %r>' % self.username
#app.route('/')
def index():
return render_template('add_user.html')
#app.route('/post_user', methods=['POST'])
def post_user():
user = User(request.form['username'], request.form['email'])
db.session.add(user) #add object
db.session.commit() #save
return redirect(url_for('index'))
#app.route('/del_user', methods=['POST'])
def del_user():
user = User(request.form['id']) #ERROR LINE
user1 = db.session.query(User).filter(User.id==user.id).first()
db.session.delete(user1)
db.session.commit()
return redirect(url_for('index'))
if __name__=="__main__":
app.run()
TypeError: init() missing 1 required positional argument: 'email'

Just get the id from the form, turn it into an integer and query the database for it.
#app.route('/del_user', methods=['POST'])
def del_user():
user = int(request.form['id'])
user1 = db.session.query(User).filter(User.id==user.id).first()
db.session.delete(user1)
db.session.commit()
return redirect(url_for('index'))
Additionally check if your db query returns a user object to make sure you don't attempt to delete a non existent user and get another error
if user1:
db.session.delete(user1)
else:
flash('the record requested was not found')
return redirect(url_for('index'))
see how to use flash here to show error messages etc elegantly
Lastly, Instead of deleting using text input, you can use select that uses already existing users so that the value is the user id and the option text is the user name to make sure attempt to delete only uses existing user ids

Related

How to alter AbstractUser Modelfields with POST request?

I have a custom AbstractUser model that I'm using with couple of model fields, and I am trying to figure out how to alter those values from outside such as frontend or another APIView.
I'm not quite sure how to tackle this, please read below:
React Frontend
This is how I want to set user fields from frontend. For example, I would set user's birthday to certain date from frontend
axios
.post(`${process.env.NEXT_PUBLIC_API_URL}/auth/users/me/`, userData, {
withCredentials: true,
})
.then(function (response) {
alert(response.data);
console.log(response.data);
});
Currently, making this request will return a 405 Method Not Allowed error.
I am also looking for ways to alter user fields in outside from outer APIViews, so I can only take the information from frontend and do the actual work inside APIView.
users/api.py
class UserMeApi(ApiAuthMixin, ApiErrorsMixin, APIView):
def get(self, request, *args, **kwargs):
return Response(user_get_me(user=request.user))
# returns logged in user fields such as name, email, tokens, etc currently.
def post(self, request):
"""
Don't know what should go here
"""
users/models.py
class User(AbstractUser):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
username = None
first_name = models.CharField(max_length=100, default="unknown")
last_name = models.CharField(max_length=100, default="unknown", blank=True)
profile_pic = models.CharField(max_length=200, default="unknown")
premium = models.BooleanField(default=False)
tokens = models.IntegerField(default=0)
email = models.EmailField(unique=True, db_index=True)
secret_key = models.CharField(max_length=255, default=get_random_secret_key)
USERNAME_FIELD = "email"
REQUIRED_FIELDS = []
objects = UserManager()
class Meta:
swappable = "AUTH_USER_MODEL"

Backend Validation error message using django

While Giving Correct username and password in login page its working correctly,while giving wrong username and password,how to show the error message.
views.py
def user_login(request):
logout(request)
username = password = ''
username = request.POST.get('username')
print(username)
password = request.POST.get('password')
print(password)
if request.POST:
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
auth_login(request, user)
return render(request, 'admin_pannel.html', { 'dept' : dt, 'ds' : ds })
return redirect('/dashboard/')
return render(request, 'registration/login.html', {'dt' : dt })
Error messages are usually handled by an instance of django.forms.forms.Form. For your view I would suggest something like this:
from django.contrib.auth.forms import AuthenticationForm
def user_login(request):
if request.method == 'POST':
logout(request)
form = AuthenticationForm(request.POST)
if form.is_valid():
user = form.get_user()
auth_login(request, user)
return render(request, 'admin_pannel.html', {...})
else:
form = AuthenticationForm()
return render(request, 'registration/login.html', {'form': form, ...})
A quick glance at AuthenticationForm.clean looks like it will accomplish the same thing that you are doing in your view.
The only other thing that comes to mind is Django's messages framework, but I don't think that would be your best option.

Django - save form into database

Hey guy I need your help
so I have this model:
class PreferedShops(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
shop = models.ForeignKey(Shops, on_delete=models.CASCADE)
date_posted = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.user.username, self.shop.name
and this is the form:
class LikeShopForm(forms.ModelForm):
class Meta:
model = PreferedShops
fields = ['date_posted']
and this is the view:
def shops(request):
if request.method == 'POST':
form = LikeShopForm(request.POST)
if form.is_valid():
u = form.save(commit=False)
u.user = request.user
u.shop = request.shop
u.save()
return redirect('shops')
else:
form = LikeShopForm()
return render(request, "shops.html", {'form': form})
the probleme that I have is when I click on Like Button, I want that the form takes automatically the user and the name of the shop, and then save them into the DB
the user and the shop's name should be hidden
when I click submit I have this error 'WSGIRequest' object has no attribute 'shop'
please help me to take the shop's name automatically and save it in the db
Well the shop is not part of the request (strictly speaking, user is not either, but it is frequently added to the request object in the middelware by looking at the session).
You thus need to encode it into the URL, or in the POST parameters. For example with:
# app/urls.py
from django.urls import path
from app.views import like_shop
urlpatterns = [
path('shop/<int:shop_id>/like', like_shop, name='like_shop'),
]
Then in the view we obtain a parameter shop_id that contains the id of the related Shops object:
from django.shortcuts import get_object_or_404
from app.models import Shops
def like_shop(request, shop_id):
if request.method == 'POST':
shop = get_object_or_404(Shops, id=shop_id)
form = LikeShopForm(request.POST)
if form.is_valid():
u = form.save(commit=False)
u.user = request.user
u.shop = shop
u.save()
return redirect('shops')
else:
form = LikeShopForm()
return render(request, "shops.html", {'form': form, 'shop_id': shop_id})
Then the request in the POST should point to:
<!-- shops.html -->
<form action="{% url 'like_shop' shop_id=shop_id %}" method="post">
<!-- ... -->
</form>
The URL to this page then thus looks like /shops/123/like with 123 the id of the shop. If you thus want to pass the shop "implicitly", you need to encode it in the URL. Otherwise, you should make it a field of the form, such that the user can pick an option. Personally I find it very strange that you use date_posted as a form field, since typically this is an field that I would expect to be filled in with the timestamp when the user likes the shop.
Note: the name of the models is normally singular, so Shop instead of Shops.

Django session with angular.js

I have set a view Index(View) to load a view for angular and it works fine. Angular communicates with Django and maintains session (Token base).
class Index(TemplateView):
context = {}
permanent = False # docs.djangoproject.com/en/1.9/ref/class-based-views/base/
template_name = 'index.html'
def __init__(self):
self.context = _.default_context()
self.response = _.default_response()
def get(self,request, *args, **kwargs):
return _.render_view(request, self.template_name, self.context)
def post(self, request, *args, **kwargs):
_.process_request(request)
print request.POST
username = request.POST['username']
password = request.POST['password']
print password
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
auth_token,_ignore = Token.objects.get_or_create(user=user)
self.response['status']=True
self.response['statusCode']=200
self.response['data'] = {'token':auth_token.key}
self.response['user'] = {'email' : user.email,
'first_name' : user.first_name,
'last_name' : user.last_name}
else:
self.response['status']=False
self.response['statusCode']=203
self.response['data']=[]
else:
self.response['status']=False
self.response['statusCode']=404
self.response['data']=[]
return _.serialize_response(self.response)
Now anyone can access this page. I want to restrict user to access dashboard without login (in the case a user tries to hack by adding cookie or something).
If I create separate pages for login and angular:
How can I handle different pages in one angular app?
Do I have to create angular app intent?
Something in Django?

Django ImageField Upload

I am trying to use Django ImageField to allow a user to upload a profile picture. However, after browsing for the image, when I attempt to update the profile, the picture upload changes from the file name to "No file selected" and I receive "This file is required" error.
If it helps, I was following along with this tutorial. I do understand that he uses two character fields, but I was attempting to change it to handle FileFields. From other questions such as this one on stack overflow, I know that the form requires a request.FILES as well.
Here is my Views.py.
#login_required
def user_profile(request):
if request.method == 'POST':
form = UserProfileForm(request.POST, request.FILES, instance=request.user.profile)
if form.is_valid():
form.save()
return HttpResponseRedirect('/accounts/loggedin')
else:
user = request.user
profile = user.profile
form = UserProfileForm(instance=profile)
args = {}
args.update(csrf(request))
args['form'] = form
return render_to_response('profile.html', args)
Additionally, I have these two lines in my settings.
AUTH_PROFILE_MODULE = 'userprofile.UserProfile'
MEDIA_ROOT = 'E:\Pictures\django_stuff'
Let me know if there is anything else that is required.
As requested by Erny
Forms.py
from django import forms
from models import UserProfile
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('logo', 'description')
Models.py
class UserProfile(models.Model):
user = models.OneToOneField(User)
logo = models.ImageField(upload_to = 'photos')
description = models.TextField()
User.profile = property(lambda u: UserProfile.objects.get_or_create(user=u)[0])

Resources