AJAX Form post for Django registration 1.0 - django

I have a view that sub classes from Django registration 1.0:
class RegistrationView(RegistrationView):
pass
I do this because I would like to now make the post over AJAX. I'm not sure what methods I have to overwrite tho? any examples or advise?
This is my view.py:
{% block content %}
<form method="post" action="" id="registration">
{{ form.as_p }}
<input type="submit" value="{% trans 'Submit' %}" />
</form>
<script>
$('#registration').submit(function(e){
e.preventDefault(); //prevent default form submit
$.ajax({
url: '/accounts/register/',
type: 'POST',
contentType: "application/json;charset=utf-8",
dataType: "json",
data: {
'csrfmiddlewaretoken': '{% csrf_token %}',
'id_username': $("#id_username").val(),
'id_email': $("#id_email").val()
},
success: function() {
alert('Test');
},
error: function(errorThrown){
console.log(errorThrown);
alert('Error');
alert(errorThrown);
}
});
});
Django registration 1.0 view
class RegistrationView(_RequestPassingFormView):
"""
Base class for user registration views.
"""
disallowed_url = 'registration_disallowed'
form_class = RegistrationForm
http_method_names = ['get', 'post', 'head', 'options', 'trace']
success_url = None
template_name = 'registration/registration_form.html'
def dispatch(self, request, *args, **kwargs):
"""
Check that user signup is allowed before even bothering to
dispatch or do other processing.
"""
if not self.registration_allowed(request):
return redirect(self.disallowed_url)
return super(RegistrationView, self).dispatch(request, *args, **kwargs)
def form_valid(self, request, form):
new_user = self.register(request, **form.cleaned_data)
success_url = self.get_success_url(request, new_user)
# success_url may be a simple string, or a tuple providing the
# full argument set for redirect(). Attempting to unpack it
# tells us which one it is.
try:
to, args, kwargs = success_url
return redirect(to, *args, **kwargs)
except ValueError:
return redirect(success_url)
def registration_allowed(self, request):
"""
Override this to enable/disable user registration, either
globally or on a per-request basis.
"""
return True
def register(self, request, **cleaned_data):
"""
Implement user-registration logic here. Access to both the
request and the full cleaned_data of the registration form is
available here.
"""
raise NotImplementedError

The "registration 1.0" app hasn't really been created to support ajax in the first place, so you have a lot of overriding to do.
Just to make the registration working you need something like this:
import json
from django.http import HttpResponse
from django.views.generic.edit import CreateView
from django.contrib.auth.models import User
from registration.views import RegistrationView
class AjaxableResponseMixin(object):
def get_form_kwargs(self):
kwargs = {'initial': self.get_initial()}
if self.request.method in ('POST', 'PUT'):
dict_ = self.request.POST.copy()
del dict_['csrfmiddlewaretoken']
kwargs.update({
'data': dict_,
'files': self.request.FILES,
})
return kwargs
def render_to_json_response(self, context, **response_kwargs):
data = json.dumps(context)
response_kwargs['content_type'] = 'application/json'
return HttpResponse(data, **response_kwargs)
def form_invalid(self, form):
response = super(AjaxableResponseMixin, self).form_invalid(form)
if self.request.is_ajax():
return self.render_to_json_response(form.errors, status=400)
else:
return response
def form_valid(self, request, form):
if self.request.is_ajax():
new_user = self.register(request, **form.cleaned_data)
data = {
'pk': new_user.pk,
}
return self.render_to_json_response(data)
else:
response = super(AjaxableResponseMixin, self).form_valid(request, form)
return response
class MyRegistrationView(AjaxableResponseMixin, RegistrationView):
def register(self, request, **cleaned_data):
del cleaned_data['password2']
user = User.objects.create_user(data['username'], data['email'], data['password1'])
return user
urls.py
(r'^accounts/register/', MyRegistrationView.as_view()),
(r'^accounts/', include('registration.backends.default.urls')),
html
<!DOCTYPE html>
<html>
<head>
<title></title>
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
</head>
<body>
<form id="registration" action="." method="post">{% csrf_token %}
{{ form }}
<input type="submit" name="submit" value="Submit" />
</form>
<script type="text/javascript">
$('#registration').submit(function(e){
e.preventDefault();
$.ajax({
url: '/accounts/register/',
type: 'POST',
dataType: "json",
beforeSend: function (request) {
request.setRequestHeader("X-CSRFToken", $('input[name="csrfmiddlewaretoken"]').val());
},
data: $('#registration').serialize(),
success: function() {
console.log('success');
},
error: function(errorThrown){
console.log(errorThrown);
}
});
});
</script>
</body>
</html>

Related

How to stop Django from rendering result in new tab

I have following views and each time form is submitted, result is rendered in new tab which has empty form.
How to render result in same form (with data submitted) without opening new tab?
views.py
class contact(View):
def __init__(self, logger=None, **kwargs):
self.logger = logging.getLogger(__name__)
def get(self, request):
return render(request, 'test.html')
def post(self, request):
if request.method == 'POST':
form = ContactForm(request.POST, request.FILES)
if form.is_valid():
self.host = form.data['ip']
messages.success(request, "Successful")
else:
form = ContactForm()
else:
form = ContactForm()
return render(request, 'test.html', {'form':form})
forms.py
class ContactForm(forms.Form):
ip = forms.CharField()
urls.py
urlpatterns = [
path('', contact.as_view()),
]
html
<body>
<form action="/" method= "post" enctype="multipart/form-data">
{% csrf_token %}
{{ form }}
<button type="submit">Submit</button>
</form>
</body>
if form.is_valid()
form.save()
messages.success(request, 'Contact request submitted successfully.')
return render(request, 'your_page.html', {'form': ContactForm(request.GET)})

Django Error: NoReverseMatch at / Reverse for 'like-post' not found

I'm developing a simple blog with Django. I tried adding ajax functionality to my like button. But got this error:
Reverse for 'like-post' with arguments '('',)' not found. 1 pattern(s)
tried: ['like/(?P[0-9]+)$']
PS: I followed this video to create a like button and this video add ajax functionality
views.py
class PostDetailView(FormMixin, DetailView):
model = Post
form_class = CommentForm
def get_success_url(self):
return reverse('post-detail', kwargs={'pk': self.object.id})
def get_context_data(self, **kwargs):
context = super(PostDetailView, self).get_context_data(**kwargs)
postid = get_object_or_404(Post, id=self.kwargs['pk'])
total_likes = postid.total_likes()
context['form'] = CommentForm(initial={'post': self.object})
context['total_likes'] = total_likes
return context
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
def form_valid(self, form):
form.save()
return super(PostDetailView, self).form_valid(form)
def LikeView(request, pk):
post = Post.objects.get(id=pk)
#post = get_object_or_404(Post, id=request.POST.get('post-id'))
post.likes.add(request.user)
context = {
'post': post,
'total_likes': post.total_likes,
}
if request.is_ajax():
html = render_to_string('blogsite/like_section.html', context, request=request)
return JsonResponse({'form': html})
return HttpResponseRedirect(reverse('blogsite-home'))
urls.py
urlpatterns = [
path('', PostListView.as_view(), name='blogsite-home'),
path('post/<int:pk>/', PostDetailView.as_view(), name='post-detail'),
path('post/new/', PostCreateView.as_view(), name='post-create'),
path('post/<int:pk>/update/', PostUpdateView.as_view(), name='post-update'),
path('post/<int:pk>/delete/', PostDeleteView.as_view(), name='post-delete'),
path('like/<int:pk>', LikeView, name='like-post'),
]
base.html
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function(event){
$(document).on('click', '#like', function(event){
event.preventDefault();
var pk = $(this).attr('value');
$.ajax({
type: 'POST',
url: '{% url "like-post" post.pk %}',
data: {'id':pk, 'csrfmiddlewaretoken':'{{ csrf_token }}'},
dataType: 'json',
success: function(response){
$('#like-section').html(response['form'])
console.log($('#like-section').html(response['form']));
},
error: function(rs, e){
console.log(rs.responseText);
}
});
});
});
</script>
like_section.html
<h5><form method="POST" action="{% url 'like-post' post.id %}">
{% csrf_token %}
<button type="submit" id="like" class="btn btn-link btn-sm" name="post-id" value="{{ post.id }}"><strong><i class="fa fa-thumbs-up"></i> {{ post.total_likes }}</strong></button><h6 align ="right" class="d-inline-block">
<i class="fa fa-facebook-f"></i> <i class="fa fa-linkedin"></i>
</h6></form>
like_section.html is then included in my post_detail.html
<div id="like-section">
{% include 'blogsite/like_section.html' %}
</div>
I can't seem to find a solution to this problem.
If believe error comes out when you try to load post detail view. You're missing post variable in get_context_data of the PostDetailView. And as you're trying to access post.pk in {% url "like-post" post.pk %}. When Django does not find variable in context, the template system inserts the value of the engine’s string_if_invalid configuration option, which defaults to ''(empty string). As a result, url tag tries to lookup for url which is like/<string:pk> which is not defined in your urls.py and thus outputs error. So, what actually you have to do is to add post to context in get_context_data.

django + ajax post form

i tru use ajax with django.
There are 2 forms. the first with the name and mail. and a quick form with a confirmation code that comes in the mail.
views.py
def get_name(request):
if request.method == 'POST':
user_code = generate_code(8)
subject = 'code'
message = user_code
form = NameForm(request.POST)
if form.is_valid():
Registration.objects.create(fio=request.POST['fio'],mail=request.POST['mail'])
send_mail(subject, message,settings.EMAIL_HOST_USER,[mail],fail_silently=False)
return JsonResponse({ 'form1': render_to_string( 'registers/endreg.html', {'form': NameForm1()},request=request ) })
else:
form = NameForm()
return render(request, 'registers/detail.html', {'form': form})
template (detail.html)
<form action="" method="post" autocomplete="off" id="my_form">
{% csrf_token %}
<div class="contact-form" >
<h1>{%trans 'Registers' %}</h1>
<div class="txtb">{{form.fio.label}} {{form.fio}}{{form.fio.help_text}}</div>
<div class="txtb">{{form.phone.label}} {{form.phone}}{{form.phone.help_text}}</div>
<input type="submit" value="{%trans 'send' %}" class="btn" id="btn">
</div>
</form>
I am hanging an event to submit this form
$(document).ready(function()
{ $("#my_form").submit(function(event)
{ event.preventDefault();
$this = $(this);
$.ajax({
type: "POST",
data: $this.serialize(),
success: function(data)
{ console.log(data);
var parent=$("#my_form").parent();
parent.html(data.form1);
},
error: function(data)
{ console.log(data);
$this.html(data);
}
});
});
});
ajax request works and get my 2 form (endreg.html)
<form action="endreg/" method="post" autocomplete="off" id="my_form2">
{% csrf_token %}
<div class="verification" >
<div class="ver">
{{form}}
</div>
<input type="submit" value="{%trans 'send' %}" class="btn1" >
</div>
</form>
views.py
def endreg(request):
if request.method == 'POST':
form = NameForm1(request.POST)
if form.is_valid():
code_use = form.cleaned_data.get("key")
try:
user = Registration.objects.get(code=code_use)
user.verification = True
user.save()
JsonResponse({'message': 'thanks.'})
except:
JsonResponse({'error': 'erorr.'})
else:
form = NameForm1()
return render(request, 'registers/endreg.html', {'form': form})
and 2nd ajax.
$(document).ready(function()
{ $("#my_form2").submit(function(event)
{ event.preventDefault();
$this = $(this);
$.ajax({
type: "POST",
data: $this.serialize(),
success: function(data)
{ console.log(data);
},
error: function(data)
{ console.log(data);
}
});
});
});
Now the question. why when I enter the code in the second form, the code is applied and a redirect to localhost:8000/endreg occurs with json .
Looks like your form is not valid, thats why it is loading the same page with the entered data. You should handle the failure condition for form.is_valid(). And also don't add the blank exception block for handling exceptions.
def endreg(request):
if request.method == 'POST':
form = NameForm1(request.POST)
if form.is_valid():
code_use = form.cleaned_data.get("key")
try:
user = Registration.objects.get(code=code_use)
user.verification = True
user.save()
messages.warning(request, u'thanks.')
except Registration.DoesNotExist as e: # Handling Exception for get()
print("NOT FOUND", e)
messages.warning(request, u'error.')
else: # if form is not valid
messages.warning(request, u'not valid.')
form = NameForm1() # reset the form
else:
form = NameForm1()
return render(request, 'registers/endreg.html', {'form': form})
In your HTML, you can render {{ form.errors }} as well.

Django web app not redirecting and not posting

I an not sure where is the problem as I press submit button, it went through with no error shown. It was supposed to update the database with the data filled in form then redirect them back to 'search' page (option.html).
models.py:
OptionChoice = (
('A','A'),
('B','B'),
('C','C'),
)
class OptionPlan(models.Model):
option = models.CharField(max_length=200, choices=OptionChoice, default="DEFAULT", blank=True)
...
updated = models.DateField(max_length=20, null=True)
updatedBy = models.CharField(max_length=10, null=True)
urls.py:
app_name = 'Benefits'
urlpatterns = [
path('simple_upload', views.simple_upload, name='simple_upload'),
#path('search', views.search, name='search'),
path('search/', FilterView.as_view(filterset_class=BenefitsFilter, template_name='Benefits/option.html'), name='search'),
path('OptionUpdate/<int:id>', views.OptionUpdate.as_view(), name='OptionUpdate')
]
views.py:
def search(request):
option = OptionPlan.objects.get_queryset()
option_filter = BenefitsFilter(request.GET, queryset=option)
return render(request, 'Benefits/option.html', {'filter':option_filter})
class OptionUpdate(UpdateView):
model = OptionPlan
fields =[
'option',
...
'cb_updatedBy',
'cb_updated',
]
template_name = 'Benefits/OptionUpdate.html'
slug_field = 'id'
slug_url_kwarg = 'id'
def form_valid(self, request, obj, form, change):
OptionPlan = form.save(commit=False)
if OptionPlan.option and 'option' in form.changed_data:
OptionPlan.updatedBy = str(self.request.user)
OptionPlan.updated = timezone.localtime(timezone.now())
OptionPlan.save()
return redirect('Benefits:search')
optionUpdate.html:
{% if user.is_authenticated %}
<div style="margin-left:100px;margin-right:100px;">
<form method="POST">
<div class="row">
<div class="col">
<h2 class="alert alert-primary">...</h2>
{% csrf_token %}
<div class="row">
<div class="col-4" style="font-size:30px;">
{{ form.option|as_crispy_field }}
</div>
</div>
...
<div class="col">
<h2 class="alert alert-success">...</h2>
...
<div class="col" style="font-size:30px;">
{{ form.cb_remarks|as_crispy_field }}
</div>
</div>
<button type="submit" class="btn btn-primary btn-block">2020 Option Form Update</button>
</div>
</form>
</div>
{% else %}
Thank you so much for helping!
Edit:
What version of Django are you using? A cursory look at generic UpdateView* from Django v1.3 through v2.2 use this same post method:
def post(self, request, *args, **kwargs):
"""
Handle POST requests: instantiate a form instance with the passed
POST variables and then check if it's valid.
"""
form = self.get_form()
if form.is_valid(): <--- you passed here so your form is valid
return self.form_valid(form) <-- you overwrote this method (problem area)
else:
return self.form_invalid(form)
*get familiar with that website if you are using class based views, its a life saver.
I am not sure how your form_valid method is being called with four variables: request, obj, form, change when it only expects one variable.
I typically split this logic apart and would make a separate form:
forms.py
class OptionPlanUpdateForm(forms.ModelForm):
class Meta:
model = OptionPlan
fields = [
'option',
'cb_updatedBy',
...
'cb_updated',
]
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user', None)
super().__init__(*args, **kwargs)
def save(self, **kwargs):
option_plan = super().save(commit=False)
if 'option' in self.changed_data:
option_plan.updatedBy = str(self.user)
option_plan.updated = timezone.localtime(timezone.now())
option_plan.save()
return option_plan
Since we have a form we have to update our view to handle the form. We pass the user to the form through the get_form_kwargs method.
class OptionUpdate(UpdateView):
form_class = OptionPlanUpdateForm
model = OptionPlan
slug_field = 'id'
slug_url_kwarg = 'id'
template_name = 'Benefits/OptionUpdate.html'
success_url = reverse_lazy('Benefits:search')
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
***To test for errors in your form you can do the following:
def post(self, request, *args, **kwargs):
form = self.form_class(self.request.POST)
print(form.errors)
return super().post(request, *args, **kwargs)
If I were to assume, the form is throwing some type of error that you aren't printing nor handling. Try checking if any form errors exists to begin with.

How to display form errors in modal box(context_processors, base.html)?

I have register function, it is displayed on every pages in my project using context_processors.
How to display errors if my form is not valid in my modal box in base.html?
Now errors is displayed in: /register/ subpage.
views.py
def UserRegistration(request):
if request.user.is_authenticated():
return HttpResponseRedirect('/showcase/')
if request.method == 'POST':
form = RegistrationForm(request.POST)
if form.is_valid():
user = User.objects.create_user(username=form.cleaned_data['username'], email= form.cleaned_data['email'], password = form.cleaned_data['password'])
user.save()
klient = ClientProfile(user=user, name= form.cleaned_data['name'], address= form.cleaned_data['address'], zip_code=form.cleaned_data['zip_code'], city=form.cleaned_data['city'], tel= form.cleaned_data['tel'] )
klient.save()
return HttpResponseRedirect('/')
return render_to_response('registration.html', {'form':form}, context_instance=RequestContext(request))
else:
form = RegistrationForm()
context= {'form':form}
return render_to_response('registration.html', context, context_instance=RequestContext(request))
context_processors.py
from content.forms import *
def include_register_form(request):
form = RegistrationForm()
return {'register_form':form}
base.html
<div class="modalBox" id="modalRegister">
<div class="modalBox_iks"></div>
<div class="titleShowcase">Register</div>
<form method="POST" action="/register/">{%csrf_token%}
{{register_form}}
<input type="submit" value="Register">
</form>
</div>
It is possible?
You need to post your data with Ajax call, Showing errors in modal need Ajax call.
Or you can use third party app to enable Ajax form validation
what version of django are you using? If you are in django 1.5, use FormView.
view.py
class UserRegistration(FormView):
template_name = 'form_registration.html'
def render_to_response(self, context):
if self.request.user.is_authenticated():
return redirect('other_page')
return super(UserRegistration, self).render_to_response(context)
def form_valid(self, form):
# Here you know that you form is valid
user = User.objects.create_user(username=form.cleaned_data['username'], email=form.cleaned_data['email'], password = form.cleaned_data['password'])
user.save()
klient = ClientProfile(user=user, name= form.cleaned_data['name'], address= form.cleaned_data['address'], zip_code=form.cleaned_data['zip_code'], city=form.cleaned_data['city'], tel= form.cleaned_data['tel'] )
klient.save()
return redirect('home') #I'm not sure that this really redirect you
Now write a 'form_registration.html' template where you show the errors. see here
And in your 'base.html'
<div class="modalBox" id="modalRegister">
<div class="modalBox_iks"></div>
<div class="titleShowcase">Register</div>
<form method="POST" id="ajax_form"action="/register/">{%csrf_token%}
{% include "form_registration.html" with form=form %}
<input type="submit" id="ajax_form_submit"value="Register">
</form>
</div>
Now, for your ajax, you can use this jquery plug-in.
You can set the 'target' option to override with the server response
Maybe that javascript help you:
<script>
$('#modalRegister').click("#ajax_form_submit", function(event){
event.preventDefault();
$('#ajax_form').ajax_form(target:'#ajax_form').submit();
})
</script>
I've used that plugin, it works fine.
hope that help!