python - Django display uploaded multiple images with foreign key - django

I have for example the Post with the id 31 after I upload one or more images are displayed in db as:
id (for example: 1,2,3)
url to image(for example: my-images/image.png)
foreing_id (thats is id to post i.e 31)
But I do not know how to display the image in the template for this post (and others of course)
my model:
class Post(models.Model):
title = models.CharField(max_length=20000)
date = models.DateTimeField(editable=True, null=True)
text = models.TextField(max_length=50000)
is_super = models.IntegerField(default=0)
class Image(models.Model):
foreing = models.ForeignKey(Post)
image = models.ImageField(null=True, blank=True, upload_to='my-images')
view where i upload and display all posts(Here i display):
class IndexView(generic.ListView):
paginate_by = 4
template_name = 'home/index.html'
context_object_name = 'all_posts'
def get_queryset(self):
query = self.request.GET.get('q')
if query:
posts = Post.objects.filter(
Q(text__icontains=query.capitalize()) |
Q(title__icontains=query.capitalize()) |
Q(text__icontains=query.lower()) |
Q(title__icontains=query.lower())
).distinct()
return posts
else:
return Post.objects.filter(date__lte=timezone.now()).order_by('-date')
there i create a new post:
def post_new(request):
ImageFormSet = modelformset_factory(Image, form=ImageForm, extra=3)
if request.method == "POST":
form = PostForm(request.POST, request.FILES or None)
formset = ImageFormSet(request.POST, request.FILES, queryset=Image.objects.none())
if form.is_valid() and formset.is_valid():
post = form.save(commit=False)
post.date = timezone.now()
post.save()
for form in formset.cleaned_data:
image = form['image']
photo = Image(foreing_id=post.id, image=image)
photo.save()
return render(request, 'home/page.html')
else:
form = PostForm()
return render(request, 'home/edit_post.html',
{'form': form, 'error_message': 'something error message'})
else:
form = PostForm()
formset = ImageFormSet(queryset=Image.objects.none())
return render(request, 'home/edit_post.html', {'form': form, 'formset': formset})
And here i need to display images for all this posts:
Here is a image displayed
<div class="profile-img-container" style="text-align: center">
<img class="img" src="images">
<a target="_blank" title="****." href="URL to the uploaded image"><span class="fa fa-expand fa-5x" style="color: darkcyan" aria-hidden="true"></span></a>
full index.html if needed:
<div class="content">
{% for post in all_posts %}
<div class="thumbnail">
<p style="text-align: center">{{ post.title }}</p>
<p class="text" style="text-align: center; height: 40px; overflow: hidden">{{ post.text }}</p>
<p><a type="button" class="btn btn-primary" href="{% url 'klass:detail' post.id %}">More...</a></p>
<div class="profile-img-container" style="text-align: center">
<img class="img" src="/media/**display images**" style="height: 150px">
<a target="_blank" title="****." href="**url to images**"><span class="fa fa-expand fa-5x" style="color: darkcyan" aria-hidden="true"></span></a>
</div>
{% if user.is_authenticated %}
<form method="post" style="text-align: right">
<p>
{% csrf_token %}
<a methods="post" role="button" class="btn btn-info" href="{% url 'klass:favorite' post.id %}">
<i class="fa fa-heart" style="color: red" aria-hidden="true"></i>great! {{ post.is_super }}
</a>
</p>
</form>
<span style="margin-left: 90px">Published: {{ post.date }}</span>
{% else %}
<p style="text-align: right">****<br>
<a role="button" class="btn btn-info disabled" style="text-align: right">
<i class="fa fa-heart" aria-hidden="true"></i>great!</a>
{{ post.date }}
</p>
{% endif %}
</div>
{% endfor %}
EDIT
urls:
from django.conf.urls import url, include
from django.contrib import admin
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^home_page/', include('home.urls', namespace='home')),
url(r'^captcha/', include('captcha.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
settings:
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'home/static'),
]
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
another urls in home app:
from django.conf.urls import url
from . import views
app_name = 'home'
urlpatterns = [
***,
url(r'^$', views.IndexView.as_view(), name='index'),
url(r'^(?P<post_id>[0-9]+)/$', views.comments, name='detail'),
url(r'^(?P<post_id>[0-9]+)/addcomment$', views.addcomment, name='comment'),
url(r'^(?P<post_id>[0-9]+)/favorite/$', views.favorite, name='favorite'),
url(r'^(?P<pk>[0-9]+)/edit/$', views.post_edit, name='edit'),
url(r'^post/new/$', views.post_new, name='post_new'),
url(r'^(?P<post_id>[0-9]+)/delete_album/$', views.delete_post, name='delete_post'),
****,
]

You should loop through post.image_set.all and display each image separately, for example:
{% for image in post.image_set.all %}
<div class="profile-img-container" style="text-align: center">
<img class="img" src="{{ image.image.url }}" style="height: 150px">
<a target="_blank" href="{{ image.image.url }}">
<span class="fa fa-expand fa-5x" style="color: darkcyan" aria-hidden="true"></span>
</a>
</div>
{% endfor %}
A few side notes:
You shouldn't include /media in your image url as it will be automatically appended by Django.
Naming your foreign keys as foreign (also check your spelling) is not recommended for readability reasons. Consider renaming it to use the parent model's name in lowercase (such as post) instead so that it becomes post = models.ForeignKey(Post)
Referencing the foreign key using _id is not recommended. Use the model itself instead, for example: photo = Image(post=post, image=image)

Related

Slug returns Reverse for '' with arguments '('',)' not found. 1 pattern(s)

I am trying to make it so when I view a blog from any particular link on my website, the url displays www.example.com/view-blog/slug. I have got it working for my images and image title. But I cannot get it to work with blog titles.
It keeps returning the error:
Reverse for 'viewblog' with arguments '('',)' not found. 1 pattern(s) tried: ['view\-blog/(?P[-a-zA-Z0-9_]+)/\Z'].
Models.py
class BlogPost(models.Model):
blog_title = models.CharField(max_length=100, null=False, blank=False, default="")
slug = models.SlugField()
blog_article = RichTextUploadingField(null=True, blank=True, default="ici")
blog_image = models.ImageField(null=True, blank=True, upload_to="images", default="default.png")
blog_date = models.DateField(auto_now_add=True)
blog_published = models.BooleanField(default=False)
blog_featured = models.BooleanField(default=False)
def save(self, *args, **kwargs):
self.slug = self.slug or slugify(self.blog_title)
super().save(*args, **kwargs)
def __str__(self):
return self.blog_title
Views.py EDIT: ADDED ALL VIEWS.
def blogPage(request):
posts = BlogPost.objects.filter(blog_date__lte=timezone.now()).order_by('-blog_date')[:4]
context = {'posts': posts}
return render(request, 'blog.html', context)
def blogsPage(request):
posts = BlogPost.objects.filter(blog_date__lte=timezone.now()).order_by('-blog_date')
context = {'posts': posts}
return render(request, 'blogs.html', context)
def searchBlogs(request):
if request.method == "POST":
searched = request.POST.get('searched', False);
searched_blogs = BlogPost.objects.filter(blog_title__icontains=searched)
return render(request, 'search-blogs.html', {'searched': searched, 'searched_blogs': searched_blogs})
def viewBlog(request, slug):
try:
blog = BlogPost.objects.get(slug=slug)
except BlogPost.DoesNotExist:
print("ViewBlog with this slug does not exist")
blog = None
return render(request, 'view-blog.html', {'blog': blog, 'slug': slug})
Urls.py
urlpatterns = [
path('', views.galleryPage, name='gallery'),
path('gallery/', views.galleryPage, name='gallery'),
path('contact/', views.contactPage, name='contact'),
path('blog/', views.blogPage, name='blog'),
path('blogs/', views.blogsPage, name='blogs'),
path('search-blogs/', views.searchBlogs, name='searchblogs'),
path('view-image/<slug:slug>/', views.viewImage, name='viewimage'),
path('view-blog/<slug:slug>/', views.viewBlog, name='viewblog'),
path('thank-you/', views.thankyouPage, name='thankyou'),
path('about-me/', views.aboutmePage, name='aboutme'),
]
**One of my templates I wish to link to viewblog page from ** ( I have tried to replace .id on my urls with .slug but this is what gives me the error.
<body>
<header>{% include 'navbardesktop.html' %}</header>
<div class="blog-container">
<h1 class="all-blog-title" id="all-blog-title" style="text-align: center;">All Blogs</h1>
<br>
<div class="search">
<form class="d-flex" method="POST" action="{% url 'searchblogs' %}">
{% csrf_token %}
<i class="fa fa-search"></i>
<input type="text" class="form-control" placeholder="Search keyword" name="searched">
<button id="search-btn" class="btn btn-secondary">Search</button>
</form>
</div>
<br>
<hr id="blog-hr" style="width:50%; margin-left:25% !important; margin-right:25% !important;" />
<div class="blog-post-container">
<div class="dropdown">
<button class="btn btn-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
Blog List
</button>
<ul class="dropdown-menu" style="background-color: #d6d6d6 ;">
{% for post in posts %} {% if post.blog_published is True %}
<li><a class="dropdown-item" href="{% url 'viewblog' post.id %}">{{post.blog_title}}</a></li>
{% endif %}
{% endfor %}
</ul>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.2.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous"></script>
</div>
<div class="row">
{% for post in posts %} {% if post.blog_published is True %}
<div class="col-md-4" id="blog-col">
<div class="blog-post">
<div class="blog-content">
<img class="blog-img"src="{{post.blog_image.url}}"alt="My image"/>
<h2 class="blog-title">{{post.blog_title}}</h2>
<hr id="blog-hr" style="width: 90%" />
<article class="blog-article">
<p>{{post.blog_article|truncatechars_html:265|safe}}</p>
</article>
Read More...
<p class="blog-date">Posted on: {{post.blog_date}}</p>
</div>
</div>
</div>
{% endif %} {% empty %}
<h3>No Blog Uploads</h3>
{% endfor %}
</div>
</div>
</div>
</div>
the error message
Reverse for 'viewblog' with arguments '('',)' not found.
Remark: what is '('',)' ??
it is simply the print of a python list () with one empty argument ('',). The comma just indicates it is a list. This is placed in '' to structure the error message text '('',)'
so this is the list of arguments that is extracted from your {% url .... %} statement for the error message
always means you have and url tag pointing to "viewblog" that requires an argument (because definded like that in urlpatterns in urls.py ) but actually one of them is null or "" (which is not accepted to reverse a valid url):
urlpatterns = [
...
path('view-blog/<slug:slug>/', views.viewBlog, name='viewblog'),
...
]
---------------------------------
href="{% url 'viewblog' post.id %}"
Now in your case you had originally post.id as parameter (I understood you changed that to post.slug). That means one of the post database entries has a post.slug that is null or ""
to debug just print the value of post.slug into the html page and you will see what is wrong. the "xxx" and "yyy" are there to mark on the output clearly where some content shoult appear (because without it is more difficult to see if there is an empty output).
{% for post in posts %}
xxx {{ post.slug }} xxx <br>
yyy {{ post.blog_title }} xxx <br>
{% endfor %}
Another way of checking post.slug is to go to the admin page ouf your app and inspect the database entries directly
And a third one would be to print the query result for posts in the view:
def blogsPage(request):
posts = BlogPost.objects.filter(blog_date__lte=timezone.now()).order_by('-blog_date')
context = {'posts': posts}
for post in posts:
print(post)
return render(request, 'blogs.html', context)
which will show the content of posts in the console

Page not found (404) error while searching through search page Raised by: blog.views.blogpost

i am unable to search and get 404 error same problem occur in sitemap views for creating static xml file,
it does not return the url for static file and now have this problem with search as it is unable to find search .html gives this Page not found (404) error while searching through search page Raised by: blog.views.blogpost error.
Search_Form
<form method='GET' action="/blog/search/" class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search" name="search" id="search">
<button class="btn btn-outline-success mx-2 my-1 my-sm-0" type="submit">Search</button>
</form>
Search views.py
def search(request):
myposts = Blogpost.objects.all()
query = request.GET['search']
if len(query)>78:
myposts = Blogpost.objects.none()
else:
post_title = Blogpost.objects.filter(Q(title__icontains=query))
posts_content = Blogpost.objects.filter(Q(content__icontains=query))
posts_slug = Blogpost.objects.filter(Q(slug__icontains=query))
myposts = post_title | posts_content | posts_slug
if myposts.count() == 0:
messages.warning(request, "No search results found. Please enter again.")
context = {'myposts': myposts,'query':query}
return render(request, 'blog/search.html', context)
url.py
urlpatterns = [
path('', views.index, name='bloglist'),
path('<slug:post>/', views.blogpost, name='blogpost'),
path("contact/", views.contact, name="contact"),
path("search/", views.search, name="search")
]
My search.html
{% block body %}
<div class="container mt-3">
<h5> <p> Search Results:</p> </h5>
{% if myposts|length < 1 %}
Your Search -<b> {{query}} </b>- did not match any documents please try again. <br>
<br> Suggestions:
<ul>
<li>Make sure that all words are spelled correctly.</li>
<li>Try more general keywords.</li>
<li>Try different keywords.</li>
</ul>
{% endif %}
<div class="container mt-3">
<div class="row my-2">
{% for post in myposts %}
<div class="col-md-6">
<div class="row no-gutters border rounded overflow-hidden flex-md-row mb-4 shadow-sm h-md-250 position-relative">
<div class="col p-4 d-flex flex-column position-static">
<h3 class="mb-0">{{post.title}}</h3>
<div class="mb-1 text-muted"></div>
<strong class="d-inline-block mb-2 text-primary"><a>{{post.author}} | {{post.created_on}}</a></strong>
<p class="card-text mb-auto">{{post.content|safe}}</p>
Continue reading
</div>
<div class="col-auto d-none d-lg-block">
<img src="/media/{{post.thumbnail}}" class="bd-placeholder-img" width="200" height="250" aria-label="Placeholder: Thumbnail">
<title>Placeholder</title></img>
</div>
</div>
</div>
{% if forloop.counter|divisibleby:2%}
</div>
<div class="row my-2">
{% endif %}
{% endfor %}</div>
</div>
</div>
{% endblock %}
Project urls.py
from django.contrib.sitemaps.views import sitemap
from blog.sitemaps import StaticViewsSitemap
from blog.sitemaps import BlogSitemap
sitemaps ={
'blogpost': BlogSitemap(),
'static': StaticViewsSitemap(),
}
urlpatterns = [
path('admin/', admin.site.urls),
path('shop/', include('shop.urls')),
path('blog/', include('blog.urls', namespace='blog')),
path('', views.index),
path('register/', views.registerPage),
path('login/', views.loginPage),
path('logout/', views.logoutUser),
path('sitemap.xml/', sitemap, {'sitemaps': sitemaps}, name='django.contrib.sitemaps.views.sitemap'),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
models.py
class Blogpost(models.Model):
STATUS_CHOICES= ( ('0', 'Draft'), ('1', 'Publish'),)
post_id = models.AutoField(primary_key= True)
title = models.CharField(max_length=50, unique=True)
slug = models.SlugField(max_length=50, unique=True)
content = models.TextField(max_length=5000, default="")
author = models.ForeignKey(Author, on_delete=models.CASCADE)
thumbnail = models.ImageField(upload_to='shop/images', default="")
created_on = models.DateTimeField(default=timezone.now)
categories = models.ManyToManyField(Category)
status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='draft')
objects = models.Manager()
featured = models.BooleanField()
def get_absolute_url(self):
return reverse('blog:blogpost',
args=[self.slug])
class Meta:
ordering = ('-created_on',)
def __str__(self):
return self.title
Try rewriting your form to something like this:
<form method="POST" action="{% url 'search' %}" class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" type="search" placeholder="Search" arialabel="Search" name="search" id="search">
<button class="btn btn-outline-success mx-2 my-1 my-sm-0" type="submit">Search</button>
</form>
And your search view like this:
def search(request):
myposts = Blogpost.objects.all()
if request.method == 'POST'
query = request.POST.get('search')
if len(query) > 78:
myposts = Blogpost.objects.none()
else:
myposts = Blogpost.objects.filter(Q(title__icontains=query))
myposts = Blogpost.objects.filter(Q(content__icontains=query))
myposts = Blogpost.objects.filter(Q(slug__icontains=query))
if myposts.count() == 0:
messages.warning(request, "No search results found. Please enter again.")
context = {'myposts': myposts, 'query': query}
return render(request, 'blog/search.html', context)
UPDATE
So, after going through your GitHub repository I saw a couple of issues, first off there is no urls.py or views.py in your blog app, its either not added in the repo or just doesn't exist, which would explain the router not finding any paths for your views, hovewer there is one in the question so I'm not sure whats the issue here, please check again so that the file is in the right directory in the root of your blog app folder.
Second off in your main project directory there are files called urls.py, views.py and forms.py, that shouldn't be the case, instead create a seperate app and place them there.

Django count views using, django-hitcount

I did break my head to implement django-hitcount on my blog.
I could do the views count works, but are happening an error to access in my administration page.
Following the code and the error image:
Thank you.
urls.py
from django.contrib import admin
from django.conf import settings
from django.conf.urls.static import static
from django.urls import path, include
from blog.views import index, blog, post
urlpatterns = [
path('admin/', admin.site.urls),
path('', index, name='home'),
path('blog/', blog, name='post-list'),
path('post/<id>/', post, name='post-detail'),
path('ckeditor', include('ckeditor_uploader.urls')),
path('hitcount/', include(('hitcount.urls', 'hitcount'), namespace='hitcount')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
views.py
from django.shortcuts import render, get_object_or_404, redirect, reverse
from .models import Post, Author
from django.db.models.aggregates import Count
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from hitcount.models import HitCount
from hitcount.views import HitCountMixin
...
def post(request, id):
category_count = get_category_count()
most_recent = Post.objects.order_by('-timestamp')[:3]
popular_posts = Post.objects.order_by('-hit_count_generic__hits')[:3]
post = get_object_or_404(Post, id=id)
hit_count = HitCount.objects.get_for_object(post)
hit_count_response = HitCountMixin.hit_count(request, hit_count)
count_hit = True
if request.method == "POST":
return redirect(reverse("post-detail", kwargs={
'id': post.pk
}))
context = {
'post': post,
'hit_count': hit_count,
'category_count': category_count,
'popular_posts': popular_posts,
'views': Post.objects.get(pk=1),
# views.hit_count.hits
# views.hit_count.hits_in_last(days=7)
}
return render(request, 'blog/post.html', context)
post.html
{% extends 'blog/base.html' %}
{% load static %}
{% load hitcount_tags %}
{% block content %}
<body>
<div class="container">
<div class="row">
<div class="col-md-8">
<div>
<div class="" >
<div class="card mb-3">
<img src="{{ post.thumbnail.url }}" class="card-img-top with:"100%"" alt="...">
<div class="card-body">
<h5 class="card-title">{{ post.title }}</h5>
<img src="{{ post.author.profile_picture.url}}" alt="..." class="rounded-circle width="40" height="40"" >
<p>{{ post.author }} | <i class="far fa-clock"></i> {{ post.timestamp|timesince }} ago | <i class="far fa-eye"> {% get_hit_count for post %} views</i></p>
<div>
<hr class="my-4">
<p class="card-text">{{ post.content|safe }}</p>
</div>
<p class="card-text"><small class="text-muted">{{ post.timestamp}}</small></p>
</div>
</div>
</div>
</div>
</div>
<!--Side Bar-->
{% include 'blog/sidebar.html' with most_recent=most_recent category_count=category_count %}
</div>
</div>
</body>
http://127.0.0.1:8000/admin/hitcount/hitcount/
enter image description here
Can you share your admin.py related this model? Because I had the same problem and fixed it in admin.py.
How I fixed my problem in my admin.py file:
class PostAdmin(admin.ModelAdmin):
list_display = ('id', 'baslik', 'kategori', 'slug', 'taslakDurumu', 'formatted_hit_count')
def formatted_hit_count(self, obj):
return obj.current_hit_count if obj.current_hit_count > 0 else '-'
formatted_hit_count.admin_order_field = 'hit_count'
formatted_hit_count.short_description = 'Hits'
it was like this and appered same error so I've added () and worked.
Like this:
def formatted_hit_count(self, obj):
return obj.current_hit_count() if obj.current_hit_count() > 0 else '-'
formatted_hit_count.admin_order_field = 'hit_count'
formatted_hit_count.short_description = 'Hits'
admin.site.register(Post, PostAdmin)

Generic Class: UpdateView and DeleteView not saving data back to model

The UpdateView and DeleteView not saving data back to model
views.py
class ProjectList(ListView):
model = Project
template_name = 'mainapp/browse_app.html'
context_object_name = 'projs'
class ProjectUpdate(UpdateView):
model = Project
fields = ['pname','desc','emailID']
template_name = 'mainapp/project_form_edit.html'
class ProjectDelete(DeleteView):
model = Project
fields = ['id','pname','desc','emailID','updated_on']
template_name = 'mainapp/index.html'
success_url = reverse_lazy('mainapp/projs')
def form_display(request):
data = Project.objects.all()
return render(request,'mainapp/browse_page.html',{'data':data})
...
browse_page.html: has an edit link and a delete button and it displays the project details of the project which is clicked
{% for i in data %}
<center>
{{ i }}
</center>
<!-- Modal -->
<div id="costumModal13{{ forloop.counter }}" class="modal" data-easein="bounceLeftIn" tabindex="-1" role="dialog" aria-labelledby="costumModalLabel" aria-hidden="true">
<a class="btn btn-info btn-lg fa fa-pencil-square-o" href="{% url 'project_edit' pk=i.id %}" aria-hidden="true">Edit</a>
<form method="POST" action="{% url 'project_del' pk=i.id %}">
{% csrf_token %}<input type="submit" value="Delete">
</form>
{{ i.pname }}
{{ i.id }}
{{ i.updated_on }}
</div>
{% endfor %}
urls.py
from django.contrib import admin
from django.urls import path, include, re_path
from mainapp import views
from mainapp.views import ProjectUpdate, ProjectDelete
app_name = 'mainapp'
urlpatterns = [
path('browse/',views.form_display,name="browse_page"),
re_path(r'^browse/(?P<pk>\d+)/$', ProjectUpdate.as_view(), name='project_edit'),
re_path(r'^browse/delete/(?P<pk>\d+)/$', ProjectDelete.as_view(), name='project_del'),
]
On submitting the edited form:
On clicking on delete button:
Can you help me resolve these 2 errors?
1st image problem:
The url has index.html appended to the end. Your url is defined as /browse/7/
2nd image problem:
The namespace delimeter is : not /.
class ProjectDelete(DeleteView):
...
success_url = reverse_lazy('mainapp:projs')

Django using generic views, error http 405

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.