querying data from foreign key (specifically, UserProfile) - django

If I have a model with a couple of fields that inherit from a UserProfile model:
class LeaveRequest(models.Model):
employee = models.ForeignKey(UserProfile)
supervisor = models.ForeignKey(UserProfile, related_name='+', blank=False, null=False)
submit_date = models.DateField(("submit date"), default=datetime.date.today)
leave_type = models.CharField(max_length=64, choices=TYPE_CHOICES)
start_date = models.DateField(("start date"))
return_date = models.DateField(("return date"))
...
and I use this model to create a model form:
class LeaveRequestForm(ModelForm):
class Meta:
model = LeaveRequest
how can I query for the email url in the User Profile? In this view function, I'm trying to send a notification email on form submit, to the sender(employee) and supervisor:
def create_request(request):
if request.method == 'POST':
form = LeaveRequestForm(request.POST)
if form.is_valid():
name = form.cleaned_data['employee']
subject = form.cleaned_data['leave_type']
message = form.cleaned_data['notes']
sender = form.cleaned_data['employee']
remoterq = form.save(commit=False)
remoterq.save()
form.save_m2m()
recipients = [user.email for user in remoterq.employee, user.email for user in remoterq.supervisor]
from django.core.mail import send_mail
send_mail(subject, message, 'projects.xxx#google.com', recipients, fail_silently=False)
return HttpResponseRedirect('.')
my code for the "recipients" var is invalid but I don't know how to fix it.

Try
remoterq.employee.user.email
for the employee email and
remoterq.supervisor.user.email
for the supervisor email.

Related

model form is not saving in django it is telling user can not be nul

i crated a model name address and connected with user by foreign key so a user can have multiple address but it is not saving i want form to take that user id to save but i don't how to do that
here is my models.py
class Address(models.Model):
phoneNumberRegex = RegexValidator(regex = r"^\d{10,10}$")
pincodeRegex = RegexValidator(regex = r"^\d{6,6}$")
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='address')
reciever_name = models.CharField(max_length=200, blank=False)
phone_no = models.CharField(validators = [phoneNumberRegex], max_length = 10, blank=False)
alt_phone_no = models.CharField(validators = [phoneNumberRegex], max_length = 10, blank=True)
state = models.CharField(max_length=50, choices=state_choice, blank=False)
pincode = models.CharField(validators = [pincodeRegex], max_length = 6, blank=False)
eighteen = models.CharField(blank=False, choices=eighteen_choice, default='Yes', max_length=4 )
city = models.CharField(max_length=100, blank=False)
address = models.CharField(max_length=500, blank=False)
locality = models.CharField(max_length=300, blank=True)
joined_date = models.DateTimeField(default=timezone.now,editable=False)
update_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.user.username
my views.py
#login_required
def add_address(request, username):
if request.method == 'POST':
form = Addressform(request.POST)
if form.is_valid():
form.save()
return redirect('accounts:home')
else:
form = Addressform()
return render(request, 'add_address.html', {'form': form})
my form.py
class Addressform(forms.ModelForm):
class Meta:
model = Address
fields = '__all__'
exclude = ['user', 'joined_date', 'updated_at']
labels = {
'reciever_name':'Reciever Name',
'phone_no':'Phone No',
'alt_phone_no':'Alternate Phone No',
'state':'State/Union Territory',
'pincode':'Area Pincode',
'eighteen':'Is reciever is 18+',
'city':'City',
'address':'Address',
'locality':'Locality',
}
widgets = {
'eighteen': forms.RadioSelect()
}
what i want is in user field it take that user who his login automatically but i don't understand how i can achieve that
since you are excluding the user field from the form, it gets a null value on the post request. With a foreign key you cannot have a null field in the database. You have 2 options:
1) Add the request user
#login_required
def add_address(request, username):
if request.method == 'POST':
form = Addressform(request.POST)
if form.is_valid():
form = form.save(commit=False)
form.user = request.user
form.save(commit=True)
return redirect('accounts:home')
else:
form = Addressform()
return render(request, 'add_address.html', {'form': form})
This will add the primary key of the user who is submitting the form as the foreign key of the address and hence associate the user with the address.
2) Allow user to select the user to associate with the address (not suggested)
The alternative method is to allow the user to select the user you want to associate with the address but it is not suggested as any user can associate any user with a particular address.
class Addressform(forms.ModelForm):
class Meta:
model = Address
fields = '__all__'
exclude = ['joined_date', 'updated_at']
labels = {
'reciever_name':'Reciever Name',
'phone_no':'Phone No',
'alt_phone_no':'Alternate Phone No',
'state':'State/Union Territory',
'pincode':'Area Pincode',
'eighteen':'Is reciever is 18+',
'city':'City',
'address':'Address',
'locality':'Locality',
}
widgets = {
'eighteen': forms.RadioSelect()
}

How to create instance of model during user registration process? Django

I am writing a simple event app in django. I have register and login process.
I have two models. Model creator has one OneToOneField with attribute User.
Event model has attribute creator as ForeignKey which contain specific User.
What is my problem? When I create new user, I want to create new instance of Creator model at the same time and when I log in as that user and create new event, I want to set value of creator in Event as this user.
How can I do it? models.py and views.py below:
models.py
class Event(models.Model):
SPORT = (
('Football', 'Football'),
('Volleyball', 'Volleyball'),
('Basketball', 'Basketball'),
('Futsal', 'Futsal'),
('Tennis', 'Tennis'),
('Handball', 'Handball'),
('Ice Hockey', 'Ice Hockey'),
('Paintball', 'Paintball')
)
creator = models.ForeignKey(Creator, null=True, on_delete=models.SET_NULL)
sport = models.CharField(max_length=20, null=True, choices=SPORT)
event_name = models.CharField(max_length=30)
event_date = models.DateTimeField(default=date.today())
end_event_date = models.DateTimeField(default=date.today())
current_members = models.IntegerField(default=1)
total_members = models.IntegerField(default=0)
event_location = models.CharField(max_length=50)
cost = models.FloatField(default=0, max_length=5)
description = models.CharField(max_length=300, blank=True)
def __str__(self):
return self.event_name
class Creator(models.Model):
user = models.OneToOneField(User, null=True, on_delete=models.CASCADE)
views.py
#unauthenticated_user
def registerPage(request):
form = CreateUserForm()
if request.method == 'POST':
form = CreateUserForm(request.POST)
if form.is_valid():
form.save()
messages.success(request, 'Account created successfully!')
return redirect('login')
context = {'form': form}
return render(request, 'events/register.html', context)
To create a new Creator at signup:
views.py
...
from django.contrib.auth import User
from .models import Creator
...
...
if form.is_valid():
new_user = form.save()
Creator.objects.create(user=new_user)
messages.success(request, 'Account created successfully!')
To add the creator to Event, you would get() the currently logged in user (request.user) from the Creator model, then pass that to the creator field when creating a new Event

how to update a extended Django User model?

I have created the user authentication system which includes both the default User model and an extended User model. They are as below:
from django.db import models
from django.urls import reverse
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True)
Photo = models.ImageField(upload_to='documents/%Y/%m/%d/', null=True)
uploaded_at = models.DateTimeField(auto_now_add=True, null=True)
dob = models.DateField(max_length=20, null=True)
country = models.CharField(max_length=100, null=True)
State = models.CharField(max_length=100, null=True)
District = models.CharField(max_length=100, null=True)
phone = models.CharField(max_length=10, null=True)
def get_absolute_url(self):
return reverse('profile', kwargs={'id': self.id})
forms.py
class UserProfileForm(forms.ModelForm):
Photo = forms.ImageField( max_length=100)
dob = forms.DateField(widget=forms.TextInput(attrs={'type': 'date'}))
country = forms.CharField(max_length=100)
State = forms.CharField(max_length=100)
District = forms.CharField(max_length=100)
phone = forms.CharField(max_length=10)
class Meta:
model = UserProfile
fields = ('Photo', 'dob', 'country', 'State', 'District', 'phone')
With the help of the above model and form, I am able to create user, and enter values for those custom model fields and see the user profile. So far so good.
However, I am facing issues while I update those custom fields. I have used the Django's in-built modules to update the default User fields(email). But I am not able to find a way to update those custom fields('dob', 'country', 'State', 'District', 'phone'). Below is the method from views.
views.py
#login_required(login_url="/login/")
def editUserProfile(request):
if request.method == "POST":
form = UserProfileUpdateForm(request.POST, instance=request.user) # default User profile update
obj = UserProfile.objects.get(id=request.user.id)
form1 = UserProfileForm(request.POST or None, instance=obj) # custom fields update.
if form.is_valid() and form1.is_valid():
obj.Photo = form1.cleaned_data['Photo']
obj.dob = form1.cleaned_data['dob']
obj.country = form1.cleaned_data['country']
obj.State = form1.cleaned_data['State']
obj.District = form1.cleaned_data['District']
obj.phone = form1.cleaned_data['phone']
form.save()
form1.save()
messages.success(request, f'updated successfully')
return redirect('/profile1')
else:
messages.error(request, f'Please correct the error below.')
else:
form = UserProfileUpdateForm(instance=request.user)
form1 = UserProfileUpdateForm(instance=request.user)
return render(request, "authenticate\\editProfilePage.html", {'form': form, 'form1': form1})
I have an update button on my profile page, on clicking I could only see the "email" field with pre-populated data to update(I can update this default field successfully).
I have seen other stackoverflow posts, but they are not helping.
I am not able to figure out the mistakes.
Please help
Thank you,
I think the problem is in this line
obj = UserProfile.objects.get(id=request.user.id)
here left id is id from UserProfile model. so it will be something like this
obj = UserProfile.objects.get(user__id=request.user.id)

Signup page stuck on loading (Waiting for Localhost...) after extending AbstractUser

I created a custom user model called Agent by extending AbstractUser. Now for some reason, my signup page is stuck and I can't figure out why (it was working fine before I created the custom user). When I click the Sign Up button, the page is stuck on Waiting for localhost...
There are 2 additional models on top of Agent that are created during registration - AgentBasicInfo and AgentPremiumInfo. AgentBasicInfo is displayed on the sign up page, while AgentPremiumInfo is created in the background, and not actually displayed during registration.
When I check my admin page, I see that an Agent model has been created, but no AgentBasicInfo and AgentPremiumInfo instances have been created. This leads me to believe something is getting stuck at or after agent_basic_info = basic_info_form.save(commit=False), but I can't figure out what it is.
Here is my code:
views.py
def signup(request):
if request.user.is_authenticated:
return HttpResponseRedirect('../dashboard/')
if request.method == 'POST':
signup_form = SignupForm(request.POST)
basic_info_form = AgentBasicInfoForm(request.POST)
if signup_form.is_valid() and basic_info_form.is_valid():
agent = signup_form.save(commit=False)
agent.is_active = False
agent.save()
# Creates a basic info form with user input
agent_basic_info = basic_info_form.save(commit=False)
agent_basic_info.agent = agent
agent_basic_info = agent_basic_info.save()
# Creates a profile model with the agent's premium information, empty except for 'agent' field. No actual form displayed on sign up page.
agent_premium_info = AgentPremiumInfo.objects.create(agent=agent)
agent_premium_info.save()
current_site = get_current_site(request)
message = render_to_string('acc_active_email.html', {
'agent':agent,
'domain':current_site.domain,
'uid': urlsafe_base64_encode(force_bytes(agent.pk)),
'token': account_activation_token.make_token(agent),
})
mail_subject = 'Activate your blog account.'
to_email = signup_form.cleaned_data.get('email')
email = EmailMessage(mail_subject, message, to=[to_email])
email.send()
return HttpResponse('Please confirm your email address to complete the registration')
else:
signup_form = SignupForm()
basic_info_form = AgentBasicInfoForm()
return render(request, 'signup.html', {'signup_form': signup_form, 'basic_info_form': basic_info_form})
def activate(request, uidb64, token):
try:
uid = force_text(urlsafe_base64_decode(uidb64))
agent = Agent.objects.get(pk=uid)
except(TypeError, ValueError, OverflowError, Agent.DoesNotExist):
agent = None
if agent is not None and account_activation_token.check_token(agent, token):
agent.is_active = True
agent.save()
login(request, agent)
# return redirect('home')
return HttpResponse('Thank you for your email confirmation. Now you can login your account.')
else:
return HttpResponse('Activation link is invalid!')
models.py
class Agent(AbstractUser):
pass
class AgentBasicInfo(models.Model):
TITLE = (
('Salesperson', 'Salesperson'),
('Sales Representative', 'Sales Representative'),
('Broker', 'Broker'),
('Broker of Record', 'Broker of Record'),
)
agent = models.OneToOneField(Agent, on_delete=models.CASCADE)
agent_first_name = models.CharField(max_length=30)
agent_last_name = models.CharField(max_length=30)
agent_preferred_email = models.EmailField()
office_phone_number = models.CharField(max_length=10)
agent_brokerage = models.CharField(max_length=50)
agent_title = models.CharField(max_length=20, choices=TITLE)
class AgentPremiumInfo(models.Model):
agent = models.OneToOneField(Agent, on_delete=models.CASCADE)
agent_phone_number = models.CharField(max_length=10, blank=True, null=True)
agent_website = models.CharField(max_length=50, blank=True, null=True)
agent_biography = models.TextField(blank=True, null=True)
agent_address_street = models.CharField(max_length=50, blank=True, null=True)
agent_address_city = models.CharField(max_length=25, blank=True, null=True)
agent_address_province = models.CharField(max_length=2, choices=PROVINCE, blank=True, null=True) # Add province choices later
agent_address_postal_code = models.CharField(max_length=6, blank=True, null=True)
agent_picture = models.ImageField(height_field=200, width_field=100, blank=True, null=True)
forms.py
class SignupForm(UserCreationForm):
email = forms.EmailField(max_length=200, help_text='Required')
def clean_email(self):
data = self.cleaned_data['email']
if not data.endswith('#gmail.com'):
raise forms.ValidationError("You must use your #gmail.com Email")
return data
class Meta:
model = Agent
fields = ('username', 'email', 'password1', 'password2')
class AgentBasicInfoForm(forms.ModelForm):
class Meta:
model = AgentBasicInfo
fields = ['agent_first_name', 'agent_last_name', 'agent_preferred_email', 'office_phone_number', 'agent_brokerage', 'agent_title']
class AgentPremiumInfoForm(forms.ModelForm):
class Meta:
model = AgentPremiumInfo
fields = ['agent_phone_number', 'agent_website', 'agent_biography', 'agent_picture', 'agent_address_street', 'agent_address_city', 'agent_address_province', 'agent_address_postal_code']
It seems something was wrong in the database despite me doing a reset_db. I did another reset_db and it magically fixed the issue.

How to intercept and control saving a Django POST form?

When the user is required to fill his profile, he picks a city from the Google Places Autocomplete and posts the form, in the view I extract the city Id from the Google API based on the posted text (I use the same id as pk in my db) and try to extract a city from my db.
These are the models:
class City(models.Model):
#extracted from the Google API
city_id = models.CharField(primary_key=True, max_length=150)
name = models.CharField(max_length=128, blank=True)
country = models.CharField(max_length=128, blank=True)
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='profile', primary_key=True)
city = models.ForeignKey(City, blank=True, null=True)
prof_pic = models.ImageField(blank=True, upload_to='profile_pictures')
This is the view:
def createprofile(request):
if request.method =='POST':
user = User.objects.get(username=request.user.username)
user_form = UserForm(data=request.POST, instance=user)
profile_form = UserProfileForm(data=request.POST)
if user_form.is_valid() and profile_form.is_valid():
user = user_form.save()
user.save()
profile = profile_form.save(commit=False)
profile.user = user
#brings back the city search result as text
searched_city = request.POST['city']
#brings back city ID from the Google API
searched_city_id = population_script.get_city_json(searched_city.replace(" ", ""))['results'][0]['id']
#If it's a valid city
if searched_city_id != -1:
city = City.objects.get(city_id = searched_city_id)
profile.city = city#this is what I want to happen!
else:
return HttpResponse("There's no such city, please try a different query.")
if 'prof_pic' in request.FILES:#now save the profile pic
profile.prof_pic = request.FILES['prof_pic']
print("PROF PIC IS: " + profile.prof_pic.url)
else:
profile.prof_pic = 'images/anon.png'
profile.save()
if 'next' in request.GET:
return redirect(request.GET['next'])
else:
print (user_form.errors, profile_form.errors)
else:
user_form = UserForm()
profile_form = UserProfileForm()
return render(request,
'excurj/createprofile.html', {'user_form':user_form, 'profile_form':profile_form})
However, I keep receiving an error that what's been posted is just text while the city needs to be a City object. I can save the profile pic ok though.
Cannot assign "'Dubai - United Arab Emirates'": "UserProfile.city"
must be a "City" instance.
edit: these are the forms:
class UserForm(forms.ModelForm):
first_name = forms.CharField(
label = "First Name:",
max_length = 80,
required = True
)
last_name = forms.CharField(
label = "Last Name:",
max_length = 80,
required = True,
)
class Meta:
model = User
fields = ('first_name', 'last_name')
class UserProfileForm(forms.ModelForm):
city = forms.CharField(
label = "Your Current City:",
max_length = 200,
required = True,
)
class Meta:
model = UserProfile
fields = ('city','prof_pic', 'dob', 'sex', 'education', 'career', 'about_you',
'music_movies_books', )
Please provide a related_name to the city field in the UserProfile.
I worked around this by creating a new UserProfile field called city_search_text which saves the searched text thus it of course does not return any error. I then receive it in the POST request and comfortable pull the proper city in the view.
I handled a similar issue by overriding my forms' clean method. Something like the following will work:
def clean(self):
# fix city problem
if self.cleaned_data.get("city") is not None:
self.cleaned_data['city'] = City.objects.get(id=self.cleaned_data.get("city"))
return self.cleaned_data