i just created a custom user model from abstractuser. I can create user but update is not working showing some error. I am also week in english so idk how to share my problem. In short hand i want to edit email and password of a user.
###This is my user model
class User(AbstractUser):
roles =(
('Admin','Admin'),
('Placement Manager','Placement Manager'),
)
username=models.CharField(max_length=100,null=True,blank=True)
email = models.EmailField(max_length=50, null=True,blank=True)
phone = models.IntegerField(unique=True)
role = models.CharField(max_length=100,choices = roles,null=True,blank=False)
USERNAME_FIELD = 'phone'
REQUIRED_FIELDS = ['email','username','role']
objects=UserManager()
def get_username(self):
return self.email
###This is my view
def editPlacementManager(request):
if request.method=='POST':
name=request.POST.get('name')
phone=request.POST.get('phone')
email=request.POST.get('email')
password=request.POST.get('password')
userid = request.POST.get('pmId')
User.objects.get(id=userid).update(username=name,phone=phone,email=email,password=password,role='Placement Manager')
return redirect('listplacementmanager')
return render(request,"index/placementmanager.html")
### The error is
AttributeError at /editplacementmanager
'User' object has no attribute 'update'
Yh, you'll get that error because the update method is available for only querysets.
So you can do this:
def editPlacementManager(request):
if request.method=='POST':
name=request.POST.get('name')
phone=request.POST.get('phone')
email=request.POST.get('email')
password=request.POST.get('password')
userid = request.POST.get('pmId')
user = User.objects.get(id=userid)
user.name = name
user.phone = phone
user.email = email
# You can continue with whichever field you want
user.save()
# Then finally you save the object with the updated fields
return redirect('listplacementmanager')
return render(request,"index/placementmanager.html")
actually it's a simple thing just hash the password and update.
Related
I am working on a Django Ticketing project where I want guest to activate Ticket PIN and then register for the event they bought the ticket for. And I also want them to have login user access and be able to update profile immediately after login.
The application usually start with PIN activation and thereafter guest registration. The issue is that I don't know how to pass the PIN value from the PIN activation view to the guest registration view.
Notice that I have used request.session['pin'] = pin_value to set the PIN as the session variable in the pin activation view and got it using user_pin = request.session.get('pin') in the register guest view but only the Guest.objects.create(guest_name=new_user, pin=user_pin) in the register guest view gets the session variable while the Pin.objects.filter(value=user_pin).update(status='Activated') fails to get the session variable for the registration process to be completed. I have tried using a literal value in the Pin filter and update query and it worked but using the session variable does not.
Below are my models:
class Guest(models.Model):
guest_name = models.OneToOneField(User, on_delete=models.CASCADE, blank=True)
pin = models.CharField(max_length=6, default='No Pin', blank=True)
def __str__(self):
return f"{self.guest_name}"
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, null = True)
surname = models.CharField(max_length=20, null=True)
othernames = models.CharField(max_length=40, null=True)
gender = models.CharField(max_length=6, choices=GENDER, blank=True, null=True)
phone = PhoneNumberField()
image = models.ImageField(default='avatar.jpg', blank=False, null=False, upload_to ='profile_images',
)
def __str__(self):
return f'{self.user.username}-Profile'
class Pin(models.Model):
ticket = models.ForeignKey(Ticket, on_delete=models.CASCADE)
value = models.CharField(max_length=6, default=generate_pin, blank=True)
added = models.DateTimeField(auto_now_add=True, blank=False)
reference = models.UUIDField(primary_key = True, editable = False, default=uuid.uuid4)
status = models.CharField(max_length=30, default='Not Activated')
#Save Reference Number
def save(self, *args, **kwargs):
self.reference == str(uuid.uuid4())
super().save(*args, **kwargs)
def __unicode__(self):
return self.ticket
class Meta:
unique_together = ["ticket", "value"]
def __str__(self):
return f"{self.ticket}"
def get_absolute_url(self):
return reverse("pin-detail", args=[str(self.id)])
My Views code:
def pin_activation(request):
if request.method == "POST":
#Create PIN form
form = PinActivationForm(request.POST)
#Get User Pin Value from Form
pin_value = form['pin'].value()
#Check if the the form has valid data in it
if form.is_valid():
try:
#Get user Pin with the one in the Database
check_pin_status = Pin.objects.get(value=pin_value)
except Pin.DoesNotExist:
messages.error(request, f'{pin_value} Does Not Exist')
return redirect('pin-activation')
else:
#Check PIN status
if check_pin_status:
#Get Event Ticket Date of the PIN
event_date = check_pin_status.ticket.event.date
#Get Current Date
current_date = datetime.now().date()
#Check if Event Date is Passed the Current Date
if event_date < current_date:
messages.error(request, 'Event Has Passed')
return redirect('pin-activation')
else:
#Update the User Pin with a new status of Activated
Pin.objects.filter(value=form['pin'].value()).update(status='Validated')
#Message the User
messages.success(request, 'Pin Validated Successfully')
#Redirect the user to register for seat
return redirect('register-guest')
#Check filter the DB where the PIN status is Validated
request.session['pin'] = pin_value
elif Pin.objects.filter(value=form['pin'].value(), status="Validated"):
messages.error(request, 'Pin Already Validated. Register for Seat')
return redirect('register-guest')
#Check Filter PIN in DB where Status is Activated
elif Pin.objects.filter(value=form['pin'].value(), status="Activated"):
messages.error(request, "Pin Already Activated, Login.")
return redirect('user-login')
else:
messages.error(request, 'Something Went Wrong. Try again')
else:
form = PinActivationForm()
context = {
'form':form,
}
return render(request, 'user/pin_activation.html', context)
def register_guest(request):
#get session variable
user_pin = request.session.get('pin')
form = GuestUserForm(request.POST)
page_title = "Festival Registration"
if request.method == 'POST':
form = GuestUserForm(request.POST)
pin_form = PinActivationForm(request.POST)
if form.is_valid() and pin_form.is_valid():
new_user = form.save()
Guest.objects.create(guest_name=new_user, pin=user_pin)
Pin.objects.filter(value=user_pin).update(status='Activated')
messages.success(request, 'Registered Successfully. Login')
return redirect('user-login')
else:
form = GuestUserForm()
pin_form = PinActivationForm()
context = {
'form':form,
'pin_form':pin_form,
'page_title':page_title,
}
return render(request, 'user/register.html', context)
Someone should please help with the best way of solving this problem. Thanks
you cannot save a quest as a User in this way.
Do something like this.
From youre form get the username.
Then create a new User with that username and create the Guest with that new user.
//simple form --> get it in youre template
class GuestUserForm(forms.Form):
username = forms.CharField()
password=forms.CharField()
//create new user from the form in template
user_guest = form.cleaned_data.get("username")
new_user = User.objects.create_user(username=user_guest)
//create new guest with created user
Guest.objects.create(guest_name=new_user)
//youre view function
def register_guest(request):
if request.method == 'POST':
form = GuestUserForm(request.POST)
if form.is_valid():
user_guest = form.cleaned_data.get("username")
print(user_guest)
new_user = User.objects.create_user(username=user_guest)
Guest.objects.create(guest_name=new_user)
form = GuestUserForm()
return render(request, "index.html",{"form":form})
So Django has this cool feature where you can annotate a query set as in you can add attributes to each object in a query set. For example if I have a query set of users I can annotate it with number of followers which is another table with a foreign key reference to user. This can be done with the QuerySet.annotate() function. I was wondering if this is possible for a single Django object. I have a view function that gets user info, which given a unique user UUID I return the users info in the user table as well as the number of followers and followees. 1 way to do this is just query across all follower and followee table for the uuid and create a dictionary that gets returned. Or create a serializer with all the fields than annotate the single Django object like you can with a query set. Is it possible to do this?
views.py
#api_view(['GET'])
def get_user_info(request, user_uuid):
is_current_user = user_uuid == str(request.user.uuid)
# Return all user info including # of followers and followees
models.py
class User(AbstractDatesModel):
uuid = models.UUIDField(primary_key=True)
username = models.CharField(max_length=USERNAME_MAX_LEN, unique=True, validators=[
MinLengthValidator(USERNAME_MIN_LEN)])
created = models.DateTimeField('Created at', auto_now_add=True)
updated_at = models.DateTimeField('Last updated at', auto_now=True, blank=True, null=True)
avatar = models.ImageField(upload_to=avatar_directory_path, blank=True, null=True)
class FollowUser(AbstractSimpleModel):
follower = models.ForeignKey(
User, on_delete=models.CASCADE, related_name='follower_id')
followee = models.ForeignKey(
User, on_delete=models.CASCADE, related_name='followee_id')
I tried this in views2.py, but the issue is that it doesn't properly just return the avatar url. serializer.serialize keeps avatar as an ImageFieldFile in the serialized user object.
views2.py
#api_view(['GET'])
def get_user_info(request, user_uuid):
is_current_user = user_uuid == str(request.user.uuid)
if is_current_user:
user_object = request.user
else:
try:
user_object = User.objects.get(uuid=user_uuid)
except User.DoesNotExist as e:
return Response(dict(error=str(e),
user_message='User does not exist.'),
status=status.HTTP_404_NOT_FOUND)
user_dict = model_to_dict(user_object)
user_dict['follower_count'] = len(FollowUser.objects.filter(followee=user_uuid))
user_dict['followee_count'] = len(FollowUser.objects.filter(follower=user_uuid))
user_dict['is_following'] = FollowUser.objects.filter(followee=user_uuid, follower=str(request.user.uuid)).exists()
return Response(user_dict, status=status.HTTP_200_OK)
#api_view(['GET'])
def get_user_info(request, user_uuid):
query = User.objects.filter(pk=user_uuid)
if query.exists():
query_annotated = query.annotate(
follower_count=Count('followee_id', distinct=True),
followee_count=Count('follower_id', distinct=True),
is_following=Count('followee_id', filter=Q(follower_id=str(request.user.uuid))))
else:
return Response(dict(error=str('User not found.'),
user_message='User not found.'),
status=status.HTTP_404_NOT_FOUND)
serializer = FullUserSerializer(query_annotated[0])
return Response(serializer.data, status=status.HTTP_200_OK)
Maybe a solution? But is_following isn't returning the correct values in my tests.
I am a beginner and I'm still learning Django. I am writing my custom form validation for user profile update. My profile update form has -
username
first name
last name
profile image
First I have used default form validation. It is also good but I want to update the error message so I tried to create a custom validation function as I seen in a post in Stack Overflow. Please also check my username validation in forms.py
So what is the error now?
Now I am facing one more issues
If I click on update button without changing anything then it shows can't use this username. {username is set to unique=True in model fields}
If I don't update username and update just first name and last name. It doesn't allow this says same error. "Username is already taken" {because that username is validated and it already taken by current user"}
What exactly I want?
Instead of changing just error message now I want to write my own validation for this. I want if some click on update without changing any data no error message should be shown.
I can update each field independently. No error message should be shown if i don't update username.
My Views
#login_required()
def profile(request):
if request.method=='POST':
u_form = UserUpdateForm(request.POST,request.FILES,instance=request.user)
if u_form.is_valid():
u_form.save()
messages.success(request, f'Profile Updated Succesfully')
redirect('profile/')
else:
u_form = UserUpdateForm(instance=request.user)
notes = UserCreatedNote.objects.filter(user=request.user)
context = {'u_form': u_form,'notes':notes}
return render(request,'profile.html',context)
My models
from django.db import models
from django.contrib.auth.models import User
from django.contrib.auth.models import (
BaseUserManager, AbstractBaseUser
)
# ///////////////User Manager/////////////////////
# Create your models here.
# overriding the create and superuser funciton
class MyAccountManager(BaseUserManager):
def create_user(self,email,username,password=None):
if not email:
raise ValueError("Users Must Have email Address")
if not username:
raise ValueError("Users Must Have username")
user = self.model(
email=self.normalize_email(email),
username=username,
)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self,email,username,password):
user = self.create_user(
email = self.normalize_email(email),
username=username,
password=password,
)
user.is_admin = True
user.is_staff = True
user.is_superuser = True
user.save(using=self._db)
return user
# ////////////////////////////////////////////////////////////
def get_profile_image_filepath(self,filename):
return f'profile_images/{self.pk}/{filename}' #pk= primary key
def get_default_profile_image():
return "img/default_profile/default.png"
class KeepSafeUserModel(AbstractBaseUser):
first_name = models.CharField(verbose_name='first_name',max_length=30,default="")
last_name = models.CharField(verbose_name='last_name',max_length=30,default="")
email= models.TextField(verbose_name='email',max_length=60,unique=True,primary_key=True)
username = models.CharField(max_length=30,unique=True)
date_joined = models.DateTimeField(verbose_name="date joined",auto_now_add=True)
last_login = models.DateTimeField(verbose_name='last_login',auto_now=True)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_admin = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
profile_image = models.ImageField(max_length=225,upload_to=get_profile_image_filepath,null=True,blank=True,default=get_default_profile_image)
#password field is buil-in
objects = MyAccountManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
def __str__(self):
return self.username
def has_perm(self,perm,obj=None):
return self.is_admin
def has_module_perms(self,app_Label):
return True
def get_profile_image_filename(self):
return str(self.profile_image)[str(self.profile_image).index('profile_images/{self.pk}/')]
forms.py
class UserUpdateForm(forms.ModelForm):
profile_image = forms.ImageField(required=False,error_messages ={'invalid':("Image files only")},widget=forms.FileInput)
class Meta:
model = KeepSafeUserModel
fields = ['username','first_name','last_name','profile_image']
labels ={
'username':'Username',
'first_name':'First Name',
'last_name':'Last Name',
'profile_image':'Profile Image'
}
def clean_username(self):
username = self.cleaned_data['username']
if not username.isdigit():
users = KeepSafeUserModel.objects.filter(username__iexact=username)
if users:
raise forms.ValidationError("Username has already taken by someone else")
else:
raise forms.ValidationError("Username can't contains only numbers")
return username
The problem is that if you update your KeepSafeUserModel, you will have a hit for KeepSafeUserModel.objects.filter(username__iexact=username): indeed, it will simply match with itself.
You can simply exclude the object with:
def clean_username(self):
username = self.cleaned_data['username']
if not username.isdigit():
users = KeepSafeUserModel.objects.exclude(pk=self.instance.pk).filter(
username__iexact=username
).exists()
if users:
raise forms.ValidationError"Username has already taken by someone else")
else:
raise forms.ValidationError("Username can't contains only numbers")
return username
I think you already pass the instance of user logged in to the form. So you need to make the clean_username(self) validation become like this.
def clean_username(self):
username = self.cleaned_data['username']
if not username.isdigit():
users = KeepSafeUserModel.objects.filter(username__iexact=username)
if users:
if users.username != self.instance.username:
raise forms.ValidationError("Username has already taken by someone else")
else:
raise forms.ValidationError("Username can't contains only numbers")
return username
It will validate the username given and stored is not same
I am a beginner in Django and I am very need your help.
Part of code:
models.py
from django.contrib.auth.models import User
class Author(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
department = models.CharField(max_length=200)
def __str__(self):
return self.user.username
class hardware(models.Model):
hostname = socket.gethostname()
login_username = getpass.getuser()
user = User.username
hardware_name = models.CharField(max_length=20)
order_no = models.CharField(max_length=10)
price = models.DecimalField(max_digits=5,decimal_places=2)
confirm = models.BooleanField(default=False)
login_user = models.ForeignKey(Author, on_delete=models.CASCADE)
computer_login_user = models.CharField(max_length=10,default=login_username)
computer = models.CharField(max_length=30,default=hostname)
def __str__(self):
return self.order_no
views.py
def get_author(user):
qs = Author.objects.filter(user=user)
if qs.exists():
return qs[0]
return None
def new_record(request):
form = OrderForm(request.POST or None, request.FILES or None)
if form.is_valid():
author = get_author(request.user)
form.instance.login_user = author
form.save()
return redirect(all_records)
context = {
'form': form
}
return render(request, 'orders/form.html', context)
I will try to explain my problem briefly.
Computers are in public places (productions) and anyone can add new record. That why in the table is info about hostname, who is login on computer and login user.
So it works well when the user is logged in to the system, but there is a problem when a new record tries to add an unlogged user (guest). Is an error "'AnonymousUser' object is not iterable".
I know that request.user is empty now.
Ok, Now questions...
How to add "guest" user and add it if noone is login?? How to add a new record if the user is not logged in??
I am sorry for very long post and Thanks for all suggestions.
So, if I understand correctly, you can do this a few ways:
The easiest way is to simply set the login_user field nullable and blank or,
Create a "guest user" and "guest author" in your Django database that is not active (is_active is set to False so they can't log in) and all anonymous users are assigned that User and Author instance the database.
As mentioned, the simplest method would be just to set the login_user field as nullable and blank, like such:
login_user = models.ForeignKey(Author, on_delete=models.CASCADE, blank=True, null=True)
And if your get_author() returns None, then simply leave that column blank, though this might affect other parts of your application if an Author or User object is required elsewhere.
Another way to do it in your get_author() method using a "guest" user:
def get_author(user):
if user.is_anonymous:
guest_user = User.objects.get(username="guest") # or whatever ID or name you use for the placeholder user that no one will be assigned
guest_author = Author.objects.get_or_create(user=guest_user)
return guest_author
else:
return Author.objects.get(user=user)
In this option, you'd need to set your department field in Author to blank and null or set a default like:
class Author(models.Model):
user = ...
department = ...(..., default="none")
or
class Author(models.Model):
user = ...
department = ...(..., blank=True, null=True)
Yet another option might be to create a new "guest" user for each action:
import random
import string
def randomString(stringLength):
letters = string.ascii_letters
return ''.join(random.choice(letters) for i in range(stringLength))
def get_author(user):
if user.is_anonymous:
random_username = f"{randomString(10)}_guest"
random_email = f"{randomString(5)}_guest#example.com"
guest_user = User.objects.create(username=random_username, is_active=False, email=random_email...)
guest_author = Author.objects.create(user=guest_user, department="none")
return guest_author
else:
return Author.objects.get(user=user)
Thank you for your help and time. I chose the second solution after little change.
def get_author(user):
if user.is_anonymous:
guest_user = User.objects.get(username="guest") # or whatever ID or name you use for the placeholder user that no one will be assigned
qs = Author.objects.filter(user=guest_user)
if qs.exists():
return qs[0]
return None
else:
qs = Author.objects.filter(user=user)
if qs.exists():
return qs[0]
return None
Now is little better and working well.
When I use exactly your method was little mistake: "ValueError: Cannot assign "(<Author: guest>, False)": "hardware.login_user" must be a "Author" instance."
So, anyway thank you again.
I'm making a stock portfolio app as a personal project. I have a form StockSymbolForm used for buying stocks. It has the fields: username, stock_symbol, and stock_qty.
I've set username to be the current user that's currently using the app - so they only need to fill stock_symbol and stock_qty.
After a valid form is submitted, I go to my admin page to check, but I don't see my new stock_symbol and stock_qty added to my model.
Here's my code:
views.py:
class PortfolioStockListView(ListView):
model = StockPortfolio
template_name = 'stocks.html'
def post(self, request):
current_user = StockPortfolioUser.objects.filter(username=request.user).first()
if request.method == 'POST':
symbol_form = StockSymbolForm(request.POST, initial={'username': current_user})
if symbol_form.is_valid():
symbol_form = StockSymbolForm(request.POST, instance=current_user)
model_instance = symbol_form.save(commit=True)
model_instance.timestamp = timezone.now()
model_instance.save()
return redirect('/')
else:
return render(request, 'stocks.html', {'symbol_form': symbol_form})
else:
symbol_form = StockSymbolForm()
return render(request, 'stocks.html', {'symbol_form': symbol_form})
models.py:
class StockPortfolioUser(models.Model):
username = models.OneToOneField(User, on_delete=models.CASCADE)
usercash = models.PositiveIntegerField(default=100000)
class StockPortfolio(models.Model):
username = models.ForeignKey(StockPortfolioUser, on_delete=models.CASCADE)
stock_symbol = models.CharField(max_length=5)
stock_qty = models.PositiveIntegerField(default=0)
forms.py:
class StockSymbolForm(ModelForm):
class Meta:
model = StockPortfolio
fields = ('stock_symbol' , 'stock_qty')
labels = {'stock_symbol': 'Stock Symbol', 'stock_qty': 'Quantity'}
How do I save the model instance properly? and why is it not saving at the moment?
In your views.py file change this
model_instance = symbol_form.save(commit=False)
model_instance.username = request.user.id
model_instance.timestamp = timezone.now()
model_instance.save()
In StockSymbolForm change this
fields = ('username', 'stock_symbol' , 'stock_qty')
Well, you don't ever seem to be setting the username. You set a timestamp, which doesn't exist as a field, but not the actual username field.
model_instance = symbol_form.save(commit=True)
model_instance.userame = request.user
model_instance.save()
As an aside, that field should be called user, as it points to the whole User object not just the username.