Send to different emails based on ChoiceField - django

I want to have my contact form send to different emails based on the department the user chooses. Right now I'm just trying to print the department the user has picked but I'd like to set up some conditionals to send to different emails based on the department value.
This gives me KeyError at /contact/ 'DEALERSHIP ENQUIRIES'
forms.py
from django import forms
class ContactForm(forms.Form):
DEPARTMENT_CHOICES = (
('SALES ENQUIRIES', 'Sales Enquiuries'),
('DEALERSHIP ENQUIRIES', 'Dealership Enquiuries'),
('JOB ENQUIRIES', 'Job Enquiuries'),
('ALL OTHER QUESTIONS', 'All Other Questions'),
)
name = forms.CharField(max_length=255)
sender_email = forms.CharField(max_length=255)
phone = forms.CharField(max_length=255)
subject = forms.CharField(max_length=255)
department = forms.ChoiceField(choices = DEPARTMENT_CHOICES, widget=forms.Select(), required=True)
message = forms.CharField(required=True, widget=forms.Textarea(attrs={'rows': 8}))
views.py
def contact_view(request):
form = ContactForm
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
subject = f'Message from {form.cleaned_data["name"]}'
message = form.cleaned_data["message"]
sender = form.cleaned_data["sender_email"]
phone = form.cleaned_data["phone"]
department = form.cleaned_data["department"]
print(form.cleaned_data[department])
context = {
"form": form,
}
return render(request=request, template_name='main/contact.html', context=context)

Related

Problem with logic building for registering a model in django

I am in the middle of a project. I have extended the custom django user and modified it.
this is my user model:-
class User(AbstractUser):
name = models.CharField(max_length=200, null=True, blank=True)
usertype = models.CharField(choices = [('d','doctor'), ('p','patient')], max_length=1)
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = []
def __str__(self):
return self.name
Also I have declared two seperate models named Patient and Doctors. My objective is to register the users in their respective models(Doctors or Patients) by checking the usertype.
Here are those models:-
class Patient(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='patient')
dob = models.DateField(null=True, blank=True)
contact = models.CharField(null=True, blank=True, max_length=100)
def __str__(self):
return self.user.name
class Doctor(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='doctor')
deg = models.TextField(null=True, blank=True)
def __str__(self):
return self.user.name
Now at the front end I want to apply the logic as every time a user is registered the user selects the usertype and based on that selection the Doctor or the Patient module is updated.
I have tried creating separate forms for that too.
Here are my forms :-
class MyUserCreation(UserCreationForm):
class Meta:
model = User
fields = ['name','username','usertype']
class DoctorCreation(ModelForm):
class Meta:
model = Doctor
fields = ['user','deg']
class PatientCreation(ModelForm):
class Meta:
model = Patient
fields = ['dob', 'contact','user']
The view handling this URL is :-
def registerUser(request):
page = 'general'
form = MyUserCreation()
if request.method == 'POST':
form = MyUserCreation(request.POST)
if form.is_valid:
user = form.save(commit=False)
user.save()
login(request, user)
return redirect('home')
else:
messages.error(request, 'Error occured')
if user.usertype == 'p':
page = 'patient'
form = PatientCreation()
form = PatientCreation(request.POST)
if form.is_valid:
form.save()
elif user.usertype== 'd':
page = 'doctor'
form = DoctorCreation()
form = DoctorCreation(request.POST)
if form.is_valid:
form.save()
context = {'form':form, 'page':page}
return render(request, 'rec/register_user.html', context )
The front end for this project is handled with very basic HTML.
Also, if possible I want the front end such that every time a user is registered and the usertype is selected(which is a dropdown menu) some more fields show up depending on the usertype selection by the user. If selected Doctor the additional fields respective to the Doctor module show up, and same for the patient module.
To keep it simple on the front end this solution works like:
Loads Page with User Form
Submit User Form
Uses value to Load Next form
Submit Next Form + Redirect
Notes:
Uses the Values POSTed to determine what form is being submitted
Uses Initial to set User for the 2nd Form
This current flow could be broken up into 3 view with their own distinct URLs
Django View
def registerUser(request):
form = None
if request.method == 'POST':
valid = False
if 'usertype' in request.POST:
# 1st form submit
form = MyUserCreation(request.POST)
if form.is_valid:
valid = True
user = form.save(commit=False)
user.save()
login(request, user)
# Get 2nd form for load
if user.usertype == 'p':
page = 'patient'
form = PatientCreation(initial={'user':user})
elif user.usertype== 'd':
page = 'doctor'
form = DoctorCreation(initial={'user':user})
else:
# 2nd form submit
if 'dob' in request.POST:
form = PatientCreation(request.POST)
if form.is_valid:
form.save()
valid = True
elif 'deg' in request.POST:
form = DoctorCreation(request.POST)
if form.is_valid:
form.save()
valid = True
if valid:
# form sequence done
return redirect('home')
if not valid:
# a form failed somewhere
print(form.errors)
messages.error(request, 'Error occured')
if form == None:
page = 'general'
form = MyUserCreation()
context = {'form':form, 'page':page}
return render(request, 'rec/register_user.html', context )
Basic Django HTML Form
<form action="" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit">
</form>
Now you could make this a single page by making the Template more complex, with JQuery Hiding/Showing extra fields based on dropdown Value on Change, but I assumed this would be the route you wanted.
Edit
To make the field disabled you'd just edit the forms.py
Note: the form-control is just showing that you can also add classes + extra attributes if you need to
class PatientForm(forms.ModelForm):
class Meta:
model = RunRequest
fields = (
'user',
'dob',
'contact',
)
def __init__(self, *args, **kwargs):
super(PatientForm, self).__init__(*args, **kwargs)
self.fields['user'].widget.attrs={'class': 'form-control', 'disabled':True}

Can't get Django forms to save to User and Profile model

I am trying to extend the Django User model by creating a user Profile model. When users register for the site, I want them to be able to select what class period they are in. To do this, I've tried to create a form that alters the User model, and a form that alters the Profile model. The problem is that when I try to put both forms into 'users/register.html' I am getting an error that says 'Anonymous User has to data _meta'. Below is my original code that only has the form for altering the User model in 'users/register.html'. How can I configure the registration so that users are able to save to the User and Profile model when they are first signing up for the site?
models.py
class Profile(models.Model):
'''
periods = [
('-','-'),
('1','1'),
('2','2'),
('3','3'),
('4','4'),
('6','6'),
('7','7'),
]
'''
user = models.OneToOneField(User,on_delete=models.CASCADE)
period = models.IntegerField(default=1)
first_name = models.CharField(max_length=100,default='Home')
last_name = models.CharField(max_length=100,default='Simpson')
def __str__(self):
return f'{self.user.username}'
forms.py
class UserRegisterForm(UserCreationForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['username','email','password1','password2']
class UserProfileForm(forms.ModelForm):
periods = [
(1,1),
(2,2),
(3,3),
(4,4),
(6,6),
(7,7),
]
period = forms.ChoiceField(choices=periods)
first_name = forms.CharField(max_length=100)
last_name = forms.CharField(max_length=100)
class Meta:
model = Profile
fields = ['first_name','last_name','period']
signals.py
#receiver(post_save,sender=User)
def create_profile(sender,instance,created,**kwargs):
if created:
Profile.objects.create(user=instance)
#receiver(post_save,sender=User)
def save_profile(sender,instance,**kwargs):
instance.profile.save()
views.py
def login(request):
context = {
'title':'Login',
}
return render(request,'users/login.html',context)
def register(request):
if request.method == "POST":
form = UserRegisterForm(request.POST)
if form.is_valid():
email = form.cleaned_data.get('email')
email_domain = re.search("#[\w.]+", email)
if email_domain.group() == EMAIL_DOMAIN:
form.save()
username = form.cleaned_data.get('username')
messages.success(request,f'Account created for {username}! You are now able to sign in.')
return redirect('users-login')
else:
messages.error(request,f'Sorry. You are not authorized to register.')
else:
form = UserRegisterForm()
context = {
'title':'Register',
'form':form
}
return render(request,'users/register.html',context)
This is happening because you are putting both the forms in the register page . When you have not created any user so how you can create a profile and how would you be able to add or retrieve data from it?
Now the solution for that is ,
1 . You create a page for registering the user say "users/register.html" , when they successfully register there, create a signal for creating the Profile for him , then successfully log the user in . Then redirect the just registered user to the profile change page.
Take both the forms in the user register page but do not validate the profile_change form .Create the user in the view and then reference it to the profile_change_form .
A simple code bit for that .
def registerUser(request) :
if request.method == "POST" :
user_form = UserRegisterForm(request.POST)
if user_form.is_valid():
username = request.POST.get("username")
# fields you require
user = User(username = username , password = password)
user.save()
profile_field_objects = request.POST.get("profile_field_data")
profile = Profile(user = user , profile_field_objects = profile_field_objects)
profile.save()
# rest you can code

Django ModelForm Custom Date Field

I am trying to create a reservation form that creates an object for model Reservation when the form is posted. I am using a custom datepicker widget to pick the ate, but I am also using ModelForms.
The issue is that, if I do not have 'date' listed in the meta fields list in the forms.py, then the form doesn't look for the date field form input on post. But if I include 'date' inside the meta fields of the forms.py Modelform, then it errors and says "date field can not be left blank" even though it is not blank...
forms.py
class ReservationForm(forms.ModelForm):
date = forms.DateField(
widget=DatePickerInput(format='%m/%d/%Y')
)
def clean_date(self):
data = self.cleaned_data['date']
# Check if a date is not in the past.
if data < datetime.date.today():
raise ValidationError(_('Invalid date - reservation in past'), code='invalid')
messages.danger(request, "Reservation Created")
print('ERROR')
# Remember to always return the cleaned date.
return data
class Meta:
model = Reservation
fields = ('reservation_time', 'people', 'name', 'email', 'phone') # REMOVED 'date'
views.py
def reservationFormView(request):
#reservation = create(Reservation)
# If this is a POST request then process the Form data
if request.method == 'POST':
# Create a form instance and populate it with data from the request (binding):
form = ReservationForm(request.POST)
# Check if the form is valid:
if form.is_valid():
# process the data in form.cleaned_data as required
reservation = form.save(commit=False)
reservation.ReservationEmail = form.cleaned_data['email']
reservation.ReservationName = form.cleaned_data['name']
reservation.ReservationPeople = form.cleaned_data['people']
reservation.ReservationTime = form.cleaned_data['reservation_time']
reservation.date = form.cleaned_data['date']
print( reservation.date)
#reservation.created_time = timezone.now()
reservation.save()
# redirect to a new URL:
return HttpResponseRedirect('/reservation-confirmation/')
# If this is a GET (or any other method) create the default form.
else:
form = ReservationForm()
return render(request, 'home/reservation_form.html', {'form': form, })
models.py
class Reservation(BaseModel):
class Meta:
verbose_name_plural = "Reservations"
TIME_CHOICES = (
...
)
SEATING_CHOICES = (
...
)
date = models.DateField(null=True)
name = models.CharField(max_length=35, null=True)
phone = PhoneNumberField(null=True) #USE THIS https://github.com/stefanfoulis/django-phonenumber-field
email = models.EmailField(null=True)
people = models.PositiveSmallIntegerField(choices=SEATING_CHOICES, default=None, db_index=True)
reservation_time = models.PositiveSmallIntegerField(choices=TIME_CHOICES, default=None, db_index=True)
def __str__(self):
return '(%s) %s %s' % (self.date, self.name, self.phone )
Your clean_date method does not return a value in case the if condition is False. You should return the cleaned data in case it is correct, like:
def clean_date(self):
data = self.cleaned_data['date']
# Check if a date is not in the past.
if data < datetime.date.today():
raise ValidationError(_('Invalid date - reservation in past'), code='invalid')
messages.danger(request, "Reservation Created")
# not indented under the if
return data
Otherwise, this function will return None in case the data is valid, and raise a ValidationError in case the data is invalid.

django issues between forms and models

i am a beginner with Django. I want to ask how can i access a variable in forms.py to print out for the user. I know that models.py create the database for the user. The variable that i want to print it is a checkbox multiple choice field. I need to print the value of the multiplechoice in a table.The image is here
This is the Form.py:
class BacktestForm(forms.ModelForm):
period_start = forms.DateField(initial=datetime.datetime.today().date() - datetime.timedelta(days=365+16), widget=forms.widgets.DateInput(format="%Y/%m/%d"), input_formats=["%Y/%m/%d"])
period_end = forms.DateField(initial=datetime.datetime.today().date() - datetime.timedelta(days=16), widget=forms.widgets.DateInput(format="%Y/%m/%d"), input_formats=["%Y/%m/%d"])
market = forms.MultipleChoiceField(required=False,widget=CheckboxSelectMultiple, choices=MARKET_CHOICES)
sector = forms.MultipleChoiceField(required=False,widget=CheckboxSelectMultiple, choices= MEDIA_CHOICES)
class Meta:
model = Parameters
Models.py:
class Parameters(models.Model):
user = models.ForeignKey(User)
title = models.CharField('title', max_length=100, default='', blank=True, help_text='Use an indicative name, related to the chosen parameters')
type = models.CharField('forecast type', choices=FORECAST_TYPES, max_length=20, default="backtest")
#input characteristics
price_1_min = models.FloatField('1. Price, min', default=0.1, validators=[MinValueValidator(0.1), MaxValueValidator(20000)])
price_1_max = models.FloatField('1. Price, max', default=20000, validators=[MinValueValidator(0.1), MaxValueValidator(20000)])
This is my view.py for the button save:
def backtest(request, pk=None):
if pk is not None:
param = get_object_or_404(Parameters, pk=pk, user=request.user)
form = BacktestForm(request.POST or None, instance=param)
else:
form = BacktestForm(request.POST or None)
if request.method == 'POST':
if form.is_valid():
if 'save' in request.POST:
obj = form.save(commit=False)
obj.user = request.user
obj.type = "backtest"
obj.save()
messages.info(request, 'Saved!')
return redirect(obj.get_backtest_url())
Please post the full forms class. I don't see how your model and form is connected. I think you might need a modelform instead of a form if you want to access the model.
So the way to connect them would be like this
forms.py
from .models import Parameter
class ParameterForm(forms.ModelForm):
market = forms.MultipleChoiceField(required=False,widget=CheckboxSelectMultiple, choices=MARKET_CHOICES)
sector = forms.MultipleChoiceField(required=False,widget=CheckboxSelectMultiple, choices= MEDIA_CHOICES)
class Meta:
model = Parameters

Error when invoking creation of another form

models.py:
from django.db import models
from django.contrib.auth.models import User as BaseUser
CHOICE_GENDER = ((1, 'Male'), (2, 'Female'))
class Location(models.Model):
city = models.CharField(max_length=75)
country = models.CharField(max_length=25)
def __unicode__(self):
return ', '.join([self.city, self.state])
class Users(BaseUser):
user = models.OneToOneField(BaseUser, on_delete=models.CASCADE)
gender = models.IntegerField(choices=CHOICE_GENDER)
birth = models.DateField()
location = models.ForeignKey(Location)
class Meta:
ordering = ('user',)
forms.py:
from django.contrib.auth.forms import UserCreationForm
from django import forms
from .models import Users, Location, CHOICE_GENDER
class LocationForm(forms.ModelForm):
city = forms.CharField(max_length=75)
country = forms.CharField(max_length=25)
class Meta:
model = Location
fields = ('city', 'country',)
class RegistrationForm(UserCreationForm):
email = forms.CharField(max_length=75)
first_name = forms.CharField(max_length=30)
last_name = forms.CharField(max_length=30)
gender = forms.ChoiceField(choices=CHOICE_GENDER)
birth = forms.DateField()
location = LocationForm()
class Meta:
model = Users
fields = ('username', 'email', 'first_name', 'last_name', 'gender', 'birth')
def save(self, commit=True):
user = super(RegistrationForm, self).save(commit=False)
user.email = self.cleaned_data['email']
user.first_name = self.cleaned_data['first_name']
user.last_name = self.cleaned_data['last_name']
user.gender = self.cleaned_data['gender']
user.birth = self.cleaned_data['birth']
if commit:
user.save()
return user
This code in forms.py doesn't work. It doesn't save LocationForm due to these errors:
country - This field is required.
city - This field is required.
I've certainly did something wrong here, but I don't know exactly what. I admit that I've jumbled the code in forms.py, especially in the save method for RegistrationForm because I don't know how to properly invoke the creation of another form and how to make a connection between two of them. I searched the Internet but I couldn't find precise info about that, so I tried to improvise but I've failed, unfortunately.
Could someone help me with this? Thanks in advance!
UPDATE: views.py (currently):
def signup(request):
if request.method == "POST":
reg_form = RegistrationForm(request.POST)
loc_form = LocationForm(request.POST)
if reg_form.is_valid() and loc_form.is_valid():
location = loc_form.save()
reg_form.cleaned_data['location_id'] = location.id
registration = reg_form.save()
else:
pass
else:
reg_form = RegistrationForm()
loc_form = LocationForm()
return render(request, 'signup.html', {'loc_form': loc_form, 'reg_form':reg_form})
I've also modified forms.py but I still got the error from above.
Instead of using LocationForm inside RegistrationForm you can handle them seprately in your views.py it will result in a cleaner code and easy to handle.
if request.method == "POST":
reg_form = RegistrationForm(request.POST)
loc_form = LocationForm(request.POST)
if reg_form.is_valid() and loc_form.is_valid():
# since in your case they are dependent on each other
# save location form and get location object
location = loc_form.save()
# now you can use it in your reg_form
reg_form.cleaned_data['location_id'] = location.id
registration = reg_form.save()
else:
# no need to handle this case only for explanation
# use the forms, with valid post data initialized
# at the start of current if block
pass
else:
# create new forms for location and registration
reg_form = RegistrationForm()
loc_form = LocationForm()
return render(request, 'signup.html', {'loc_form': loc_form, 'reg_form':reg_form})
You can read here more on how to handle more than one nested forms in django docs.