Page not redirecting after form submit - python

I have a form which creates a new category. Previously, the form was in a different template which worked fine but since it's only a simple form I have decided to render it in modal form instead of redirecting to a different page.
The user can add a new category, however the success message and the page rendering after the form submit is not shown. It only shows up if you refresh the page. The response message is 302.
I've done similar method with other forms which worked perfectly fine.
forms.py
class CategoryModelForm(forms.ModelForm):
def clean_name(self):
print(self.cleaned_data['name'])
name = self.cleaned_data['name']
try:
Category.objects.get(name__iexact=name)
except ObjectDoesNotExist:
return name
raise forms.ValidationError('Category Name already exists.')
class Meta:
model = Category
fields = ['name']
views.py
#method_decorator(login_required, name='dispatch')
class CategoryView(TemplateView):
template_name = 'content/category_list.html'
def get_context_data(self, **kwargs):
context = super(CategoryView, self).get_context_data(**kwargs)
categories = Category.objects.all()
user = self.request.user
category_list = []
for category in categories:
article_count = category.article_count(user)
include = category.show or user.usertype_is_staff() or user.is_superuser
requested_by = category.requested_by if category.requested_by else ''
cat = {
'reference': category.pk,
'name': category.name,
'show': category.show,
'article_count': article_count,
'has_articles': article_count > 0,
'requested_by': requested_by,
'requested_by_name': requested_by.profile.full_name if requested_by and requested_by.profile.full_name
else '-'
}
include and category_list.append(cat)
context['categories'] = category_list
context['form'] = CategoryModelForm(self.request.POST or None)
return context
def post(self, request, *args, **kwargs):
context = self.get_context_data(**kwargs)
if context['form'].is_valid():
context['form'].save()
messages.success(request, 'Successfully created new category.')
return redirect('content:category')
return super(CategoryView, self).render_to_response(context)
category_list.html
<div id="newCategory" data-id="new-account" class="modal fade bd-example-modal-lg"
tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="syn-breadcrumb">
<div class="syndicator-form-container">
<form class="syndicator-form" action="{% url 'content:category' %}"
method="post">
{% csrf_token %}
<div class="">
<h3 class="lighter-weight">
{% if user.usertype_is_supplier %}
Request New Category
{% else %}
Add New Category
{% endif %}
</h3>
</div>
<div class="form-fields">
<div class="non-field-errors">
{{ form.non_field_errors }}
</div>
<div id="{{ form.name.name }}" class="d-flex flex-column fields">
<div class="lighter-weight"><label for="id_name">Name</label></div>
<div>{{ form.name }}</div>
<div class="field-errors">{{ form.name.errors }}</div>
</div>
</div>
<div class="submit-button">
<button type="submit" class="btn btn-primary form-control">{% trans 'Submit' %}</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
I want the page to be redirected to an updated list of the categories after the form submit with the success message. As well as show the error message if the category name already exists or if the fields re empty.

You are using self.request instead of request even though request is already passed in post method
def post(self, request, *args, **kwargs):
context = self.get_context_data(**kwargs)
context['form'] = CategoryModelForm(request.POST or None) # use request.POST
I would rather suggest you to use a FormView or rather a generic view. (docs). You won't need to handle the form by yourself.
#method_decorator(login_required, name='dispatch')
class CategoryView(FormView):
template_name = 'content/category_list.html'
form = CategoryModelForm
success_url = reverse("content:category")
def form_valid(self, form):
self.obj = form.save(commit=True)
messages.success(self.request, 'Successfully created new category.')
return super(CategoryView, self).form_valid(form)
def get_context_data(self, **kwargs):
context = super(CategoryView, self).get_context_data(**kwargs)
categories = Category.objects.all()
user = self.request.user
category_list = []
for category in categories:
article_count = category.article_count(user)
include = category.show or user.usertype_is_staff() or user.is_superuser
requested_by = category.requested_by if category.requested_by else ''
cat = {
'reference': category.pk,
'name': category.name,
'show': category.show,
'article_count': article_count,
'has_articles': article_count > 0,
'requested_by': requested_by,
'requested_by_name': requested_by.profile.full_name if requested_by and requested_by.profile.full_name
else '-'
}
include and category_list.append(cat)
context['categories'] = category_list
# form will be automatically added to context

Related

How to make Django form field blank after submit?

I've created a django subscription form. I want to show a 'Thank You' message below the form after submitting but if I submit the form, email field is still showing the value. I've tried HttpResponseRedirect('/') but doing so doesn't show 'Thank You' message.
#Views.py
global categories
categories = ['Development','Technology','Science','Lifestyle','Other']
class IndexView(TemplateView):
model = Post
template_name = 'blog/index.html'
def post(self,request,*args,**kwargs):
context = self.get_context_data()
if request.method == 'POST':
form = SubscriberForm(request.POST)
if context["form"].is_valid():
context["email"] = request.POST.get('email')
form.save()
form = SubscriberForm()
return render(request, 'blog/index.html', context=context)
else:
form = SubscriberForm()
def get_context_data(self, **kwargs):
# Call the base implementation first to get a context
context = super(IndexView,self).get_context_data(**kwargs)
# Add in a QuerySet of all the books
context['post_list'] = Post.objects.all()
context["categories"] = categories
form = SubscriberForm(self.request.POST or None) # instance= None
context["form"] = form
return context
#sidebar.html
<div class="subscribe">
<form class="" action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<button id="subscribe-button" type="submit" name="button"><i class="fa fa-paper-plane" aria-hidden="true"></i></button>
</form>
{% if email %}
<h6>Thank you for Subscribing!</h6>
{% endif %}
<!-- <i class="fa fa-paper-plane" aria-hidden="true"></i> -->
</div>
#models.py
class Subscribe(models.Model):
email = models.EmailField()
subscribed_on = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ('-subscribed_on',)
def __str__(self):
return 'Subscribed by {} on {}'.format(self.email, self.subscribed_on)
#forms.py
class Subscribe(models.Model):
email = models.EmailField()
subscribed_on = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ('-subscribed_on',)
def __str__(self):
return 'Subscribed by {} on {}'.format(self.email, self.subscribed_on)
Instead of rendering the template you can redirect() after saving the form.
And to render the success message you can use the django messaging framework.
def post(self,request,*args,**kwargs):
context = self.get_context_data()
if request.method == 'POST':
form = SubscriberForm(request.POST)
if context["form"].is_valid():
context["email"] = request.POST.get('email')
form.save()
messages.success(request, 'Thank you for subscribing')
return redirect('/')
else:
form = SubscriberForm()
return render(request, 'blog/index.html', context=context)
Now in the template you can render the messages like this.
<div class="subscribe">
<form class="" action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<button id="subscribe-button" type="submit" name="button"><i class="fa fa-paper-plane" aria-hidden="true"></i></button>
</form>
{% if messages %}
<ul class="messages">
{% for message in messages %}
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
<!-- <i class="fa fa-paper-plane" aria-hidden="true"></i> -->
</div>

Django 'Model matching query does not exist.' error

I have a three simple models. User, Restaurant, Menu. A single user can have many restaurants, and each restaurant can have many Menus. I am using the generic Django CreateView for the Posting of the Restaurants and Menus to their respective models. This works for The restaurants, But fails for the Menus and I get a "Restaurant matching query does not exist" ERROR. I feel that it is a URL issue because I can reach the template if I input it manually, but fails when i use the button.
VIEWS.py
#login_required
def profile(request, pk):
user = CustomUser.objects.get(pk=pk)
if not user.id == request.user.pk:
raise PermissionDenied()
else:
context = {
'user': user,
'rests': Restaurant.objects.filter(account=request.user).order_by('-date'),
'countRests': Restaurant.objects.filter(account=request.user).count(),
}
return render(request, 'restaurants/profile.html',context)
class RestCreateView(LoginRequiredMixin, CreateView):
template_name = 'restaurants/makeRestaurant.html'
form_class = RestCreateForm
def form_valid(self, form):
form.instance.account = self.request.user
return super().form_valid(form)
def RestMenus(request, pk, name):
rest = Restaurant.objects.get(name=name)
user = CustomUser.objects.get(pk=pk)
if not user.id == request.user.pk:
raise PermissionDenied()
else:
context = {
'rest': rest,
'user': user,
'menus': Menu.objects.filter(restaurant=rest).order_by('-uploadDate'),
'countMenus': Menu.objects.filter(restaurant=rest).count(),
}
return render(request, 'restaurants/menus.html',context)
class MenuCreateView(LoginRequiredMixin, CreateView):
template_name = 'restaurants/makeMenu.html'
form_class = MenuCreateForm
def form_valid(self, form):
form.instance.restaurant = self.request.restaurant
return super().form_valid(form)
URLS.py
urlpatterns = [
path('', home, name='home'),
path('profile/<int:pk>/',profile, name='profile'),
path('profile/<int:pk>/createRest/', RestCreateView.as_view(), name='createRest'),
path('profile/<int:pk>/restaurant/<str:name>',RestMenus, name='RestDetail'),
path('profile/<int:pk>/restaurant/<str:name>/createMenu/', MenuCreateView.as_view(), name='createMenu'),
]
FORMS.py
class RestCreateForm(forms.ModelForm):
class Meta:
model = Restaurant
fields = [
'name'
]
class MenuCreateForm(forms.ModelForm):
class Meta:
model = Menu
fields = [
'name',
'menuFile'
]
Template (Menus.html)
<section id="menusdash">
<div class="container">
<br>
<h3>{{ rest.name }}'s Menus</h3>
<br>
<div class="row">
<div class="col-md-10">
{% if countMenus == 0 %}
<p>You have no Menus</p>
{% else %}
{% for menu in menus %}
<div class="card" style="width: 18rem;">
<div class="card-body">
<h5 class="card-title">Menu Name: {{ menu.name }}</h5>
View Menu
View QR Code
Edit
</div>
</div>
{% endfor %}
{% endif %}
</div>
<div class="col-md-2">
<button>Make a Menu</button>
</div>
</div>
</div>
</section>
The URL seems to drop the str:name/ for the menu create template. Is it possible to pass a second argument using a CreateView, SO that i can have the PK and String:name in the url?

Filter queryset inside a form

I have one app that holds a list of work orders, and another app that holds list of parts.
class Order(models.Model):
parts = models.ManyToManyField(Part, blank=True) # Assosiated parts
class Part(models.Model):
partnum = models.CharField(max_length=20) # Part number
mwos = models.ManyToManyField('mtn.Order', blank=True) # Assosiated work orders
Now i want to add a button to my DetailView for order which will open a list of parts, which i will be able to add to my order. At the moment i have a created an UpdateView for my order
class AddPartView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
model = Order
form_class = AddPartForm
...
and a form
class AddPartForm(forms.ModelForm):
class Meta:
model = Order
fields = ['parts', ]
labels = {'parts': "Parts", }
def FilterList(request):
qs = Part.objects.all()
search_part_query = request.GET.get('search_part')
if is_valid_queryparam(search_part_query):
qs = qs.filter(Q(partnum__icontains=search_part_query)
| Q(descr__icontains=search_part_query)
).distinct()
return qs
def __init__(self, *args, **kwargs):
super(AddPartForm, self).__init__(*args, **kwargs)
self.fields["parts"].widget = CheckboxSelectMultiple()
self.fields["parts"].queryset = self.FilterList()
for this template
{% block content %}
<form method="GET" action=".">
<div class="form-row justify-content-start">
<div class="form-group col-md align-self-center">
<div class="input-group">
<input class="form-conrol py-2 border-right-0 border" type="search" placeholder="Find part" name="search_part">
<span class="input-group-append">
<div class="input-group-text bg-transparent">
<i class="fa fa-search"></i>
</div>
</span>
</div>
</div>
</div>
<button type="submit" class="btn btn-primary btn-sm btn-block">Search</button>
</form>
<form action="{% url 'mtn:add_part' order.id %}" method='post'>
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Save</button>
</form>
{% endblock content %}
But when i'm executing it i get
'AddPartForm' object has no attribute 'GET'
error.
I am new to programming, so maybe i am approaching this the wrong way.
A form is normally not aware of the request object. You can make such a form, for example with:
class AddPartForm(forms.ModelForm):
class Meta:
model = Order
fields = ['parts', ]
labels = {'parts': "Parts", }
widgets = {
'parts': CheckboxSelectMultiple
}
def filter_list(self, request):
qs = Part.objects.all()
search_part_query = request.GET.get('search_part')
if is_valid_queryparam(search_part_query):
qs = qs.filter(Q(partnum__icontains=search_part_query)
| Q(descr__icontains=search_part_query)
).distinct()
return qs
def __init__(self, *args, request=None, **kwargs):
super(AddPartForm, self).__init__(*args, **kwargs)
self.fields["parts"].queryset = self.filter_list(request)
In the AddPartView, you can the pass the request as parameter to the form by overriding the .get_form_kwargs(..) method [Django-doc]
class AddPartView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
model = Order
form_class = AddPartForm
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs.update(request=self.request)
return kwargs

Django Form Field Validation failed to work

Here is my form.
class POICreateForm(ModelForm):
def __init__(self, *args, **kwargs):
super(POICreateForm, self).__init__(*args, **kwargs)
self.fields['latitude'].widget = HiddenInput()
self.fields['longitude'].widget = HiddenInput()
self.fields['picture'].required = True
class Meta:
fields = ['name', 'vip', 'category', 'place', 'latitude', 'longitude', 'picture', 'website', 'description',
'phone',
'email']
model = PointOfInterest
def clean(self):
cleaned_data = super(POICreateForm, self).clean()
pic = cleaned_data.get('picture', None)
if not pic:
msg = 'You must Choose an image'
self.add_error('picture', msg)
return cleaned_data
I have given required=True for picture field and also I overridded the clean method. BUt both failed to show the validation error.
Here is my view
class POIFormCreateView(LoginRequiredMixin, CreateView):
login_url = '/login/'
model = PointOfInterest
form_class = POICreateForm
success_url = reverse_lazy('POIs')
def post(self, request, *args, **kwargs):
query_dict = request.POST.dict()
super(POIFormCreateView, self).post(request, *args, **kwargs)
filtered_dict = {i: j for i, j in query_dict.items() if i.endswith('day')}
out = PointOfInterestQuery.create_or_update_open_hours(filtered_dict)
if out:
return HttpResponseRedirect(reverse('POIs'))
return HttpResponse('Error :(')
template.html
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<script type="text/javascript">
</script>
<h1>New Point Of Interest</h1>
<form role="form" method="POST" action="/poi/add/" class="post-form form-horizontal"
enctype="multipart/form-data" name="poi_create" onsubmit="return validateForm()">{% csrf_token %}
<div class="container row">
<div class="col-lg-6">
<!-- customizing form -->
{{ form|crispy }}
<!-- End of customization -->
</div>
<div class="col-lg-6">
<div id="map"></div>
{% include 'open_hours.html' %}
</div>
</div>
<button type="submit" id="poi-submit" class="save btn btn-default btn-primary center-block">Save
</button>
</form>
<div class="modal-footer"><a href="/poi/">
<button type="button" class="btn btn-default btn-danger center-block">Cancel
</button>
</a></div>
{% endblock %}
You've overridden the post method and avoided using the form at all. All of this logic should be in the form_valid method instead; that allows the CreateView to do the normal job of form validation and re-displaying the page with errors if the form is invalid, while your processing happens if the form is valid.
Note also however that you should be getting your values to populate filtered_dict from the form's cleaned_data dict, not directly from request.POST.
class POIFormCreateView(LoginRequiredMixin, CreateView):
login_url = '/login/'
model = PointOfInterest
form_class = POICreateForm
success_url = reverse_lazy('POIs')
def form_valid(self,form):
super(POIFormCreateView, self).form_valid(form)
filtered_dict = {i: j for i, j in self.request.POST.items() if i.endswith('day')}
out = PointOfInterestQuery.create_or_update_open_hours(filtered_dict)
if out:
return HttpResponseRedirect(reverse('POIs'))
return HttpResponse('Error :(')

Django- why after using ajax, it becomes an empty page

The function on the page:
user enter some information on the form
without refreshing, the right side can show some query result(sales) based on user entry
Before adding the ajax function, the page can display the form and the table. But after using the ajax, the page becomes empty.
Can anyone help check what is the reason? Thanks in advance.
url
url(r'^result_list/$',ResultView.as_view(),name='result'),
models.py
class Input(models.Model):
company=models.CharField(max_length=100)
region=models.CharField(max_length=100)
class Result(models.Model):
sales=models.IntegerField(blank=False,null=False)
views.py
from django.views.generic.list import ListView
from django.core import serializers
class ResultView(ListView):
context_object_name = 'result_list'
template_name = 'result_list.html'
def get_queryset(self):
return Result.objects.all()
def post(self, request, *args, **kwargs):
form = InputForm(request.POST)
if form.is_valid():
if self.request.is_ajax():
company = form.cleaned_data['company']
region = form.cleaned_data['region']
queryset=Result.objects.filter(region=region).aggregate(Sum('sales'))
return HttpResponse(json.dumps(queryset))
else:
return HttpResponse(form.errors)
'''def get_context_data(self, **kwargs):
context = super(ResultView, self).get_context_data(**kwargs)
context["sales"] = self.get_queryset().aggregate(Sum('sales'))'''
html
<style>...CSS part
</style>
<script src="http://apps.bdimg.com/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.js"></script>
<script src="http://malsup.github.com/jquery.form.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$("#InputForm").submit(function() { // catch the form's submit event
var region= $("#id_region").val();
var company= $("#id_company").val();
$.ajax({
data: $(this).serialize(), // get the form data
type: $(this).attr('post'),
dataType: 'json',
url: "dupont_list/",
success: function(data) {
var html = "<table>"
html += "<td>"+data['sales__sum']+"</td>"
html += "</table>"
$("#result").html(html);
html += "</table>"
$("#result").html(html);
}
return false;
});
})
</script>
<form id="InputForm" method="post" action=""> #here is the data entry form
{% csrf_token %}
<!--enter the company name-->
<div class="field">
{{ form.company.errors }}
<label id="id_company" name="company" for="{{ form.company.id_for_label }}">Company:</label>
{{ form.company }}
</div>
<!--select region-->
<div class="field" >
<label> Select the Region:
{{ form.region }}
{% for region in form.region.choices %}
<option value="region" name= "region" id="id_region">{{region}} </option>
{% endfor %}
</label>
</div>
<!--submit-->
<p><input type="button" value="Submit" /></p></div>
</form>
</div>
<div id="result" class="result"> <!--Showing the filtered result in database-->
<table>
<tr><b>Sales</b></tr>
<td> {{sales.sales__sum}}</td>
<tr><b>Employee</b></tr>
<td> {{employee.employee__sum}}</td>
</table>
I would go with a FormView:
class ResultView(FormView):
context_object_name = 'result_list'
template_name = 'result_list.html'
form_class = InputForm
def get_context_data(self, **kwargs):
context = super(ResultView, self).get_context_data(**kwargs)
context["results"] = Result.objects.all()
context["sales"] = context.results.aggregate(Sum('sales'))
return context
def form_valid(self,form):
company = form.cleaned_data['company']
region = form.cleaned_data['region']
queryset = Result.objects.filter(region=region).aggregate(Sum('sales'))
return HttpResponse(json.dumps(queryset))
This way you're bypassing the get_context_data and get_queryset methods if the form is valid and return a custom content response.

Categories

Resources