Django checkout not accessible: Page not found (404) - python

I'm trying to develop an e-commerce site with Django. So I'm at this point where, users can add items to their cart, but when I try to proceed to checkout, for some reason, my checkout form is not displayed rather, it says:
Page not found (404)
I made sure that I have registered my models, and ran migrations.
What is the problem?
My views.py:
#login_required
def checkout(request):
address_form = UserAddressForm(request.POST or None)
if address_form.is_valid():
new_address = address_form.save(commit= False)
new_address.user = request.user
new_address.save()
else:
raise Http404
print(form.errors)
context = {"address_form": address_form}
template = "orders/checkout.html"
return render(request, template, context)
My checkout.html:
<form method="POST" action=''>
{% csrf_token %}
<fieldset class="form-group">
{{ address_form|crispy }}
</fieldset>
<div class="form-group">
<input type="submit" class="btn btn-outline-dark" value="Place Order"/>
</div>
</form>
My urls.py:
from orders import views as orders_views
path('checkout/', orders_views.checkout, name='checkout'),

You've implemented GET request handling incorrectly, for reference see this example from the docs. In your case form was always invalid because in case of GET request it was initialized with none. However you don't even have to validate empty form on GET request.
Your code updated:
#login_required
def checkout(request):
if request.method == 'POST':
address_form = UserAddressForm(request.POST)
if address_form.is_valid():
new_address = address_form.save(commit= False)
new_address.user = request.user
new_address.save()
return # TODO : return what?
else:
# otherwise (if GET request) we get here
address_form = UserAddressForm()
context = {"address_form": address_form}
return render(request, "orders/checkout.html", context)
And you need to specify what is supposed to happen when the form is valid: redirect for example.

Related

Avoiding page refresh when a form is used in Django

I have a very basic Django view:
def myview(request):
if request.method == 'POST':
if 'button1' in request.POST:
form1 = form = myForm(request.POST)
# check whether it's valid:
if form.is_valid():
profile = form.save()
profile.user = request.user
profile.save()
messages.success(request, f"Success")
return HttpResponseRedirect(request.path_info)
else:
form = myForm()
return render(request,
"main/mytemplate.html",
context={"form":form})
And its template:
<form method="post" novalidate>
{% csrf_token %}
{% include 'main/includes/bs4_form.html' with form=form %}
<button name="button1" type="submit" class="btn btn-primary">SUBMIT</button>
</form>
Everything works here, when this form is used, some data is saved on my DB. What i would like to change, though, is the page reload after the form is used.
When the Submit button is hit, the page will be refreshed. Since it makes the navigation way slower, i would like to have the view not refreshing the page each time the form is used.
Is it possible to accomplish this in Django? For example, instead of refreshing the page, i would like to only load part of it, or to have a 'Reload' icon while the view is doing its work.
I'm pretty new to Ajax, so i don't know how to get started on this.

Django - template build-in filter tags {% url %}

I am a new coder with Django. So, first apologize for it if this question is too easy.
class CommentForm(forms.Form):
comment = forms.CharField(widget=forms.Textarea)
def save_comments_into_database(topic, user_id, content):
data = Comment(topic=topic, commenter_id=user_id, content=content)
data.save()
this is the code for form
<form action = "{% url 'post:comment' the_topic=topic user_id=1 %}" method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">submit</button>
</form>
I am trying to use url tag to call a function is views.py.
topic is a variable I passed in when this page is created.
this is my code in urls.py
url(r'^(?P<topic_id>[0-9]+)/comment/$', views.comment, name="comment"),
then this is how I do in views.py
def comment(request, the_topic, user_id):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = CommentForm(request.POST)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
text = form.cleaned_data['comment']
args = {'form': form, 'text': text, 'topic': the_topic}
# save the data in database
save_comments_into_database(the_topic.id, user_id, text)
# redirect to a new URL:
return render(request, 'post/detail.html', args)
# if a GET (or any other method) we'll create a blank form
else:
form = CommentForm()
return render(request, 'post/detail.html', {'form': form, 'topic': the_topic})
I get the NoReserveMatchException:
I really don't get where it goes wrong.
Your comment URL only has one var, the topic_id, but you passed two vars, the_topic and user_id. You need to pass just the topic ID. Also, in views you would normally access the current user via request.user.
you should to change declare the urls, added second parameter and change name of the first
url(r'^(?P<the_topic>[0-9]+)/comment/(?P<user_id>[0-9]+)/$', views.comment, name="comment"),
# ^^^^^^^^^ ^^^^^^
It's better to serve the action redirection using Django built in HttpResponseRedirect in the views.py and combine it with reverse of your url Django docs ref, check bellow and change yourapp_path with your app path and name_space with url name like "blog".
main urls.py with "name_space"
like namepsace="blog"
url(r'^', include('yourapp_path.urls', namespace='name_space))
# ^^^^^^^^^^^^ ^^^^^^^^^^
app urls.py with name="name"
like name="comment"
url(r'^(?P<topic_id>[0-9]+)/comment/$', views.comment, name="name")
# ^^^^^^
reverse with name_space:name
will return the complete path of the url taking name_space:name lets say blog:comment
reverse('name_space:name')
reverse with kwargs or args
reverse('name_space:name', kwargs={'kw1': 'val1'})
reverse('name_space:name', args=['val1'])
HttpResponseRedirect()
302 redirect to a given url in that case we will pass the reverse url.
like: HttpResponseRedirect(reverse('blog:comment', kwargs={'topic_id': topic.id}))
HttpResponseRedirect(reverse('name_space:name', kwargs={'kw1': 'val1'}))
views.py
#import HttpResoneRedircet and reverse
from django.shortcuts import HttpResponseRedirect, reverse
def comment(request, the_topic, user_id):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = CommentForm(request.POST)
# check whether it's valid:
if form.is_valid():
# your is_valid()
return HttpResponseRedirect(reverse('name_space:name', kwargs={'the_topic': the_topic.id}))
template
<form action="{{ action }}" method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">submit</button>
</form>

Django rest framework - Delete model objects from HTML

So i'm developing an app using Django framework, and i need HTML forms to insert/delete and update data from the database. I was able to make the form to Update the data, but i can't seem to find any info on how to make a Create form and a delete button.
I tried this, with no success:
HTML
<form action="{% url 'conta_details_html' conta.id %}" data-method="delete">
<input type="submit" value="delete">
</form>
Views:
class ContaDetailsHTML(APIView):
renderer_classes = [TemplateHTMLRenderer]
template_name = 'conta_details.html'
def get(self, request, pk):
user = request.user
conta = get_object_or_404(Conta, pk=pk,user=user)
serializer = ContaDetailsSerializerHTML(conta)
return Response({'serializer': serializer, 'conta': conta})
def delete(self,request,pk):
"""Deletes a transaccao"""
user = request.user
if not user.is_authenticated:
return Response(status=status.HTTP_403_FORBIDDEN)
conta = get_object_or_404(Conta, pk=pk, user=user)
serializer = ContaDetailsSerializerHTML(conta,many=False)
if conta:
conta.delete()
return Response(status=status.HTTP_200_OK)
return Response(serializer.errors,status=status.HTTP_400_BAD_REQUEST)
Maybe im not getting the syntax correct on the html, but the update form was pretty easy, like this:
<form action="{% url 'conta_details_html' conta.id %}" method="POST">
{% csrf_token %}
{% render_form serializer %}
<input type="submit" value="Save">
</form>
any idea ?
Edit:
URL:
url(r'^api/html/contas/(?P<pk>[0-9]+)/$', views.ContaDetailsHTML.as_view(), name='conta_details_html'),
Oh even for delete is it's easy. You missed out on a few things here.
1. DELETE is a HTTP Verb, Your method field in the form can take one of this.
<form action="{% url 'conta_details_html' conta.id %}" data-method="delete" method="DELETE">
<input type="submit" value="delete">
</form>
In your delete view, you are trying to serialiaze but you don't need to.
def delete(self, request, pk):
"""Deletes a transaccao"""
user = request.user
if not user.is_authenticated:
return Response(status=status.HTTP_403_FORBIDDEN)
conta = get_object_or_404(Conta, pk=pk, user=user)
conta.delete()
return Response(status=status.HTTP_200_OK)

Django form in the base template. How to display validation error?

I use Django 1.8.14. I have Search form on every page of my website. I pass Search form to base template through context processor. Each time form sends data to /search/ view. And there is a problem. Django raises ValidationError on form, but it doesn't display anywhere. What is the correct way to display form errors in template, when form passes to base template through context processor and sends data to one view?
form.py:
class SearchForm(forms.Form):
search = forms.CharField(required = True,
max_length=255,
widget = forms.TextInput({'class':'form-control', 'type':'search','required':''})
)
def clean_search(self):
search = self.cleaned_data.get("search")
regex = myregex
if not re.match(regex, search):
print("ValidationError")
raise forms.ValidationError(u'Please enter a valid value')
return search
context processor:
from myproject.forms import SearchForm
def form_context(request):
context_dict = {}
context_dict['search_form'] = SearchForm()
return(context_dict)
my base template:
<form method="post" action="/search/">
{% csrf_token %}
{{ search_form.non_field_errors }}
{{ search_form.errors }}
{{ search_form.search }}
{{ search_form.search.errors }}
<button type="submit" class="btn btn-find">Search</button>
</form>
my seach view:
def search(request, template):
if request.method == 'POST':
search_form = SearchForm(request.POST)
if search_form.is_valid():
domen = search_form.cleaned_data['search']
try:
site = SitePage.objects.get(domen=domen)
path="/"+site.domen +"/"
return HttpResponseRedirect(path)
except:
site = None
else:
print search_form.errors
return render(request, template, context_dict)
If you Django is raising validation error how you want it to and now all you need is to display that validation error on your html templates then i suppose what you are looking for is Django Messages
See the official documentation for the same -> https://docs.djangoproject.com/en/1.8/ref/contrib/messages/
You need to pass the form once it is bound to the data (the POST request) and validated; right now your context only has a blank form which is why no errors are being displayed.
from django.shortcuts import redirect
def search(request, template):
search_form = SearchForm(request.POST or None, request.FILES or None)
if search_form.is_valid():
domen = search_form.cleaned_data['search']
results = SitePage.objects.filter(domen=domen)
if results.exists():
return redirect('/{}/'.format(results.domen))
return render(request, template, {'form': search_form})

Edit/Add objects using the same django form

I already used the answer to this question, but for some reason I'm not getting a good result.
I'm trying to use the same template for my edit form and my add form. Here's my urls.py:
url(r'^app/student/new/$', 'edit_student', {}, 'student_new'),
url(r'^app/student/edit/(?P<id>\d+)/$', 'edit_student', {}, 'student_edit'),
And my views.py:
def edit_student(request, id=None, template_name='student_edit_template.html'):
if id:
t = "Edit"
student = get_object_or_404(Student, pk=id)
if student.teacher != request.user:
raise HttpResponseForbidden()
else:
t = "Add"
student = Student(teacher=request.user)
if request.POST:
form = StudentForm(request.POST, instance=student)
if form.is_valid():
form.save()
# If the save was successful, redirect to another page
redirect_url = reverse(student_save_success)
return HttpResponseRedirect(redirect_url)
else:
form = StudentForm(instance=student)
return render_to_response(template_name, {
'form': form,
't': t,
}, context_instance=RequestContext(request))
And my forms.py:
class StudentForm(ModelForm):
class Meta:
model = Student
exclude = ('teacher',)
And finally my template student_edit_template.html:
<h1>{{ t }} Student</h1>
<form action="/app/student/edit/{{ student.id }}" method="post"> {% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
For some reason, this is throwing a 404:
Page not found (404)
Request Method: POST
Request URL: http://192.168.1.3:5678/app/student/edit/
I'm probably missing something easy here, but at this point I need another set of eyes on it at the very least.
Thanks in advance!
You're getting the 404 because /student/edit/ requires an id at the tail end otherwise there's no route, and when you're coming from /student/new/ you don't have an id yet. Create a route and view for /student/edit/ and put logic in there to handle the case for when you're creating a record on POST.

Categories

Resources