In the Django app I am building I would like to have the user creation process go as follows: As user signs up, if valid is then redirected to create a LIST object, and if valid is then redirected to what will be a dashboard for the LIST object just created. My views.py are as follows:
def user_signup(request):
if request.method == 'POST':
form = forms.UserSignupForm(data=request.POST)
if form.is_valid():
user = form.save()
g = Group.objects.get(name='test_group')
g.user_set.add(user)
# log user in
username = form.cleaned_data['username']
password = form.cleaned_data['password1']
user = authenticate(username=username, password=password)
login(request, user)
messages.success(request, u'Welcome to Social FollowUp')
return redirect('user_create')
else:
form = forms.UserSignupForm()
return TemplateResponse(request, 'user_signup.html', {
'form': form,
})
#login_required
#permission_required('')
def user_create(request):
if request.method == 'POST':
list_form = forms.ListForm(request.POST)
if list_form.is_valid():
list_create = list_form.save()
messages.success(request, 'List {0} created'.format(list_create.list_id))
return redirect('user_dashboard')
else:
list_form = forms.ListForm()
return TemplateResponse(request, 'dashboard/create.html', {'list_form': list_form, })
def user_dashboard(request, list_id):
try:
list_id = models.List.objects.get(pk=list_id)
except models.List.DoesNotExist:
raise Http404
return TemplateResponse(request, 'dashboard/view.html', {'list_id': list_id})
My urls.py for these views is as follows:
url(r'user/signup/$', views.user_signup, name='user_signup'),
url(r'u/dashboard/(?P<list_id>\d+)/$', views.user_dashboard, name='user_dashboard'),
url(r'u/list/create/$', views.user_create, name='user_create'),
When I try to run through the process, the first two views work correctly. However when I redirect to the user_dashboard I get the following error:
Reverse for 'user_dashboard' with arguments '' and keyword arguments '{}' not found.
which sites this:
return redirect('user_dashboard')
I'm assuming this has something to do with me not passing in a list_id, however, even when I tried to pass in a hardcoded value it did not work (like this):
return redirect('user_dashboard', {'list_id': 2})
What am I doing wrong here?
Try:
return redirect(reverse('user_dashboard', args=(2,)))
Your code
return redirect('user_dashboard')
would not work because in your url pattern, you have
url(r'u/dashboard/(?P<list_id>\d+)/$', views.user_dashboard, name='user_dashboard'),
which requires list_id as a parameter.
Related
I have a edit-scholarship.html in which you can search for a scholarship by passing name and type and then select that scholarship and edit it in update-scholarship.html by passing scholarship id from the url.
Now after updating the scholarship, the url becomes
http://127.0.0.1:8000/admin/updatescholarship/50
50 is the scholarship id passed into the url
Now when I try to go to dashboard in my project, the url becomes
http://127.0.0.1:8000/admin/updatescholarship/dashboard
I dont't want the dashboard to get appended after the updatescholarship . The url should be
http://127.0.0.1:8000/admin/dashboard
Here's my edit-scholarship view
def admin_editscholarship(request):
if request.method == 'POST':
name = request.POST['sch_name']
type = request.POST['sch_type']
schdets = ScholarshipDetails.objects.filter(name = name,type = type)
if schdets is not None:
#if something exists in scholarship details, then print it
print('Scholarship found')
else:
schdets = None
return render(request,'admin-editscholarship.html',{'schdets':schdets})
Here's my update-scholarship view
def admin_updatescholarship(request,pk=None):
#can update the new data in the selectd scholarship
if pk:
sch = ScholarshipDetails.objects.get(pk = pk)
if request.method == 'POST':
form = EditScholarshipForm(request.POST,instance=sch)
if form.is_valid():
form.save()
print('\nform saved')
args = {'form' : form}
messages.success(request,'Successfully updated')
return render(request,'admin-editscholarship.html',args)
Here's my urls.py
path('admin/dashboard',views.admin_dash),
path('admin/addscholarship',views.admin_addscholarship),
path('admin/editscholarship',views.admin_editscholarship),
url(r'^admin/updatescholarship/(?P<pk>\d+)$',views.admin_updatescholarship,name =
'updatescholarship'),
path('admin/students',views.admin_students),
path('admin/requests',views.admin_requests)
you can redirect to other url using django redirect
from django.shortcuts import redirect
def fn_test(request):
task here
return redirect('path_to_redirect/')
Here I am trying to redirect to another page if the form is submitted successfully but this code is not working properly .The code saves the form data sends the email , everything is fine but the problem is while redirecting to another page if the form succeed. The error I get is:
Django Version: 2.0.6
Exception Type: ValueError
Exception Value:
dictionary update sequence element #0 has length 0; 2 is required
context_processor.py
def volunteer_page2(request):
volunteer = Volunteer.objects.all().order_by('date')
if request.method == 'POST':
form = VForm(request.POST or None)
if form.is_valid():
name = form.cleaned_data['name']
email = form.cleaned_data['email']
message = "{0} with email address {1} has sent you new message \n\n{2}".format(name, email, form.cleaned_data['message'])
form.save(commit = False)
try:
send_mail(name, message, 'appname <settings.EMAIL_HOST_USER>', ['myemail'])
except:
return HttpResponse('Invalid header found')
form.save()
messages.success(request, 'Success')
return redirect('volunteer_page')
else:
messages.error(request, "Sorry try again")
else:
form = VForm()
return {'volunteer': volunteer, 'form':form}
views.py
def about_page(request):
about = About.objects.all().order_by('date')
banner = Banner.objects.all()
testimonial = Testimonial.objects.order_by('-pk')[0:2]
nav = Nav.objects.all()
footer = Footer.objects.all()
latest_event2 = Events.objects.order_by('-pk')[0:2]
context = {
'about': about,
'testimonial': testimonial,
'footer':footer,
'banner': banner,
'nav': nav,
'latest_event2': latest_event2,
}
return render(request, 'myapp/about.html', context)
settings.py
'myapp.context_processor.volunteer_page2'
Django's context processor should always return dictionary. In your code you are returning HttpResponse also. This is problem.
I have a django application and on one page I have several forms for different models. I would like a 'success' message, which is easy to do by just adding to the context after form submission/validation. However, this leaves the possibility of re-submission of the form, which would just produce an error back to the page, but it still annoys me.
urls:
url_patterns = [
re_path(r'^manager/$', Manager.as_view(), name='manager'),
.......more.....
]
views.py:
class Manager(LoginRequiredMixin, View):
template_name = 'results/manager_templates/manager.html'
form1 = Form1
form2 = Form2
login_url = '/'
redirect_field_name = 'redirect_to'
def get(self, request, *args, **kwargs):
form1 = self.form1()
form2 = self.form2()
context = {
'form1': form1,
'form2': form,}
return render(request, self.template_name, context)
def post(self, request, *args, **kwargs):
submit_clicked = request.POST.get('submit')
form1 = self.form1()
form2 = self.form2()
context = {}
if submit_clicked == 'Form 1':
form1 = self.form1(request.POST)
if form1.is_valid():
form1.save()
context['message'] = 'Form 1 successful'
# reset the form
form1 = self.form1()
# return HttpResponseRedirect(
# reverse('results:manager',
# ))
else:
print('NOT VALID')
elif submit_clicked == 'Form 2':
... do same stuff as above ...
context['form1'] = form1
context['form2'] = form2
return render(request, self.template_name, context)
If I were to uncomment out the HttpResponseRedirect out, after the form was validated and added like so:
return HttpResponseRedirect(
reverse('results:manager',
))
Then it returns me to my page, and if i refresh the form isnt re-submitted. However I can't pass this an argument without it going through the url:
i.e if I were to write:
return HttpResponseRedirect(
reverse('results:manager',
kwargs={'success':'success'}
))
I get the error:
Reverse for 'manager' with keyword arguments '{'success': 'success'}' not found. 1 pattern(s) tried: ['manager/$']
and if I change urls.py to:
url_patterns = [
re_path(r'^manager/$', Manager.as_view(), name='manager'),
re_path(r'^manager/(?P<success>)$', Manager.as_view(), name='manager'),
]
I get the error:
Reverse for 'manager' with keyword arguments '{'success': 'success'}' not found. 2 pattern(s) tried: ['manager/(?P<success>)$', 'manager/$']
Is there anyway to pass HttpResponseRedirect variables that dont need to be added to url regex? Or is there any other way to 'reset' my request.POST so that forms dont get re-submitted, without using HttpResponseRedirect?
As you've found, you should redirect after a successful post to prevent duplicate requests.
When you changed the urls, you didn't add any characters to match in your success group.
re_path(r'^manager/(?P<success>\w+)$', Manager.as_view(), name='manager'),
Another option is to store the variable in the querystring, e.g. /manager/?success=success, then you can retrieve the value from request.GET after the redirect.
You could also store data in the session, or use the messages framework.
I currently have a model form that submits an entered domain to the db.
The problem I'm encountering is, I need to save the currently logged in user's ID (PK from the django.auth table) when a domain is submitted to satisfy a PK-FK relationship on the db end.
I currently have:
class SubmitDomain(ModelForm):
domainNm = forms.CharField(initial=u'Enter your domain', label='')
FKtoClient = User.<something>
class Meta:
model = Tld #Create form based off Model for Tld
fields = ['domainNm']
def clean_domainNm(self):
cleanedDomainName = self.cleaned_data.get('domainNm')
if Tld.objects.filter(domainNm=cleanedDomainName).exists():
errorMsg = u"Sorry that domain is not available."
raise ValidationError(errorMsg)
else:
return cleanedDomainName
and views.py
def AccountHome(request):
if request.user.is_anonymous():
return HttpResponseRedirect('/Login/')
form = SubmitDomain(request.POST or None) # A form bound to the POST data
if request.method == 'POST': # If the form has been submitted...
if form.is_valid(): # If form input passes initial validation...
domainNmCleaned = form.cleaned_data['domainNm'] ## clean data in dictionary
clientFKId = request.user.id
form.save() #save cleaned data to the db from dictionary`
try:
return HttpResponseRedirect('/Processscan/?domainNm=' + domainNmCleaned)
except:
raise ValidationError(('Invalid request'), code='300') ## [ TODO ]: add a custom error page here.
else:
form = SubmitDomain()
tld_set = request.user.tld_set.all()
return render(request, 'VA/account/accounthome.html', {
'tld_set':tld_set, 'form' : form
})
The problem is it gives me an error of: (1048, "Column 'FKtoClient_id' cannot be null"), very odd thing happening, for the column FKtoClient, its trying to submit: 7L instead of 7(the PK of this user's record). Any ideas?
If someone can please help, I would really appreciate it
Firstly, remove FKtoClient from your form. You need to set the user in your view where you can yes the request object. It's not possible to set an attribute on the form that automatically sets the current user.
When instantiating your form, you can pass a tld instance which already has the user set.
def AccountHome(request):
# I recommend using the login required decorator instead but this is ok
if request.user.is_anonymous():
return HttpResponseRedirect('/Login/')
# create a tld instance for the form, with the user set
tld = Tld(FKtoClient=request.user)
form = SubmitDomain(data=request.POST or None, instance=tld) # A form bound to the POST data, using the tld instance
if request.method == 'POST': # If the form has been submitted...
if form.is_valid(): # If form input passes initial validation...
domainNm = form.cleaned_data['domainNm']
form.save() #save cleaned data to the db from dictionary
# don't use a try..except block here, it shouldn't raise an exception
return HttpResponseRedirect('/Processscan/?domainNm=%s' % domainNm)
# No need to create another form here, because you are using the request.POST or None trick
# else:
# form = SubmitDomain()
tld_set = request.user.tld_set.all()
return render(request, 'VA/account/accounthome.html', {
'tld_set':tld_set, 'form' : form
})
This has an advantage over #dm03514's answer, which is that you can access the user within form methods as self.instance.user if required.
If you want to Require that a user be logged in to submit a form, you could do something like:
#login_required # if a user iS REQUIRED to be logged in to save a form
def your_view(request):
form = SubmitDomain(request.POST)
if form.is_valid():
new_submit = form.save(commit=False)
new_submit.your_user_field = request.user
new_submit.save()
You can get the logged in user from the request object:
current_user = request.user
First off, I know what the error means, I'm just confused on the configuration.
I'm getting an error of:
views.Registration didn't return an HttpResponse object
The issue is when I visit localhost/Register, I get the above error.
Q: If I want localhost/Register to show form from RegistrationForm() when it loads the register.html template within render() (at the bottom) when /Register is accessed. How do I do that? Do I need to create another view like /NewUser that I currently have specified? My thought was that render() was going to execute to show the template (with the form inside it) when viewing /Register
Code:
a view of:
def Registration(request):
RegForm = RegistrationForm(request.POST or None)
if request.method == 'POST':
if RegForm.is_valid():
clearUserName = RegForm.cleaned_data['userNm']
clearPass = RegForm.cleaned_data['userPass']
RegForm.save()
try:
return HttpResponseRedirect('/NewUser/?user=' + clearUserName)
except:
raise ValidationError('Invalid Request', code='300') ## [ TODO ]: add a custom error page here.
else:
RegForm = RegistrationForm()
return render(request, 'VA/reuse/register.html', {
'form': RegForm
})
You need to render something if the request is 'GET' instead of 'POST': ie.
def Registration(request):
RegForm = RegistrationForm(request.POST or None)
if request.method == 'POST':
if RegForm.is_valid():
clearUserName = RegForm.cleaned_data['userNm']
clearPass = RegForm.cleaned_data['userPass']
RegForm.save()
try:
return HttpResponseRedirect('/NewUser/?user=' + clearUserName)
except:
raise ValidationError('Invalid Request', code='300') ## [ TODO ]: add a custom error page here.
else:
RegForm = RegistrationForm()
return render(request, 'VA/reuse/register.html', {
'form': RegForm
})
else:
RegForm=RegistrationForm()
return render(request, 'template.html', {'formset': RegForm})
of course, you should change the context for your template, depending on whatever it is you need to render.
No, you should just move everything from the else onwards back one indentation level. Otherwise, nothing is returned if the request is not a POST.