Django - handling a large number of forms - python

I'm starting to work on a website, which obviously will have a ton of buttons, and I still only have 2 buttons to handle, and one of my views already has this piece of code to handle just those two form submissions
if request.method == "POST":
if "see" in request.POST:
seetagform = SeeTagForm(request.POST)
createform = CreateForm()
if seetagform.is_valid():
cd = seetagform.cleaned_data
tagstring = "_".join(cd["name"].split(' '))
return HttpResponseRedirect(reverse("base:see",args=(tagstring,)))
elif "create" in request.POST:
createform = CreateForm(request.POST)
seetagform = SeeTagForm()
if createform.is_valid():
cd = createform.cleaned_data
p = Event.objects.create(start=cd["datetime"])
tags = cd["tags"]
tags = tags.split(' ')
for tag in tags:
t = Tag.objects.get(name=tag)
t.events.add(p)
return HttpResponseRedirect(reverse("base:see",args=(tagstring,)))
else:
createform = CreateForm()
seetagform = SeeTagForm()
else:
createform = CreateForm()
seetagform = SeeTagForm()
Well, as far as I can sense, these are many if's and else's for only 2 buttons (but everything here is needed), so I wonder the confusion it might be when I have like 12 buttons across my page. This doesn't look too pythonic!
Is there a simpler/more clever way to handle many form submissions?
Thanks in advance

I am doing it also that way, just adding prefix to the buttons name to be more clear
#login_required
def profile_view(request):
message = None
user = MyUser.objects.get(pk=request.user.pk)
addresses = user.profile_address.all()
AddressFormSet = modelformset_factory(Address, fields=['city','zip_code','address','phone','default_address',
'first_name','last_name'])
address_formset = AddressFormSet(queryset=addresses)
profile_form = ProfileForm(instance=user)
pass_form = PasswordChangeForm()
if request.method == "POST":
if 'btn_profile' in request.POST:
profile_form = ProfileForm(request.POST, instance=user)
if profile_form.is_valid():
profile_form.save()
messages.add_message(request, messages.INFO, 'Successfully changed your profile')
return HttpResponseRedirect(reverse('profile'))
if 'btn_pass' in request.POST:
pass_form = PasswordChangeForm(request.POST)
if pass_form.is_valid():
user.set_password(pass_form.cleaned_data['password1'])
user.save()
messages.add_message(request, messages.INFO, 'Successfully changed your password')
return HttpResponseRedirect(reverse('profile'))
if 'btn_address' in request.POST:
address_formset = AddressFormSet(request.POST)
if address_formset.is_valid():
for address_form in address_formset:
if address_form.is_valid() and address_form.has_changed():
address = address_form.save(commit=False)
address.user_profile = user
address.save()
return HttpResponseRedirect(reverse('profile'))
orders = Order.objects.filter(user = user).order_by('-created')
context = {
'address_formset': address_formset,
'pass_form': pass_form,
'profile_form':profile_form,
'message':message,
'orders':orders,
}
return render(request,'custom_auth/profile.html', context)

Related

How to remove "this field is not required" in django?

I found posts with similar problem, but the solutions dont seem to work with me. Or maybe I am missing something.
I created a form in Django, but as a default it seems that every mandatory fields have this "this field is required" text above.
Ideally, I would like to have this only when someone tries to submit a form and a field is missing.
form.py
class ElderFlowerChampFormAdmin(ModelForm):
fieldsets=[
("Look",{'fields':[
('look_colour','look_clarity','look_effervescence')]}),
}
widgets = {
'user': forms.Select(attrs={'class':'form-control','required':'True'}),
'look_colour':forms.Select(attrs={'class':'form-control','required':'True'}),
}
view.py
def elderflowerchamp(request, product_id):
global ChampageRating
product = Product.objects.get(pk=product_id)
url = request.META.get('HTTP_REFERER')
submitted = False
try:
if request.method == "POST":
reviews = ChampageRating.objects.get(pk=product_id)
if request.user.is_superuser:
form = ElderFlowerChampFormAdmin(request.POST, instance=reviews)
if form.is_valid():
form.save()
return redirect('home')
else:
form = ElderFlowerChampForm(request.POST, instance=reviews)
if form.is_valid():
ChampageRating = form.save(commit=False)
ChampageRating.user = request.user
ChampageRating.save()
return redirect('home')
else:
#This part goes to the page, but doesnt submit
reviews = ChampageRating.objects.get(pk=product_id)
if request.user.is_superuser:
form = ElderFlowerChampFormAdmin
else:
form = ElderFlowerChampForm
if 'submitted' in request.GET:
submitted = True
except:
reviews = None
if request.user.is_superuser:
form = ElderFlowerChampFormAdmin(request.POST)
if form.is_valid():
data = ChampageRating()
data.rating = form.cleaned_data['rating']
data.look_colour = form.cleaned_data['look_colour']
data.ip = request.META.get('REMOTE_ADDR')
data.product_id = product_id
data.user_id = request.user.id
data.save()
messages.success(request, 'Thank you! Your review has been submitted.')
return redirect('home')
else:
form = ElderFlowerChampForm(request.POST)
if form.is_valid():
data = ChampageRating()
data.rating = form.cleaned_data['rating']
data.look_colour = form.cleaned_data['look_colour']
data.ip = request.META.get('REMOTE_ADDR')
data.product_id = product_id
data.user_id = request.user.id
data.save()
messages.success(request, 'Thank you! Your review has been submitted.')
return redirect('home')
return render(request,"main/ElderFlowerReview.html", {'form':form, 'submitted':submitted,'reviews':reviews, 'product':product})
models.py
LOOKCOLOUR=(
(1,'Straw'),
(2,'Yellow'),
(3,'Gold'),
(4,'Amber'),
)
class ChampageRating(models.Model):
user = models.ForeignKey(User,blank=True, on_delete=models.CASCADE)
product=models.ForeignKey(Product,related_name="champcomments", on_delete=models.CASCADE)
look_colour=models.IntegerField(choices=LOOKCOLOUR, default=0)
def __str__(self):
return '%s - %s - %s'%(self.user, self.product, self.date_added)
Any ideas
something wrong on case request.GET here:
if request.user.is_superuser:
form = ElderFlowerChampFormAdmin
else:
form = ElderFlowerChampForm
You send the FormClass into the template context, and not the form instance.
Also see eror on the except case: If i have a GET, i should not render BoundedForm, here should be form.bounded = false (form is not bounded with any data). But you are always made the BoundedForm, with the request.POST data after error here:
reviews = ChampageRating.objects.get(pk=product_id)
My opinion is - you should try to read about Django-GCBV, it is better way to avoid complex errors, like in your question.
https://docs.djangoproject.com/en/4.0/topics/class-based-views/

How do I save multiple forms in the same Django View from the same Model? Currently the last form overwrites in save

How do I save multiple forms in the same Django View from the same Model?
Currently the last form overwrites in save
views.py
def createrequest_1(request):
if request.method == 'POST':
form1 = SurveyNameForm(request.POST)
form2 = Question1Form(request.POST)
form3 = Question2Form(request.POST)
if form1.is_valid() and form2.is_valid() and form3.is_valid():
survey = form1.save(commit=False)
question1 = form2.save(commit=False)
question2 = form3.save(commit=False)
survey.survey_creation_date = datetime.date.today()
survey.customuser = request.user
survey.save()
question1.survey = survey
question1.save()
question2.survey = survey
question2.save()
return HttpResponseRedirect('createrequest_2')
else:
form = SurveyNameForm()
return render(request, 'requestapp/createrequest_1.html', {'SurveyNameForm': SurveyNameForm, 'Question1Form':Question1Form, 'Question2Form': Question2Form})
You must set different prefix for every form.
Put instances of forms for render in the template.
In this way:
def createrequest_1(request):
form1 = SurveyNameForm(request.POST or None, prefix='survey')
form2 = Question1Form(request.POST or None, prefix='question1')
form3 = Question2Form(request.POST or None, prefix='question2')
if request.method == 'POST':
if form1.is_valid() and form2.is_valid() and form3.is_valid():
survey = form1.save(commit=False)
question1 = form2.save(commit=False)
question2 = form3.save(commit=False)
survey.survey_creation_date = datetime.date.today()
survey.customuser = request.user
survey.save()
question1.survey = survey
question1.save()
question2.survey = survey
question2.save()
return HttpResponseRedirect('createrequest_2')
return render(request, 'requestapp/createrequest_1.html',
{'SurveyNameForm': form1, 'Question1Form': form2, 'Question2Form': form3})
This is explained in https://docs.djangoproject.com/en/3.0/ref/forms/api/#django.forms.Form.prefix

How to clear only a specific field from a form after submission?

I have a form with a few fields. Most of the time, people only need to change one field every time they submit, not all, so I would like to change it in such a way that upon submission, only the employee field is cleared, but the Work Area choice and station (if there are any available) remain selected.
How could I change the way the form is handled so it is not completely cleared upon submission? I know the form = WarehouseForm() is what clears it, but I'm not sure how I could just specify I only want the employee_number field cleared.
views.py
def enter_exit_area(request):
enter_without_exit = None
exit_without_enter = None
if request.method == 'POST':
form = WarehouseForm(request.POST)
if form.is_valid():
emp_num = form.cleaned_data['employee_number']
area = form.cleaned_data['work_area']
station = form.cleaned_data['station_number']
if 'enter_area' in request.POST:
# Submission logic
form = WarehouseForm()
elif 'leave_area' in request.POST:
# Submission logic ..
form = WarehouseForm()
else:
form = WarehouseForm()
return render(request, "operations/enter_exit_area.html", {
'form': form,
'enter_without_exit': enter_without_exit,
'exit_without_enter': exit_without_enter,
})
You can use the initial argument:
if 'enter_area' in request.POST:
# Submission logic
form = WarehouseForm(initial={'employee_number': '', 'work_area': area, 'station_number': station})
Note the employee_number field is blank.
You haven't included your submission logic, so your implementation might be slightly different. But the principle is the same.
form_obj = form.save(commit=False)
form_obj.employee_number = '' # if you want to clear employee_number field
form_obj.save()
Note:- 'employee_number' field should be null=True in models.py, so that you can clear the field
For Example:-
def enter_exit_area(request):
enter_without_exit = None
exit_without_enter = None
if request.method == 'POST':
form = WarehouseForm(request.POST)
if form.is_valid():
emp_num = form.cleaned_data['employee_number']
area = form.cleaned_data['work_area']
station = form.cleaned_data['station_number']
if 'enter_area' in request.POST:
# Submission logic
form_obj = form.save(commit=False)
form_obj.employee_number = '' # if you want to clear employee_number field
elif 'leave_area' in request.POST:
# Submission logic ..
form_obj = form.save(commit=False)
form_obj.employee_number = '' # if you want to clear employee_number field
form_obj.save()
else:
form = WarehouseForm()
return render(request, "operations/enter_exit_area.html", {
'form': form,
'enter_without_exit': enter_without_exit,
'exit_without_enter': exit_without_enter,
})
If it is input type textbox then you can also do it in javascript something like below :
eg : document.getElementById("formFieldId").value = '';

Trying to edit profile for two different user types in Django

I have 2 user types, teacher and student. I have built the view to be able to edit a student profile. But I also needed a different one for teacher. I didn't want 2 views, because that would be pointless. Now, for teacher it works as intended, but for some reason for student, the same form as for teacher is displayed... a student has different attributes so it has a different form I need to show.
#login_required
def profile_edit(request):
user = request.user
student = request.user.student
teacher = request.user.teacher
if user == teacher.user:
if request.method != 'POST':
form = TeacherEditForm(instance=teacher)
else:
form = TeacherEditForm(request.POST, instance=teacher)
if form.is_valid():
user.email = form.cleaned_data['email']
user.save()
form.save()
return redirect('index')
elif user == student.user:
if request.method != 'POST':
form = StudentEditForm(instance=student)
else:
form = StudentEditForm(request.POST, instance=student)
if form.is_valid():
user.email = form.cleaned_data['email']
user.save()
form.save()
return redirect('index')
context = {
"form": form,
}
return render(request, "registration/profile_edit.html", context)
I think there is something wrong with the way I pass data to student and teacher and the view can't differentiate between user types.
Something like this but remove
User.student = property(lambda p: Student.objects.get_or_create(user=p)[0])
User.teacher = property(lambda p: Teacher.objects.get_or_create(user=p)[0])
#login_required
def profile_edit(request):
user = request.user
try:
student = Student.objects.get(user=user)
s=True
except: teacher = Teacher.objects.get(user=user)
if not s:
if request.method != 'POST':
form = TeacherEditForm(instance=teacher)
else:
form = TeacherEditForm(request.POST, instance=teacher)
if form.is_valid():
user.email = form.cleaned_data['email']
user.save()
form.save()
return redirect('index')
elif s:
if request.method != 'POST':
form = StudentEditForm(instance=student)
else:
form = StudentEditForm(request.POST, instance=student)
if form.is_valid():
user.email = form.cleaned_data['email']
user.save()
form.save()
return redirect('index')
context = {
"form": form,
}
return render(request, "registration/profile_edit.html", context)

Why whenever I click on a link within my site, any logged in user gets logged out?

I have built a hackernews type clone with login system, upvotes etc.
I just have one problem at the moment. Whenever I click a link that redirects me to somewhere else on the site (i.e. localhost/ to localhost/science) the logged in user gets logged out.
Here are some of the key views associted with the problem I think:
def index(request, category_id=1):
stories = top_stories(top=30)
category = Category.objects.get(id = category_id)
if request.user.is_authenticated():
liked_stories = request.user.liked_stories.filter(id__in = [story.id for story in stories])
else:
liked_stories = []
return render(request, 'stories/index.html', {
'stories': stories,
'user': request.user,
'liked_stories': liked_stories,
'category': category,
})
#login_required(login_url = "/login/")
def story(request):
if request.method == 'POST':
form = StoryForm(request.POST)
if form.is_valid():
story = form.save(commit = False)
story.moderator = request.user
story.save()
return HttpResponseRedirect('/')
else:
form = StoryForm()
return render(request, 'stories/story.html', {'form': form})
#login_required
def vote(request):
story = get_object_or_404(Story, pk = request.POST.get('story'))
story.points += 1
story.save()
user = request.user
user.liked_stories.add(story)
user.save()
return HttpResponse()
Is there a 'next' parameter I can include somewhere that will keep each user logged in as they jump from link to link?
If you need any other parts of the code let me know.

Categories