As of today, my UpdateView no longer works. Whenever I select the icon to edit an item I get the following error:
EntryUpdate is missing a QuerySet. Define EntryUpdate.model, EntryUpdate.queryset, or override EntryUpdate.get_queryset().
I have never had to have a QuerySet within my UpdateView before, so I am unsure why it is asking for one now. My understanding of the Generic UpdateView is that the self-query was built in, but I may be wrong.
Any help would be much appreciated.
views.py
class IndexView(generic.ListView):
template_name = 'argent/index.html'
# paginate_by = 10
def get_queryset(self):
return Entry.objects.all()
def get_context_data(self, **kwargs):
ctx = super(IndexView, self).get_context_data(**kwargs)
# TODAY'S ENTRY
ctx['entry_qs'] = Entry.objects.filter(date=today_date)
# CURRENT SAVINGS TOTALS
ctx['savings_qs'] = Savings.objects.filter(id=1)
# MONTHLY TOTALS
# November
ctx['November16_qs'] = MonthYear.objects.filter(month='November')
# December
ctx['December16_qs'] = MonthYear.objects.filter(month='December')
# January
ctx['January17_qs'] = MonthYear.objects.filter(month='January')
# February
ctx['February17_qs'] = MonthYear.objects.filter(month='February')
# March
ctx['March17_qs'] = MonthYear.objects.filter(month='March')
# # April
# ctx['April_qs'] = MonthYear.objects.filter(month='April')
# # May
# ctx['May_qs'] = MonthYear.objects.filter(month='May')
return ctx
class DetailView(generic.DetailView):
model = Entry
template_name = 'argent/detail.html'
#
# def get_context_data(self, **kwargs):
# ctx = super(DetailView, self).get_context_data(**kwargs)
# ctx['savings_qs'] = Savings.objects.filter(id=1)
# return ctx
class EntryCreate(CreateView):
form_class = EntryForm
template_name = 'argent/entry_form.html'
def form_valid(self, form):
if form.save(self):
# total_euros_spent
sum_euros = Entry.objects.aggregate(s=Sum('euros_sum')).get('s')
sum_euros_f = "{0:.2f}".format(sum_euros)
# total_dollars_spent
sum_dollars = Entry.objects.aggregate(s=Sum('dollars_sum')).get('s')
sum_dollars_f = "{0:.2f}".format(sum_dollars)
# total_sum
sum_savings = Entry.objects.aggregate(s=Sum('daily_savings_dollars')).get('s')
sum_format = "{0:.2f}".format(sum_savings)
# total_sum_format
sum_abs_savings = Entry.objects.aggregate(s=Sum('daily_savings_dollars')).get('s')
absolute = abs(sum_abs_savings)
sum_abs = "{0:.2f}".format(absolute)
Savings.objects.filter(id=1).update(total_savings=sum_format, total_savings_display=sum_abs,
total_spent_dollars=sum_dollars_f, total_spent_euros=sum_euros_f)
return super(EntryCreate, self).form_valid(form)
else:
return self
class EntryUpdate(UpdateView):
form_class = EntryForm
template_name = 'argent/entry_form.html'
def form_valid(self, form):
if form.save(self):
# total_euros_spent
sum_euros = Entry.objects.aggregate(s=Sum('euros_sum')).get('s')
sum_euros_f = "{0:.2f}".format(sum_euros)
# total_dollars_spent
sum_dollars = Entry.objects.aggregate(s=Sum('dollars_sum')).get('s')
sum_dollars_f = "{0:.2f}".format(sum_dollars)
# total_sum
sum_savings = Entry.objects.aggregate(s=Sum('daily_savings_dollars')).get('s')
sum_format = "{0:.2f}".format(sum_savings)
# total_sum_format
sum_abs_savings = Entry.objects.aggregate(s=Sum('daily_savings_dollars')).get('s')
absolute = abs(sum_abs_savings)
sum_abs = "{0:.2f}".format(absolute)
Savings.objects.filter(id=1).update(total_savings=sum_format, total_savings_display=sum_abs, total_spent_dollars=sum_dollars_f, total_spent_euros=sum_euros_f)
return super(EntryUpdate, self).form_valid(form)
else:
return self
urs.py
urlpatterns = [
url(r'^$', views.IndexView.as_view(), name='index'),
url(r'entry/detail/(?P<pk>[0-9]+)/$', views.DetailView.as_view(), name='detail'),
url(r'entry/add/$', views.EntryCreate.as_view(), name='entry-add'),
url(r'entry/update/(?P<pk>[0-9]+)/$', views.EntryUpdate.as_view(), name='entry-update'),
]
template
{% if object_list %}
{% for Entry in object_list %}
<div class="col-md-3 col-sm-4 col-xs-6">
<div class="thumbnail" style="background: #ebebeb" >
<h3 align="center" style="font-weight: bold; color: #337ab7;">{{ Entry.date }}</h3>
<div class="caption">
<h4 align="center" style="color: #FF5A09">€{{ Entry.euros_sum }}
<!-- View Details -->
<a href="{% url 'argent:detail' Entry.id %}"><button type="button" class="btn btn-link btn-lg">
<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span>
</button></a>
<!-- Update -->
<a href="{% url 'argent:entry-update' Entry.id %}"><button type="button" class="btn btn-link btn-lg" style="padding: 0">
<span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
</button>
</a>
</h4>
</div>
</div>
</div>
{% endfor %}
{% endif %}
SOLUTION:
Fixed it. It turns out I accidentally deleted model=Entry from the view. Once I added it back, it started to work again.
class EntryUpdate(UpdateView):
model = Entry
form_class = EntryForm
template_name = 'argent/entry_form.html'
def form_valid(self, form):
....
Related
models.py
from django.db import models
from django.utils.translation import gettext_lazy as _
# Create your models here.
# from django.utils.encoding import smart_unicode
from enum import Enum
from django.contrib.auth.models import AbstractUser
from django import forms
class CommentForm(forms.Form):
name = forms.CharField()
comment = forms.CharField(widget=forms.Textarea)
class Username(AbstractUser):
firstName = models.CharField(max_length=200, null=True)
lastName = models.CharField(max_length=200, null=True)
email = models.EmailField(unique=True, default=None, null=True)
password = models.CharField(max_length=32)
REQUIRED_FEILDS = []
def __str__(self):
return self.username
class Option(models.TextChoices):
OPTION1 = 'OPTION1', _('OPTION1')
OPTION2 = 'OPTION2', _('OPTION2')
OPTION3 = 'OPTION3', _('OPTION3')
OPTION4 = 'OPTION4', _('OPTION4')
class Question(models.Model):
# id = models.AutoField(primary_key=True)
question=models.CharField(max_length=600)
option1=models.CharField(max_length=200, default=None)
option2=models.CharField(max_length=200, default=None)
option3=models.CharField(max_length=200, default=None)
option4=models.CharField(max_length=200, default=None)
difficulty=models.PositiveIntegerField()
exam=models.BooleanField()
key=models.CharField(max_length=100)
correct_answer = models.CharField(max_length=7,choices=Option.choices,default=None,)
def __str__(self):
return str(self.id)
class Answer(models.Model):
username=models.ForeignKey(Username,max_length=200, null=True,on_delete=models.CASCADE)
question_id = models.ForeignKey(Question, on_delete=models.CASCADE)
answer = models.CharField(
max_length=7,
choices=Option.choices,
default=None,
)
surety=models.PositiveIntegerField( null=True)
difficulty=models.PositiveIntegerField( null=True)
def __str__(self):
return self.answer
views.py
from django.shortcuts import render, redirect
from .models import *
from django.http import JsonResponse
from django.contrib.auth import authenticate, login, logout
# from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse
from django.contrib.auth import get_user_model
from django.template import loader
from django.views.generic import ListView
from django.core.paginator import Paginator
from ada.models import Question
from django.db.models.functions import Lower
from django import forms
# class TestScreen(ListView):
# paginate_by = 6
# model = Question
# from .forms import CommentForm
# def post_comment(request, username_id):
# if request.method == 'POST':
# form = CommentForm(request.POST)
# if form.is_valid():
# data = form.cleaned_data
# blog = get_object_or_404(Practise, id=username_id)
# Comment.objects.create(
# question_id = question_id)
def viewtemplate(request, username):
student = Answer.objects.get(id = username)
form = templateform(request.POST)
if request.method == "POST":
if form.is_valid():
form = form.save(commit=False)
form.username = student
form.save()
return redirect('index')
else:
form = templateform()
return render(request, 'practise.html', {'form': form})
def index(request):
if request.user.is_authenticated:
return render(request,'index.html')
# #login_required(login_url = '/login')
# def quiz(request, myid):
# quiz = Quiz.objects.get(id=myid)
# return render(request, "quiz.html", {'quiz':quiz})
def Signup(request):
if request.user.is_authenticated:
return redirect('/')
if request.method=="POST":
username = request.POST['username']
email = request.POST['email']
first_name=request.POST['first_name']
last_name=request.POST['last_name']
password = request.POST['password1']
confirm_password = request.POST['password2']
if password != confirm_password:
return redirect('/register')
User = get_user_model()
user = User.objects.create_user(username, email, password)
user.first_name = first_name
user.last_name = last_name
user.save()
return render(request, 'login.html')
return render(request, "signup.html")
# def testscreen(request):
# return render(request, 'questions.html')
# def quizData (request):
# context = {'quiz' : quizData }
# return render (request, testscreen, context)
def Login(request):
if request.user.is_authenticated:
return redirect('/')
if request.method=="POST":
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
login(request, user)
return redirect("/")
else:
return render(request, "login.html")
return render(request, "login.html")
def Practise(request):
questions_list = Question.objects.get_queryset().order_by('id')
paginator = Paginator(questions_list, 1)
page_number = request.GET.get('page')
page_obj = paginator.get_page(page_number)
# if request.user.is_authenticated:
# return render(request, 'practise.html',)
if request.method=="POST":
answer = request.POST.get('html')
print(request.POST)
# difficulty = request.POST['difficulty']
# surety=request.POST['surety']
# answer.save()
return render(request, 'practise.html' ,{'page_obj': page_obj})
def Profile(request):
if request.user.is_authenticated:
return render(request, 'users-profile.html')
def FAQ(request):
if request.user.is_authenticated:
return render(request, 'pages-faq.html')
def Contact(request):
if request.user.is_authenticated:
return render(request, 'pages-contact.html')
def Logout(request):
logout(request)
return redirect(request,'login.html')
def question(request):
# questions_list = Question.objects.all().order_by(Lower("key"))
questions_list = Question.objects.get_queryset().values("key").annotate(n=models.Count("pk"))
practise_questions = Question.objects.filter(key= 'questions_list').all()
print(practise_questions)
# a = Question.objects.filter(key='C.1.1')
# print(a.count())
if request.user.is_authenticated:
return render(request, 'questions.html', {'questions_list': questions_list})
def practise(request):
print(request)
questions_list = Question.objects.get_queryset().order_by('id')
# answers_list = Answer.objects.all()
# print(answers_list)
paginator = Paginator(questions_list, 1)
page_number = request.POST.get('page_no')
page_obj = paginator.get_page(page_number)
print(request.GET)
# if request.user.is_authenticated:
# return render(request, "try.html",{'page_obj': page_obj})
if request.method=="POST":
answer = request.POST.get('answer')
difficulty = request.POST.get('myRange')
surety=request.POST.get('surety')
# Answer = ()
# answer_submit = Answer(answer='answer')
# answer_submit.save()
# answer_submit.answer = answer
# answer_submit.difficulty = difficulty
# answer_submit.surety = surety
# answer_submit.save()
# print(request.POST)
# User_ans = get_user_model()
# user = User_ans.objects.create_user(answer, difficulty, surety)
#user.answer = answer
# user.difficulty = difficulty
#user.save()
return render(request, "try.html", {'page_obj': page_obj})
try.html
{% extends 'base.html' %}
{% block title %}Practise Test {% endblock %}
{% block css %}
<style>
.head1 {
color: bisque;
font-size: 2rem;
font-weight: bold;
height: 50px;
font-family: 'Lucida Sans';
}
.head2 {
color: cyan;
font-size: 2rem;
font-weight: bold;
font-family: 'Lucida Sans';
}
</style>
{% endblock %}
{% block body %}
<div class="btn-wrapper">
<div class="row py-5 p-4 bg-white rounded shadow-sm">
<div class="col-lg-6">
<div class="bg-light rounded-pill px-4 py-3 text-uppercase font-weight-bold"
style="color:black;font-weight:bold">Practise Test</div>
<br>
{% for question in page_obj %}
<form class="row g-4" method="POST" action="/try/">{% csrf_token %}
<div class="col-md-12">
<li class="list-group-item active font-weight-bold">{{ question.id }}. {{ question.question }}</legend></li>
<label for="{{ question.option1 }}" class="form-label" style="font-weight: bold;"><i>
{{ question.option1 }}</i></label>
<input type="radio" style="text-align: center;"value="{{ question.option1 }}"
class="form-control" id="html1" name="option">
</div>
<div class="col-md-12">
<label for="{{ question.option2 }}" class="form-label" style="font-weight: bold;"><i>
{{ question.option2 }}</i></label>
<input type="radio" style="text-align: center;" value="{{ question.option2 }}"
class="form-control" id="html2" name="option">
</div>
<div class="col-md-12">
<label for="{{ question.option3 }}" class="form-label" style="font-weight: bold;"><i>
{{ question.option3 }}</i></label>
<input type="radio" style="text-align: center;"value="{{ question.option3 }}"
class="form-control" id="html3" name="option">
</div>
<label for="{{ question.option4 }}" class="form-label" style="font-weight: bold;"><i>
{{ question.option4 }}</i></label>
<input type="radio" style="text-align: center;"value="{{ question.option4 }}"
class="form-control" id="html4" name="option">
</div>
{% endfor %}
<div class="slid">
<h3>
<b> <i> Difficulty </i> </b>
</h3>
<p>Slide according to difficulty of question:</p>
<div class="slidecontainer">
<input
type="range"
min="1"
max="5"
value="value"
class="slider"
id="myRange"
name="difficulty_slider"
/>
<p>Value: <span id="demo"></span></p>
</div>
</div>
<script>
var slider = document.getElementById("myRange");
var output = document.getElementById("demo");
output.innerHTML = slider.value;
slider.oninput = function () {
output.innerHTML = this.value;
};
</script>
<h3>Surety: </h3>
<div class="slidecontainer">
<input
type="range"
min="1"
max="5"
value="value"
class="slider"
id="justRange"
name="surety_slider"
/>
<p>Value: <span id="realDemo"></span></p>
<script>
var slider = document.getElementById("myRange");
var output = document.getElementById("demo");
output.innerHTML = slider.value;
slider.oninput = function () {
output.innerHTML = this.value;
};
var slider = document.getElementById("justRange");
var display = document.getElementById("realDemo");
display.innerHTML = slider.value;
slider.oninput = function () {
display.innerHTML = this.value;
};
</script>
{% if page_obj.has_previous %}
<button method="post" type="submit" class="action-btn checkRequired Submit" name="action" value="Submit"> previous</button>
<input type="hidden" name="page_no" value="{{ page_obj.previous_page_number }}">
{% endif %}
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}
{% if page_obj.has_next %}
<button method="post" type="submit" class="action-btn checkRequired Submit" name="action" value="Submit"> next</button>
<input type="hidden" name="page_no" value="{{ page_obj.next_page_number }}">
{% endif %}
<!-- <button type="submit" class="btn btn-primary">Submit</button> -->
</form>
<br>
</div>
</div>
</div>
{% endblock %}
I have attached the necessary views, models and html files for references. Also,
In html page there are radio buttons inside of form, where clicking Submit button has to save all selected radio buttons into the database. Is there any way to do that? Any solution would be of lot more help.
in views.py you can use:
# If not using required attribute in HTML
seleted_option = request.POST.get('option')
# If using required it is suggested to use
seleted_option = request.POST['option']
i've added to my Blog post comments now the problem is that i'm trying to create remove function for that and i have one but now eve uset thak is logged in can remove all the comments how can i fix this that user can delete only their own comments??
the funnyiest thing is that i have this function on my posts and it wokres and if i'm trying to do the same on my comments then i've get 404 error. Ive tried a few different ways but nothing worked You are my only hope:)
views.py
from django.shortcuts import render, get_object_or_404, redirect
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from django.contrib.auth.models import User
from .models import Post, Comment
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from .forms import CommentForm
from django.contrib.auth.decorators import login_required
# Create your views here.
def home(request):
context = {
'posts': Post.objects.all()
}
return render(request, 'blog/home.html', context)
class PostListView(ListView):
model = Post
template_name = 'blog/home.html'
context_object_name = 'posts'
ordering = ['-date_posted']
paginate_by = 5
class UserPostListView(ListView):
model = Post
template_name = 'blog/user_posts.html'
context_object_name = 'posts'
ordering = ['-date_posted']
paginate_by = 5
def get_queryset(self):
user = get_object_or_404(User, username=self.kwargs.get('username'))
return Post.objects.filter(author=user).order_by('-date_posted')
class PostDetailView(DetailView):
model = Post
class PostCreateView(LoginRequiredMixin, CreateView):
model = Post
fields = ['title', 'content']
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
class PostUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
model = Post
fields = ['title', 'content']
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
def test_func(self):
post = self.get_object()
if self.request.user == post.author:
return True
return False
class PostDeleteView(LoginRequiredMixin, UserPassesTestMixin, DeleteView):
model = Post
success_url = '/'
def test_func(self):
post = self.get_object()
if self.request.user == post.author:
return True
return False
def about(request):
return render(request, 'blog/about.html', {'title': 'About'})
#login_required
def add_comment_to_post(request, pk):
post = get_object_or_404(Post, pk=pk)
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.author = request.user
comment.post = post
comment.save()
return redirect('post-detail', pk=post.pk)
else:
form = CommentForm()
return render(request, 'blog/add_comment_to_post.html', {'form': form})
#login_required
def comment_remove(request, pk):
comment = get_object_or_404(Comment, pk=pk)
comment.delete()
return redirect('post-detail', pk=comment.post.pk)
Models.py
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
from django.urls import reverse
# Create your models here.
class Post(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post-detail', kwargs={'pk': self.pk})
class Comment(models.Model):
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')
author = models.CharField(max_length=30)
text = models.TextField()
created_on = models.DateTimeField(default=timezone.now)
active = models.BooleanField(default=False)
class Meta:
ordering = ['-created_on']
def approve(self):
self.approved_comment = True
self.save()
def __str__(self):
return self.text
post_detail
{% extends "blog/base.html" %}
{% block content %}
<article class="media content-section">
<img class="rounded-circle article-img" src="{{post.author.profile.image.url}}">
<div class="media-body">
<div class="article-metadata">
<a class="mr-2" href="{% url 'user_posts' object.author.username %}">{{ object.author }}</a>
<small class="text-muted">{{ object.date_posted|date:"d F, Y" }}</small>
{% if object.author == user %}
<div>
<a class="btn btn-secondary btn-sm mt-1 mb-1" href="{% url 'post-update' object.id %}">Update</a>
<a class="btn btn-danger btn-sm mt-1 mb-1" href="{% url 'post-delete' object.id %}">Delete</a>
</div>
{% endif %}
</div>
<h2 class="article-title">{{ object.title }}</h2>
<p class="article-content">{{ object.content }}</p>
</div>
</article>
<hr>
<a class="btn btn-default" href="{% url 'add_comment_to_post' pk=post.pk %}">Add comment</a>
{% for comment in post.comments.all %}
{% if user.is_authenticated or comment.approved_comment %}
<div class="comment">
<div class="date">
<a class="btn btn-default" href="{% url 'comment_remove' pk=comment.pk %}">remove</a>
</div>
<strong>{{ comment.author }}</strong> {{ comment.created_on|date:"d F, Y G:i" }}
<p>{{ comment.text|linebreaks }}</p>
</div>
{% endif %}
{% empty %}
<p>No comments here yet :(</p>
{% endfor %}
{% endblock content %}
Firstly make author in Comment model Foreign Key(User). Then in views check this condition:
if comment.author == request.user:
comment.delete()
I am writing and Update View for a model that I have created. The model is a Product Backlog Item. The UpdateView is unable to find a reverse match for my view.
The NoReverseMatch error is saying that Django cannot find a matching url pattern.
My code as below:
UpdatePBI View
class updatePBI(LoginRequiredMixin, UpdateView):
pk_url_kwarg = 'pbipk'
kwargs={'pk_url_kwarg': 'pbipk'}
model = PBI
fields = ['priority', 'summary', 'story_points', 'effort_hours']
login_url = '/accounts/login'
redirect_field_name = '/home'
template_name = 'backtrack/PBIdetail.html'
def dispatch(self, request, *args, **kwargs):
print(kwargs)
return super().dispatch(request, *args, **kwargs)
def get_success_url(self):
return "{}?all=0".format(reverse('pb', kwargs={'pk': self.kwargs['pk']}))
def get_object(self, queryset=None):
obj = get_object_or_404(self.model,pk=self.kwargs['pbipk'])
return obj
def form_valid(self, form):
PBIList = getPBIfromProj(self.kwargs['pk'], '0')
remove = []
priorityData = form.cleaned_data['priority']
if int(priorityData) < self.object.priority:
# Remove all PBI with priority higher than post data priority
# and lesser or equal than current PBI priority
for PBIObj in PBIList:
if PBIObj.priority < int(priorityData) or PBIObj.priority >= self.object.priority:
remove.append(PBIObj.priority)
PBIList = [
PBIObj for PBIObj in PBIList if PBIObj.priority not in remove]
# Increase each objects priority by one
for PBIObj in PBIList:
PBIObj.priority += 1
PBIObj.save()
else:
# Remove all PBI with priority higher than post PBI priority
# and lesser than and equal to Post data priority
for PBIObj in PBIList:
if PBIObj.priority <= self.object.priority or PBIObj.priority > int(priorityData):
remove.append(PBIObj.priority)
PBIList = [
PBIObj for PBIObj in PBIList if PBIObj.priority not in remove]
# Decrease each objects priority by one
for PBIObj in PBIList:
PBIObj.priority -= 1
PBIObj.save()
return super().form_valid(form)
model.py
from django.urls import reverse
# Create your models here.
class PBI(models.Model):
status = models.CharField(max_length=1,
choices=[("N", "Not Done"), ("P", "In Progress"), ("D", "Done")], default="N")
story_points = models.FloatField()
effort_hours = models.FloatField()
summary = models.TextField(default = None)
priority = models.IntegerField(default=0)
Project = models.ForeignKey('Project', on_delete=models.CASCADE, related_name='pbi')
def __str__(self):
return self.summary
class Meta:
db_table = "PBI"
verbose_name = 'PBI'
verbose_name_plural = 'PBIs'
class Project(models.Model):
name = models.CharField(max_length=256)
def __str__(self):
return self.name
class Meta:
db_table = "Project"
urls.py
from django.conf.urls import url
from backtrack import views
from django.shortcuts import redirect
urlpatterns = [
path('', lambda x: redirect('1/'),name='home'),
path('<int:pk>/', views.HomeView.as_view(),name = 'home-project'),
path('<int:pk>/pb/', views.ProductBacklogView.as_view(),name='pb'),
path('<int:pk>/pb/add/', views.AddPBI.as_view(),name='add'),
path('<int:pk>/pb/<int:pbipk>/update', views.updatePBI.as_view(),name='detail'),
path('<int:pk>/pb/<int:pbipk>/delete', views.DeletePBI.as_view(),name='delete')
]
Product Backlog Page
{% block content %}
<h1 class="page-header"><i class="fa fa-file"></i> Product BackLog</h1>
<div class="row placeholders"></div>
{% if data|length == 0 %}
<h4>There are no PBIs</h4>
{% endif %}
<h2 class="sub-header">
<div class="dropdown">
<button class="btn btn-light dropdown-toggle pull-left" type="button" data-toggle="dropdown" style="margin-bottom: 10px;">Filter By
<span class="caret"></span></button>
<ul class="dropdown-menu">
<li>Priority</li>
<li>Story Points</li>
<li>Effort Hours</li>
</ul>
<div class="btn-group btn-toggle">
<button class="btn btn-xs btn-primary active toggle">NOT DONE</button>
<button class="btn btn-xs btn-default toggle">ALL</button>
</div>
<button type="button" class="btn btn-light" style="margin-bottom: 10px;"><i class="fa fa-plus" id="A"></i>ADD</button>
<button type="button" class="btn btn-light" style="margin-bottom: 10px;"><i class="fa fa-times" id="A"></i>DELETE</button>
</div>
</h2>
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th> </th>
<th>Priority</th>
<th>Summary</th>
<th>Status</th>
<th>Story Points</th>
<th>Cumulative Story Points</th>
<th>Effort hours</th>
<th>Cumulative Effort hours</th>
</tr>
</thead>
<tbody>
{% for PBI in data %}
<tr>
<td><input type="checkbox"></td>
<td>
{% if PBI.status == "N" %}
{{PBI.priority}}
{% else %}
--
{% endif %}
</td>
<td><a style="text-decoration: none; color: cornflowerblue;" href={% url 'detail' pk=1 pbipk=PBI.id %}>{{PBI.summary}}</a></td>
<td>
{% if PBI.status == "N" %}
Not Done
{% elif PBI.status == "P" %}
In Progress
{% else %}
Done
{% endif %}
</td>
<td>{{PBI.story_points}}</td>
<td>{{PBI.sum_story_points}}</td>
<td>{{PBI.effort_hours}}</td>
<td>{{PBI.sum_effort_hours}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<script>
$.urlParam = function (name) {
var results = new RegExp('[\?&]' + name + '=([^&#]*)')
.exec(window.location.search);
return (results !== null) ? results[1] || 0 : false;
}
$(document).ready(function () {
if($.urlParam('all') == '1'){
$(this).find('.toggle').toggleClass('active');
if ($(this).find('.btn-primary').length>0) {
$(this).find('.toggle').toggleClass('btn-primary');
}
}
var getUrl = window.location;
var baseUrl = getUrl.protocol + "//" + getUrl.host + getUrl.pathname;
$('.btn-toggle').click(function(){
console.log($.urlParam('all') == '0')
if($.urlParam('all') == '0')
window.location.replace(baseUrl + "?all=1");
else
window.location.replace(baseUrl + "?all=0");
})
});
</script>
{% endblock content %}
I am getting this error
NoReverseMatch at /home/1/pb/50/update
Reverse for 'detail' with keyword arguments '{'pk': 1, 'pbipk': ''}' not found. 1 pattern(s) tried: ['home/(?P<pk>[0-9]+)/pb/(?P<pbipk>[0-9]+)/update$']
Update
I have found that the error is because I am setting the form action with the PBI.id but the Update view is not passing a PBI to my template. How do I fix this?
Okay. I found what I was doing wrong. I have to override the get_context_data() function of the template view mixin and pass the PBI in the context after calling super().get_context_data(form).
I am trying use the django generic view for CRUD, but the DeleteView result in error 405, following the guide official Django https://docs.djangoproject.com/en/2.1/ref/class-based-views/generic-editing/ , I don't understand where is my error, so that's my code:
views.py
from django.urls import reverse
from django.views.generic import (
CreateView,
DetailView,
ListView,
UpdateView,
ListView,
DeleteView
)
from .forms import ContatoModelForm
from .models import Contato
class ContatoCreateView(CreateView):
template_name = 'contato/contato_create.html'
form_class = ContatoModelForm
model = Contato
class ContatoListView(ListView):
template_name = 'contato/contato_list.html'
model = Contato
class ContatoDetailView(DetailView):
template_name = 'contato/contato_detail.html'
model = Contato
class ContatoUpdateView(UpdateView):
template_name = 'contato/contato_create.html'
form_class = ContatoModelForm
model = Contato
class ContatoDeleteView(DeleteView):
template_name = 'contato/contato_delete.html'
model = Contato
def get_success_url(self):
return reverse('contato:contato-list')
urls.py
from django.urls import path
from .views import (
ContatoCreateView,
ContatoDeleteView,
ContatoDetailView,
ContatoListView,
ContatoUpdateView,
)
app_name = 'contato'
urlpatterns = [
path('', ContatoListView.as_view(), name='contato-list'),
path('create/', ContatoCreateView.as_view(), name='contato-create'),
path('<int:pk>/', ContatoDetailView.as_view(), name='contato-detail'),
path('<int:pk>/update/', ContatoUpdateView.as_view(), name='contato-update'),
path('<int:pk>/delete/', ContatoDeleteView.as_view(), name='contato-delete'),
]
contato_delete.html
<form action='.' method='post'>{% csrf_token %}
<dialog class="mdl-dialog">
<h6>Deseja excluir {{ object.nome }}?</h6>
<div class="mdl-dialog__actions">
<input type="submit" class="mdl-button mdl-js-button mdl-button--accent" value="Excluir">
<button type="button" class="mdl-button close">Cancelar</button>
</div>
</dialog>
</form>
contato_detail.html
{% extends 'base.html' %}
{% load staticfiles %}
{% block content %}
<div class="mdl-card__title">
<h2 class="mdl-card__title-text">{{ object.nome }}</h2>
</div>
<div class="mdl-layout-spacer"></div>
<a id="show-dialog" class="mdl-button mdl-js-button mdl-button--icon">
<i class="material-icons">delete</i>
</a>
{% include "contato/contato_delete.html" %}
<script type="text/javascript" src="{% static 'js/dialog.js' %}"></script>
<div class="mdl-card__actions mdl-card--border">
<ul class="demo-list-icon mdl-list">
<li class="mdl-list__item">
<span class="mdl-list__item-primary-content">
<i class="material-icons mdl-list__item-icon">call</i>
{{ object.celular }}
</span>
</li>
<li class="mdl-list__item">
<span class="mdl-list__item-primary-content">
<i class="material-icons mdl-list__item-icon">email</i>
{{ object.email }}
</span>
</li>
<li class="mdl-list__item">
<span class="mdl-list__item-primary-content">
<i class="material-icons mdl-list__item-icon">business</i>
{{ object.cargo }} na {{ object.empresa}}
</span>
</li>
</ul>
</div>
<a href="{% url 'contato:contato-update' object.id %}" id="fab" class="mdl-button mdl-js-button mdl-button--fab mdl-button--primary">
<i class="material-icons">create</i>
</a>
{% endblock %}
contato_list.html
{% extends "base.html" %}
{% block content %}
<style>
.demo-list-three {
width: 800px;
margin-left: 30px;
}
#fab {
position: fixed;
display: block;
right: 0;
bottom: 0;
margin-right: 40px;
margin-bottom: 40px;
z-index: 900;
}
</style>
<form method='GET' action=''>
</form>
{% for obj in object_list %}
<ul class="demo-list-three mdl-list">
<li class="mdl-list__item mdl-list__item--three-line">
<span class="mdl-list__item-primary-content">
<i class="material-icons mdl-list__item-avatar">person</i>
<a href='{{ obj.get_absolute_url }}'><span>{{ obj.nome }}</span>
</a>
<span class="mdl-list__item-text-body">
{{ obj.celular }} <br>
{{ obj.email }}
</span>
</span>
<a href="{{ obj.get_absolute_url }}" class="mdl-button mdl-js-button mdl-button--primary">
DETALHES
</a>
</li>
</ul>
{% endfor %}
<a href="{% url 'contato:contato-create' %}" id="fab" class="mdl-button mdl-js-button mdl-button--fab mdl-button--primary">
<i class="material-icons">person_add</i>
</a>
{% endblock content %}
Simplify your code:
class ContatoCreateView(CreateView):
template_name = 'contato/contato_create.html'
form_class = ContatoModelForm
model = Contato # Tell the CBV what object you will create
#** This doesn't make any sense, you are creating a new Contato not retrieving a queryset.
# queryset = Contato.objects.all()
#** Let the ModelForm handle the validation
# def form_valid(self, form):
# print(form.cleaned_data)
# return super().form_valid(form)
class ContatoListView(ListView):
template_name = 'contato/contato_list.html'
model = Contato # This does the work for you
#** You don't need to do this, unless you want a _specific_ queryset filterd
# queryset = Contato.objects.all()
class ContatoDetailView(DetailView):
template_name = 'contato/contato_detail.html'
model = Contato # again, just define the model
#** let CBV handle this logic
# def get_object(self):
# id_ = self.kwargs.get("id")
# return get_object_or_404(Contato, id=id_)
class ContatoUpdateView(UpdateView):
template_name = 'contato/contato_create.html'
form_class = ContatoModelForm
model = Contato # again, just define the model
#** let CBV handle this logic
# def get_object(self):
# id_ = self.kwargs.get("id")
# return get_object_or_404(Contato, id=id_)
#** Let the ModelForm handle the validation
#def form_valid(self, form):
# print(form.cleaned_data)
# return super().form_valid(form)
class ContatoDeleteView(DeleteView):
template_name = 'contato/contato_delete.html'
model = Contato # the class object you want to delete
#** let CBV handle this logic
# def get_object(self):
# id_ = self.kwargs.get("id")
# return get_object_or_404(Contato, id=id_)
def get_success_url(self):
return reverse('contato:contato-list')
You need to set the action on the form to match the route (url) for deleting a contato object.
Basically change the open tag of the <form> to:
<form action='{{ id }}/delete' method='post'>
and pass an id to the view through the context, like this:
class ContatoDetailView(DetailView):
model = Contato
def get(self, request, *args, **kwargs):
self.object = self.get_object()
context = self.get_context_data(object=self.object)
context['id'] = self.object.id
return self.render_to_response(context)
As an additional recommendation, I'd look into making your routes more RESTful. See this gist for info: https://gist.github.com/alexpchin/09939db6f81d654af06b. Something to note though is that HTML5 forms do not have support for delete (or put) requests. To make a delete request with a form you'd have to submit the request manually on submit using javascript.
Hi: I am trying to build a staff directory where user can filter view by department. I have the department list displayed in a dropdown button but cannot figure out how to properly pass the user selection to the listview in the views.py Please see the code below.
models.py
class Department(models.Model):
department = models.CharField(max_length = 20, unique = True)
def __str__(self):
return self.department
class EmployeeList(models.Model):
department = models.ForeignKey(Department, on_delete = models.SET_NULL, null = True, blank = True)
views.py
class EmployeeOutput(ListView):
model = models.EmployeeList
context_object_name = 'employee_list'
template_name = 'employee_list.html'
def get_context_data(self, **kwargs):
context = super(EmployeeOutput, self).get_context_data(**kwargs)
context['filter_list'] = models.Department.objects.values_list('department', flat = True)
return context
class FilterDepartment(ListView):
model = models.EmployeeList
context_object_name = 'employee_list'
template_name = 'employee_list.html'
def get_context_data(self, **kwargs):
context = super(FilterDepartment, self).get_context_data(**kwargs)
context['filter_list'] = models.Department.objects.values_list('department', flat = True)
context['department_filter'] = models.EmployeeList.objects.filter(department_id = 3)
return context
employee_list.html
<table class = 'table table-striped table-hover' id = 'my_table'>
<thead>
<tr>
<th><button type="button" class = ' btn btn-info' onclick = 'sortTable(0)'>Name</button></th>
<th><button type="button" class = ' btn btn-info' onclick = 'sortTableNumbers(1)'>Phone Ex</button></th>
<th><button type="button" class = ' btn btn-info' onclick = 'sortTable(2)'>Email</button></th>
<th>
<div class="btn-group dropright">
<button class="btn btn-success dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Department
</button>
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
<a class="dropdown-item" onclick = 'sortTable(3)'><b>Sort Department</b></a>
<h6 class="dropdown-header">Filter by:</h6>
<div class="dropdown-divider"></div>
{% for running in filter_list%}
<a class="dropdown-item" href="{% url 'employee:department_filter' %}"><b>{{running}}</b></a>
{% endfor %}
</div>
</div>
</th>
<th><button type="button" class = ' btn btn-info' onclick = 'sortTable(4)'>Remote Access</button></th>
<th>Cell Phone</th>
</tr>
</thead>
<tbody>
{% if department_filter %}
{% for EL in department_filter %}
<tr>
<td>{{EL.first_name}} {{EL.last_name}}</td>
<td>{{EL.phone_ex}}</td>
<td> {{EL.email}}</td>
<td>{{EL.department}}</td>
<td>{{EL.remote_access}}</td>
<td>{{EL.cell}}</td>
</tr>
{% endfor %}
{% else %}
{% for EL in employee_list %}
<tr>
<td>{{EL.first_name}} {{EL.last_name}}</td>
<td>{{EL.phone_ex}}</td>
<td> {{EL.email}}</td>
<td>{{EL.department}}</td>
<td>{{EL.remote_access}}</td>
<td>{{EL.cell}}</td>
</tr>
{% endfor %}
{% endif %}
</tbody>
</table>
I can properly display the entire staff with 'employee_list'. I can show a list of current department in the dropdown button with 'filter_list'. When user clicked on any of the selection, it always shows the same result since 'department_list' is hard coded to department_id = 3. What I need to find out is how to pass in the ID with href as
{% url 'employee:department_filter' dept=running.id %}
with url.py
path('filter/<int:dept>', views.FilterDepartment.as_view(), name = 'department_filter'),
I am struggling to find out how to pass 'dept' into the 'FilterDepartment' view. Maybe there is a better way to do this or I am just missing the last piece to make this happen. Any suggestion is welcome. Thank you
suggestion by #dirkgroten
employee_list.html
<a class="dropdown-item" href="{% url 'employee:department_filter' dept=running.id %}"><b>{{running}}</b></a>
{% if object_list %}
{% for EL in object_list %}
<tr>
<td>{{EL.first_name}} {{EL.last_name}}</td>
<td>{{EL.phone_ex}}</td>
<td> {{EL.email}}</td>
<td>{{EL.department}}</td>
<td>{{EL.remote_access}}</td>
<td>{{EL.cell}}</td>
</tr>
{% endfor %}
urls.py
path('filter/<int:dept>/', views.FilterDepartment.as_view(), name = 'department_filter'),
views.py
class FilterDepartment(ListView):
model = models.EmployeeList
context_object_name = 'employee_list'
template_name = 'employee_list.html'
def get_context_data(self, **kwargs):
context = super(FilterDepartment, self).get_context_data(**kwargs)
context['filter_list'] = models.Department.objects.values_list('department', flat = True)
return context
def get_queryset(self, **kwargs):
return super().get_queryset().filter(department_id=self.kwargs['dept'])
working solution:
employee_list.html
{% for running in filter_list%}
<a class="dropdown-item" href="{% url 'employee:department_filter' running %}"><b>{{running}}</b></a>
{% endfor %}
{% if object_list %}
{% for EL in object_list %}
<tr>
<td>{{EL.first_name}} {{EL.last_name}}</td>
<td>{{EL.phone_ex}}</td>
<td> {{EL.email}}</td>
<td>{{EL.department}}</td>
<td>{{EL.remote_access}}</td>
<td>{{EL.cell}}</td>
</tr>
urls.py
path('filter/<department>/', views.FilterDepartment.as_view(), name = 'department_filter'),
views.py
class FilterDepartment(ListView):
model = models.EmployeeList
context_object_name = 'employee_list'
template_name = 'employee_list.html'
#if missing, it is looking for EmployeeList_list.html
#employee_list.pk used in empllyee_list.html
def get_context_data(self, **kwargs):
context = super(FilterDepartment, self).get_context_data(**kwargs)
context['filter_list'] = models.Department.objects.values_list('department', flat = True)
# context['department_filter'] = models.EmployeeList.objects.filter(department_id = self.kwargs['dept'])
return context
def get_queryset(self):
return super(FilterDepartment, self).get_queryset().filter(department__department=self.kwargs['department'])
Use the ListView's get_queryset() method to filter the list of objects you want to display. This will add object_list to the context in the template. Only use get_context_data() to add additional information to the context.
class FilterDepartment(ListView):
# properties like model and template_name
# context_object_name can be used if you want to call the list something else than 'object_list' in your context
def get_queryset(self):
return super().get_queryset().filter(department_id=self.kwargs['dept'])
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) # this will already include object_list
context['filter_list'] = models.Department.objects.values_list('department', flat = True)
return context
The Django documentation on ListView is quite concise and makes it difficult to really understand which methods to override. A better place to understand Django's generic class based views is here.