Codes in views
I am new to django I couldn't able to rectify where it went wrong can anyone please help me on this.
class UpdateVote(LoginRequiredMixin,UpdateView):
form_class = VoteForm
queryset = Vote.objects.all()
def get_object(self,queryset=None):
vote = super().get_object(queryset)
user = self.request.user
if vote.user != user:
raise PermissionDenied('can not change another user vote')
return vote
def get_success_url(self):
movie_id = self.object.movie.id
return reverse('core:movie_detail', kwargs={'pk':movie_id})
def render_to_response(self, context, **response_kwargs):
movie_id = context['object'].id
movie_detail_url = reverse('core:movie_detail',kwargs={'pk':movie_id})
return redirect(to=movie_detail_url)
class MovieDetail(DetailView):
queryset = Movie.objects.all_with_prefetch_persons()
def get_context_data(self, **kwargs):
ctx = super().get_context_data(**kwargs)
if self.request.user.is_authenticated:
vote = Vote.objects.get_vote_or_unsaved_blank_vote(movie=self.object,user=self.request.user)
if vote.id:
vote_url_form = reverse('core:UpdateVote',kwargs={'movie_id':vote.movie.id,'pk':vote.id})
else:
vote_url_form = (reverse('core:create_vote',kwargs={'movie_id':self.object.id}))
vote_form = VoteForm(instance=vote)
ctx['vote_form'] = vote_form
ctx['vote_url_form'] = vote_url_form
return ctx
Codes in form.py
I have used this form to link with UpdateView
from django import forms
from django.contrib.auth import get_user_model
from .models import Movie,Vote
class VoteForm(forms.ModelForm):
user = forms.ModelChoiceField(widget=forms.HiddenInput,queryset=get_user_model().objects.all(),disabled=True)
movie = forms.ModelChoiceField(widget=forms.HiddenInput,queryset = Movie.objects.all(),disabled=True)
value = forms.ChoiceField(widget=forms.RadioSelect,choices=Vote.VALUE_CHOICE)
class Meta:
model = Vote
fields = ('value','user','movie',)
urls.py
This is the url mapping for the view.
from django.contrib import admin
from django.urls import path
from .views import MovieList,MovieDetail,PersonDetail,CreateVote,UpdateVote
app_name = 'core'
urlpatterns = [
path('movies/', MovieList.as_view(), name='movie_list'),
path('movie/<int:pk>/', MovieDetail.as_view(), name='movie_details'),
path('person/<int:pk>/', PersonDetail.as_view(), name='person_details'),
path('movie/<int:movie_id>/vote/', CreateVote.as_view(), name='create_vote'),
path('movie/<int:movie_id>/vote/<int:pk>', UpdateVote.as_view(), name='UpdateVote'),
]
HTML template
This is the template I used.
{% block sidebar %}
<div>
{% if vote_form %}
<form action="{{vote_form_url}}" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ vote_form.as_p }}
<button class="btn btn-primary" type="submit" >Vote</button>
</form>
{% else %}
<p>Login to vote for this movie</p>
{% endif %} </div> {% endblock %}
The problem caused because your form was sent to another path which doesn't allow POST request. vote_form_url is not which you added in the view context, use vote_url_form instead.
...
<form action="{{ vote_url_form }}" method="post" enctype="multipart/form-data">
...
Btw, your MovieDetail view can get rid of if self.request.user.is_authenticated: by using LoginRequiredMixin like UpdateVote view.
Hope that helps!
Related
I have a page for teachers to input the marks and registration number of the students..
After input, it gets stored in the database and the students can fill a form which asks for D.O.B and registration number and get's the marks based on that particular registration from the database..
But when I use post request for the students, it shows form is invalid and says that, the registration number already exists..
My views.py:
from django.shortcuts import render
from django.views.generic.list import ListView
from django.views.generic.edit import CreateView
from django.urls import reverse_lazy
from .models import Mark
from django.contrib.auth.views import LoginView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic.edit import FormView
from .forms import ViewResultForm, AddResultForm
from django.contrib import messages
class ViewResultFormView(FormView):
template_name = 'main/home.html'
form_class = ViewResultForm
success_url= 'result'
def form_valid(self, form):
global registration_number
global dob
registration_number = form.cleaned_data['registration_number']
dob = form.cleaned_data['dob']
return super(ViewResultFormView, self).form_valid(form)
class MarkListView(ListView):
model = Mark
template_name = "main/result.html"
context_object_name = 'result'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['result'] = context['result'].get(registration_number=registration_number, dob=dob)
return context
class MarkCreateView(LoginRequiredMixin, CreateView):
model = Mark
template_name = "main/add.html"
form_class = AddResultForm
def form_valid(self, form):
total_10th = ((form.cleaned_data['class_10_sub_1'] + form.cleaned_data['class_10_sub_2'] + form.cleaned_data['class_10_sub_3'])/300)*30
total_11th = ((form.cleaned_data['class_11_English'] + form.cleaned_data['class_11_Maths'] +form.cleaned_data['class_11_Physics'] +form.cleaned_data['class_11_Chemistry'] +form.cleaned_data['class_11_Comp_Bio'])/500) * 30
total_12th = ((form.cleaned_data['class_12_English'] + form.cleaned_data['class_12_Physics'] +form.cleaned_data['class_12_Chemistry'] +form.cleaned_data['class_12_Maths']+ form.cleaned_data['class_12_Comp_Bio'] + form.cleaned_data['class_12_practicals_Physics'] + form.cleaned_data['class_12_practicals_Chemistry'] + form.cleaned_data['class_12_practicals_Comp_Bio'] )/500)*40
result = total_10th + total_11th + total_12th
total = form.save(commit=False)
total.teacher_name = self.request.user
total.result = result
total.save()
message = messages.success(self.request, f'Result added successfully')
return super().form_valid(form)
class CustomLoginView(LoginView):
template_name = 'main/login.html'
fields = '__all__'
redirect_authenticated_user = True
def get_success_url(self):
return reverse_lazy('add')
home.html:
{% extends 'main/base.html' %}
{%load crispy_forms_tags %}
{% block content %}
<div class="container mt-5 card shadow p-3 mb-5 bg-white rounded">
<legend>Enter your credentials</legend>
<form method="POST">
{% csrf_token %}
{{ form | crispy }}
<input class='btn btn-outline-info' type="submit" value="Submit">
</form>
</div>
{% endblock content %}
result.html:
{% extends 'main/base.html' %}
{% block content %}
<div class="container">
{{ result.student_name }}
<br>
{{ result.dob }}
<br>
{{ result.result }} %
</div>
{% endblock content %}
So once the teacher enters the marks of the student, I calculate the results and store it in the database.. But bcz the teacher has registered a particular registration number, it shows form is invalid when a student tries to enter the same registration number in the form.. I want the registration number to be unique..
So if I have to use GET in home.html, how to access the values of the form?
You should rewrite your ViewResultFormView.form_valid, because you do not want form.save() to be called in the super call. You should retrieve registration_number and dob from the form and then fill a context for the template with a results of the corresponding student.
Also I do not understand what are those global hacks for? If you need to store that info for a several site pages, then you should implement your own authentication for students which will store their auth tokens/cookies somewhere, and then use that authentication info to allow/deny access to certain pages.
I've followed the tutorial here to implement a basic search function: https://learndjango.com/tutorials/django-search-tutorial
I'd like to extend that tutorial by making the search function visible on the results page, allowing for repeated search. However, when I do this I can't get the search form to show up on the search results page. The search button shows up, but not the field to provide input.
Relevant code:
home.html:
<div name="searchform">
<form action="{% url 'search_results' %}" method="get">
{{ form }}
<input type="submit" value="Search">
</form>
</div>
{% block content %}
{% endblock %}
search_results.html:
{% extends home.html}
{% block content %}
<h1>Search Results</h1>
<ul>
{% for city in object_list %}
<li>
{{ city.name }}, {{ city.state }}
</li>
{% endfor %}
</ul>
{% endblock %}
Views.py:
from django.db.models import Q
from django.views.generic import TemplateView, ListView, FormView
from .models import City
class HomePageView(FormView):
template_name = 'home.html'
form_class = SearchForm
class SearchResultsView(ListView):
model = City
template_name = 'search_results.html'
def get_queryset(self):
query = self.request.GET.get('q')
object_list = City.objects.filter(
Q(name__icontains=query) | Q(state__icontains=query)
)
return object_list
urls.py:
from django.urls import path
from .views import HomePageView, SearchResultsView
urlpatterns = [
path('search/', SearchResultsView.as_view(), name='search_results'),
path('', HomePageView.as_view(), name='home'),
]
forms.py:
from django import forms
class SearchForm(forms.Form):
q = forms.CharField(label='', max_length=50,
widget=forms.TextInput(attrs={'placeholder': 'Search Here'})
)
Any advice on how I might troubleshoot this sort of issue (or if I'm blatantly doing something un-django-y) would be greatly appreciated.
You're using ListView which is a Generic display view.
You need to use get method, then you can pass the form to make the search again and stay on the same page.
class SearchResultsView(View):
template_name = 'search_results.html'
form_class = SearchForm
def get(self, request):
form = self.form_class()
query = self.request.GET.get('q')
context = {}
context['form'] = form
context['cities'] = City.objects.filter(
Q(name__icontains=query) | Q(state__icontains=query)
)
return render(self.request, self.template_name, context)
You can achieve the same result with ListView but is better if you use other based view class.
You can check the doc. here
class HomePageView(FormView):
template_name = 'home.html'
form_class = SearchForm # This line!
Remember to also apply the form_class attribute to SearchResultsView, otherwise, no forms will be interpreted. The submit button only shows up because it's not a part of the rendered form.
I am trying to insert a newsletter signup form into my base.html template which is a listview that displays upcoming events and featured shops and everytime I submit the form it returns a 'HTTP error 405'
Any help with this would be appreciated
Views.py
from django.shortcuts import render
from django.views.generic import ListView, TemplateView
from events.models import Event
from newsletter.forms import NewsletterSignUpForm
from shops.models import Shop
class HomeListView(ListView):
template_name = 'core/index.html'
def get_context_data(self, **kwargs):
context = super(HomeListView, self).get_context_data(**kwargs)
context.update({
'events': Event.get_upcoming_events()[:1], # returns only the first event in the list
'shops': Shop.objects.all(),
})
context['newsletter_form'] = NewsletterSignUpForm()
return context
def get_queryset(self):
return None
forms.py
from django.forms import ModelForm
from .models import Newsletter
class NewsletterSignUpForm(ModelForm):
class Meta:
model = Newsletter
fields = ['email']
Models.py
from django.db import models
class Newsletter(models.Model):
email = models.EmailField(unique=True)
date_subscribed = models.DateTimeField(auto_now=False, auto_now_add=True)
def __str__(self):
return f'{self.email}'
base.html
<form method="post">
{% csrf_token %}
{{ newsletter_form|crispy }}
<button class="btn btn-primary" type="submit">Sign Up!</button>
</form>
first add action url in form to handle post data
<form method="post" action="{% url 'submit_url' %}">
{% csrf_token %}
{{ newsletter_form|crispy }}
<button class="btn btn-primary" type="submit">Sign Up!</button>
</form>
urls.py
add url
path('your_url',views.formSubmit,name='submit_url')
views.py
def formSubmit(request):
if request.method == 'POST':
form = NewsletterSignUpForm(request.POST)
if form.is_valid():
form.save()
return redirect('your_list_view_url')
or you can use FormMixin along with classbased views
formmixin with classbased views
Your help will be nice for me. Here are that codes:
models.py:
from django.db import models
class TagModel(models.Model):
tag = models.CharField(max_length=50)
def __str__(self):
return self.tag
class MyModel(models.Model):
title = models.CharField(max_length=50)
tag = models.ManyToManyField(TagModel)
forms.py:
from django import forms
from .models import *
class MyForm(forms.ModelForm):
class Meta:
model = MyModel
fields = '__all__'
views.py:
from django.shortcuts import render, get_object_or_404, redirect
from .models import *
from .forms import *
def MyWriteView(request):
if request.method == "POST":
mywriteform = MyForm(request.POST)
if mywriteform.is_valid():
confirmform = mywriteform.save(commit=False)
confirmform.save()
return redirect('MyDetail', pk=confirmform.pk)
else:
mywriteform = MyForm()
return render(request, 'form.html', {'mywriteform': mywriteform})
form.html(1st trial):
<form method="post">
{% csrf_token %}
{{ mywriteform }}
<button type="submit">Save</button>
</form>
form.html(2nd trial):
<form method="post">
{% csrf_token %}
{{ mywriteform.title }}
<select name="tags" required="" id="id_tags" multiple="">
{% for taglist in mywriteform.tags %}
<option value="{{taglist.id}}">{{taglist}}</option>
{% endfor %}
</select>
<button type="submit">Save</button>
</form>
I am trying to add tags on my post. I made a simple manytomany tagging blog but it does not work. I submitted a post by clicking the save button, and the title was saved, but the tag was not. In the admin, it worked well.
Thank you in advance.
update the code like this
if mywriteform.is_valid():
confirmform = mywriteform.save(commit=False)
confirmform.save()
mywriteform.save_m2m()
return redirect('MyDetail', pk=confirmform.pk)
for more details Refer here
I have a DetailView, in which I show contents of a post and as well I wanted to add comments functionality to that view. I found 2 ways to do it: combine a DetailView and FormView or make a custom view with mixins. Since I am new to Djanfgo, I went on the 1st way, guided by this answer: Django combine DetailView and FormView but i have only a submit button and no fields to fill on a page.
Here is a necessary code:
#urls.py
from . import views
app_name = 'bankofideas'
urlpatterns = [
path('<int:pk>/', views.DetailView.as_view(), name='idea'),
path('<int:idea_id>/vote', views.vote, name='vote'),
path('<formview', views.MyFormView.as_view(), name='myform')
]
#views.py
class DetailView(generic.DetailView):
model = Idea
template_name = 'bankofideas/detail.html'
context_object_name = 'latest_question_list'
def get_queryset(self):
return Idea.objects.filter(pub_date__lte=timezone.now())
def get_context_data(self, **kwargs): # передача формы
context = super(DetailView, self).get_context_data(**kwargs)
context['comment_form'] = CommentForm#(initial={'post':
self.object.pk})
return context
class MyFormView(generic.FormView):
template_name = 'bankofideas/detail.html'
form_class = CommentForm
success_url = 'bankofideas:home'
def get_success_url(self):
post = self.request.POST['post']
Comment.objects.create()
return '/'
def form_valid(self, form):
return super().form_valid(form)
#models.py
class Idea(models.Model):
main_text = models.CharField(max_length=9001, default='')
likes = models.IntegerField(default=0)
pub_date = models.DateTimeField('date published',
default=timezone.now)
def __str__(self):
return self.main_text
def save(self, *args, **kwargs):
''' On save, update timestamps '''
if not self.id:
self.pub_date = timezone.now()
#self.modified = timezone.now()
return super(Idea, self).save(*args, **kwargs)
class Comment(models.Model):
post = models.ForeignKey(Idea, on_delete=models.PROTECT) #
related_name='comments',
user = models.CharField(max_length=250)
body = models.TextField(default=' ')
created = models.DateTimeField(default=timezone.now)
def __str__(self):
return self.body
def get_absolute_url(self):
return reverse('post_detail', args=[self.post.pk])
#forms.py
from .models import Idea, Comment
from django import forms
class IdeaForm(forms.ModelForm):
class Meta:
model = Idea
fields = ('main_text',)
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
exclude = ['post', 'datetime']
#detail.html
{% extends 'base.html' %}
{% load bootstrap3 %}
{% block body %}
<div class="container">
<p>{{ idea.main_text }} {{ idea.likes }} like(s)</p>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form action="{% url 'bankofideas:vote' idea.id %}" method="post">
{% csrf_token %}
<input type="submit" name="likes" id="idea.id" value="{{ idea.likes }}" />
</form>
{% for comment in idea.comment_set.all %}
<p>{{comment.body}}</p>
{% empty %}
<p>No comments</p>
{% endfor %}
<form action="{% url "bankofideas:myform" %}" method="post">
{% csrf_token %}
{{ myform. }}
<input type='submit' value="Отправить" class="btn btn-default"/>
</form>
</div>
{% endblock %}
As a result, I have an ability to see post, read all comments, like it, but cannot leave a comment. I tried to rename the form both in view and template, but it didn't work.
The question is: What should i do to bring comment form on the page?