Django DeleteView doesn't delete the object from data - python

I've just learned CreateView UpdateView and DeleteView models and then I got all of them working. I can change my object I can delete them, but after deleting an object I try to create another and creates one like the before hasn't been deleted. giving me the following pk of the deleted before
it still creates de object although the pk at the moment should be 3, I think after I click the delete button and confirm delete it isn't deleting from data.
These are my models:
from django.db import models from django.urls import reverse
class Dreams (models.Model):
titulo = models.CharField(max_length=100)
objetivo = models.CharField(max_length=100)
imagem = models.CharField(max_length=100)
def get_absolute_url(self):
return reverse ('webdeve:index', kwargs={'pk': self.pk})
def __str__(self):
return self.titulo + ' - ' + self.objetivo
class Which (models.Model):
lets = models.ForeignKey(Dreams, on_delete=models.CASCADE)
make = models.CharField(max_length=100)
it = models.CharField(max_length=100)
favorite = models.BooleanField(default=False)
def __str__(self):
return self.make
my views.py:
from django.views import generic
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from .models import Dreams, Which
from django.urls import reverse_lazy
class IndexView (generic.ListView):
template_name = 'index.html'
def get_queryset(self):
return Dreams.objects.all()
class DetailView (generic.DetailView):
model = Dreams
template_name = 'detail.html'
class DreamCreate (CreateView):
model = Dreams
fields = ['titulo', 'objetivo', 'imagem']
template_name = 'dreams_form.html'
class DreamUpdate (UpdateView):
model = Dreams
fields = ['titulo', 'objetivo', 'imagem']
template_name = 'dreams_form.html'
class DreamDelete (DeleteView):
model = Dreams
template_name= ('dreams_confirm_delete.html')
success_url= reverse_lazy('webdeve:index')
my urls.py:
from django.conf.urls import url
from webdeve import views
app_name = 'webdeve'
# Dreams
urlpatterns = [
url(r'^$', views.IndexView.as_view(), name='index'),
# Dreams/detail
url(r'^(?P<pk>[0-9]+)/$', views.DetailView.as_view(), name='detail'),
# Dreams/detail/add
url(r'^dream/add/$', views.DreamCreate.as_view(), name='dream-add'),
# Dreams/detail/Update
url(r'^dream/(?P<pk>[0-9]+)/$', views.DreamUpdate.as_view(), name='dreams-uptdate'),
# Dreams/detail/detete
url(r'^dream/(?P<pk>[0-9]+)/delete/$', views.DreamDelete.as_view(), name='dreams-delete'),
]
And my index.html with delete button:
<!-- linkando css no html -->
{% extends 'base.html' %}
{% block nav %}
<ul>
{% for Dreams in object_list %}
<img src={{ Dreams.imagem }}>
<li> {{ Dreams.titulo }} - {{ Dreams.objetivo }} <li>
<!--delete BUTTON-->
<form action="{% url 'webdeve:dreams-delete' Dreams.id %}">
{% csrf_token %}
<input type="hidden" name="dreams_id" value="{{ Dreams.id }}" method="post" style="display: inline" >
<button type="submit" class="btn btn-default btn-sm">
<span class="glyphicon glyphicon-trash"></span>
</button>
</form>
{% endfor %}
</ul>
{% endblock %}

DeleteView only deletes your object on POST, not GET. As a result, you need to use method="post" in your form since GET would render this confirm_delete.html again.
<form method="post" action="">
...
</form>
If you can get into DeleteView on GET, action="" is all you need to POST.

Related

ValueError at /create_entry/

Can someone help me to solve this error?
ValueError at /create_entry/
Cannot assign "<SimpleLazyObject: <django.contrib.auth.models.AnonymousUser object at 0x000000B7BBF1BFC8>>": "Entry.entry_author" must be a "User" instance.
urls.py
from django.urls import path
from .views import HomeView, EntryView, CreateEntryView
urlpatterns = [
path('', HomeView.as_view(), name = 'blog-home'),
path('entry/<int:pk>/', EntryView.as_view(), name = 'entry-detail'),
path('create_entry/', CreateEntryView.as_view(success_url='/'), name = 'create_entry')
]
views.py
from django.shortcuts import render
from django.views.generic import ListView, DetailView, CreateView
from .models import Entry
class HomeView(ListView):
model = Entry
template_name = 'entries/index.html'
context_object_name = "blog_entries"
class EntryView(DetailView):
model = Entry
template_name = 'entries/entry_detail.html'
class CreateEntryView(CreateView):
model = Entry
template_name = 'entries/create_entry.html'
fields = ['entry_title', 'entry_text']
def form_valid(self,form):
form.instance.entry_author = self.request.user
return super().form_valid(form)
models.py
from django.db import models
from django.contrib.auth.models import User
class Entry(models.Model):
entry_title=models.CharField(max_length=50)
entry_text=models.TextField()
entry_date=models.DateTimeField(auto_now_add=True)
entry_author=models.ForeignKey(User, on_delete=models.CASCADE)
class Meta:
verbose_name_plural = "entries"
def __str__(self):
return f'{self.entry_title}'
create_entry.html
{% extends "entries/base.html" %}
{% block content %}
<div class="col-md-8"><br><br>
<!-- Blog Post -->
<div class="card mb-4">
<div class="card-header">
Create Blog Post
</div>
<div class="card-body">
<form class="form-conrol" action="" method="post">
{% csrf_token %}
{{form.as_p}}
<button type="submit" class="btn btn-primary">Post Entry</button>
</form>
</div>
</div>
</div>
{% endblock %}
I need your help for this
small project.
You are not logged in, so self.request.user is not a real user. You can use the LoginRequiredMixin [Django-doc] to restrict access to a view such that you can only post (and retrieve) the view when the user has logged in:
from django.contrib.auth.mixins import LoginRequiredMixin
class CreateEntryView(LoginRequiredMixin, CreateView):
model = Entry
template_name = 'entries/create_entry.html'
fields = ['entry_title', 'entry_text']
def form_valid(self,form):
form.instance.entry_author = self.request.user
return super().form_valid(form)

Python Django Form submit button not working as desired

I have been trying to learn Django.
I am stuck on this form part. A form has been created that allows the user to create an Album object where they can fill in the Artist, Album Name, Genre and upload an Album Logo. When I fill in the fields and then click submit, it should then redirect me to the details page for that particular Album that just got created. But nothing appears to happen when clicking the submit button and the object does not get created.
Here is the models.py code that contains an Album class with 4 fields; artist, album_name, genre and album_logo.
from django.db import models
from django.urls import reverse
# Create your models here.
class Album(models.Model):
artist = models.CharField(max_length=250)
album_name = models.CharField(max_length=500)
genre = models.CharField(max_length=100)
album_logo = models.ImageField()
def get_absolute_url(self):
return reverse('music:detail', kwargs={'pk':self.pk})
def __str__(self):
return self.album_name + " - " + self.artist
class Song(models.Model):
album = models.ForeignKey(Album, on_delete=models.CASCADE)
file_type = models.CharField(max_length=100)
song_title = models.CharField(max_length=250)
is_favourite = models.BooleanField(default=False)
def __str__(self):
return self.song_title
Here is the album_form.html code which contains the actual form. I have not used crispy_forms as I am not familiar with Bootstrap though I know CSS.
{% extends 'music/base.html' %}
{% block title %}Add a New Album{% endblock %}
{% block body %}
<form class="formContainer" method="post" enctype="multipart/form-data">
{% csrf_token %}
{% for field in form %}
{% if field.label != 'Album logo' %}
<label for="field{{ forloop.counter }}">{{ field.label }}</label>
<input type="text" id="field{{ forloop.counter }}" name="" value="">
{% else %}
<label for="field{{ forloop.counter }}">{{ field.label }}</label>
<input type="file" id="field{{ forloop.counter }}" name="" value="" accept="image/*">
{% endif %}
<br>
{% endfor %}
<input type="submit" id="submitBtn" name="" value="Add">
</form>
{% endblock %}
This is views.py code where I have made use of class based views and not function based views.
from django.views import generic
from .models import Album, Song
# Create your views here.
class IndexView(generic.ListView):
template_name = 'music/index.html'
queryset = Album.objects.all()
context_object_name = 'all_albums'
class DetailView(generic.DetailView):
model = Album
template_name = 'music/detail.html'
class AlbumCreate(generic.CreateView):
model = Album
fields = ['artist', 'album_name', 'genre', 'album_logo']
def form_valid(self, form):
return super().form_valid(form)
and finally this is my urls.py code:
from django.urls import path, include
from . import views
app_name='music'
urlpatterns = [
#/music/
path('', views.IndexView.as_view(), name='index'),
#/music/5/
path('<int:pk>/', views.DetailView.as_view(), name='detail'),
#/music/album/add/
path('album/add/', views.AlbumCreate.as_view(), name='album-add')
]
After clicking the submit button in the form, it should take me to the "detail" url for the primary key of the Album that got created. Am I missing something here?
In your views.py you need to override the get_success_url function in your CreateView and pass the id as an argument while redirecting.
class AlbumCreate(generic.CreateView):
model = Album
fields = ['artist', 'album_name', 'genre', 'album_logo']
def form_valid(self, form):
return super().form_valid(form)
def get_success_url(self):
return reverse('music:detail', args=(self.object.id,))
Seems you forgot to put action to your <form> tag
Try this
<form class="formContainer" action='{% url 'music:album-add'%}' method="post" enctype="multipart/form-data">
Edit: Also add success url using get_success_url function in your AlbumCreate view to redirect user to album detail page, like was mentioned in above answer
from django.urls import reverse_lazy
...
class AlbumCreate(generic.CreateView):
...
def get_success_url(self, **kwargs):
return reverse_lazy('music:detail', args = (self.object.id,))

Django Getting PK from Createview

I am creating a blog post with a specific primary key (pk). My other function requires to have the pk as an input (please check the views.py). I am trying to get the post id by getting it as an object id, although it indicated that object has no attribute 'id'.
Any ideas how to get pk as a variable?
Thanks,
Ted
#The template
{% extends "Blog/base.html" %}
{% load crispy_forms_tags %}
{% block content%}
<div class="content-section">
<form method = "POST">
{% csrf_token %}
<fieldset class="form-group">
<legend class="border-bottom mb-4"> Blog Post </legend>
{{ form|crispy }}
</fieldset>
<div class="form-group">
<button class="btn btn-outline-info" type="submit">Post</button>
</div>
</form>
</div>
{% endblock content%}
#urls.py
from django.urls import path
from .views import PostListView, PostDetailView, PostCreateView, PostUpdateView, PostDeleteView
from . import views
urlpatterns = [
path('post/<int:pk>/', PostDetailView.as_view(), name='post-detail'),
path('post/new', PostCreateView.as_view(), name='post-create'),
]
#views.py
from django.shortcuts import render
from django.views.generic import (
ListView,
DetailView,
CreateView,
UpdateView,
DeleteView
)
from .models import Post
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from .latex import tex
from django.http import FileResponse, Http404
from django.urls import reverse
class PostCreateView(LoginRequiredMixin, CreateView):
model = Post
fields = ['first_name', 'last_name', 'titles' ,'title', 'content', 'billing']
def form_valid(self, form):
form.instance.author = self.request.user # Use this to get the information from the form.
pk = self.object.id
self.external(pk)
return super().form_valid(form),
#Error which I am getting
'NoneType' object has no attribute 'id'
You can obtain the object through the instance wrapped in the form. But as long as the object is not saved, it has no primary key.
class PostCreateView(LoginRequiredMixin, CreateView):
model = Post
fields = ['first_name', 'last_name', 'titles' ,'title', 'content', 'billing']
def form_valid(self, form):
form.instance.author = self.request.user
response = super().form_valid(form)
pk = form.instance.pk
self.external(pk)
return response

Django form not passing is_valid() test

In my Django app in a Createview class it never enters the is_valid(): statement and I can not seem to find any errors:
models.py
from django.db import models
from django.core.urlresolvers import reverse
from django.contrib.auth.models import User
from django.conf import settings
from .validators import validate_file_extension
import zipfile
class Post(models.Model):
title = models.CharField(max_length=140)
body = models.TextField(max_length=250)
date = models.DateTimeField(auto_now=True, auto_now_add=False)
album_image = models.FileField(validators=[validate_file_extension])
user = models.ForeignKey(User, default=1)
face = models.IntegerField(default=1)
def get_absolute_url(self):
return reverse('photos:detail',kwargs={'pk':self.pk})
def __str__(self):
return self.title
views.py
This is my view folder that contains a list view a detailed view and create view. Although the form doesnt pass the valid test, it still gets uploaded and is viewable by the user
from django.http import Http404
from django.http import HttpResponse
from django.shortcuts import render, get_object_or_404
from django.core.urlresolvers import reverse
from .forms import PostForm
from .models import Post
from django.contrib.auth.models import User
from django.template import loader
from django.views import generic
from django.views.generic.edit import CreateView
import cognitive_face as CF
import json
class IndexView(generic.ListView):
template_name='photos/post.html'
def get_queryset(self):
return Post.objects.filter(user=self.request.user)
class DetailView(generic.DetailView):
model = Post
template_name = 'photos/detail.html'
class PostCreate(generic.CreateView):
form = PostForm()
model = Post
if form.is_valid():
print('valid')
instance = form.save(commit=False)
username = form.cleaned_data['username']
album_image = form.cleaned_data['album_image']
instance.save()
if not form.is_valid():
print('not')
post_form.html
<html>
<body>
{% if request.user.is_authenticated%}
<h3>Hello {{request.user.username}}, please upload your image as either a .JPEG, .GIF or .PNG</h3>
{% endif %}
<div class="container-fluid">
<div class="row">
<div class="col-sm-12 col-md-7">
<div class="panel panel-default">
<div class="panel-body">
{% if request.user.is_authenticated %}
<form class="form-horizontal" role="form" action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
{{form.as_p}}
{{ form.errors }}
{{ form.non_field_errors }}
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-success">Submit</button>
</div>
</div>
</form>
{% else %}
<p>You must be logged in to upload a file</p>
{% endif %}
</div>
</div>
</div>
</body>
</html>
urls.py
from django.conf.urls import url, include
from django.views.generic import ListView, DetailView
from photos.models import Post
from . import views
app_name = 'photos'
urlpatterns = [
url(r'^$',views.IndexView.as_view(), name='index'),
url(r'^(?P<pk>[0-9]+)/$',views.DetailView.as_view(), name='detail'),
url(r'post/add/$', views.PostCreate.as_view(), name='post-add'),
]
You are writing function based view code inside a class based view, which is incorrect.
You shouldn't need to instantiate the form, or manually check whether it is valid. Just set form_class for the view, then override form_valid or form_invalid if you need to change the behaviour when the form is valid or invalid. Since you have {{ form.errors }} in your template, it should show any errors when you submit the form.
class PostCreate(generic.CreateView):
form_class = PostForm
model = Post
See the docs on form handling with class based views for more information. You might find it easier to write a function based view to begin with, since the flow of the code is easier to follow.

NoReverse Match at Delete View

I started coding with Python and Django last week and now I start getting desperate about it.
I have to work on a To-Do-List and want to delete ToDo task by clicking on a button next to the task.
Now I always get a
NoReverseMatch at /delete/1
error :(
The delete_confirm.html:
{% extends "base_page.html" %}
{% block title %}Confirm Todo delete{% endblock %}
{% block content %}
<form action="" method="post">{% csrf_token %}
<p>Are you sure you want to delete "{{ object }}"?</p>
<input type="submit" value="Confirm" />
</form>
{% endblock %}
My Urls.py:
from django.conf.urls import patterns, url
from todolist import views
urlpatterns = patterns('',
url(r'^$', views.IndexView.as_view(), name='index'),
url(r'^add', views.AddView.as_view(), name='add'),
url(r'^impressum', views.ImpressumView.as_view(), name='impressum'),
url(r'^edit/(?P<pk>\d+)$', views.UpdateView.as_view(), name='todo_edit'),
url(r'^delete/(?P<pk>\d+)', views.DeleteView.as_view(), name='todo_delete'),
)
The views.py:
from django.shortcuts import render
from django.core.urlresolvers import reverse_lazy
from django.http import HttpResponse
from django.views import generic
from django.views.generic import TemplateView, ListView, CreateView, UpdateView, DeleteView
from todolist.models import Todo
# Create your views here.
class IndexView(ListView):
template_name = 'index.html'
model = Todo
class ImpressumView(TemplateView):
template_name = 'impressum.html'
class AddView(CreateView):
template_name = 'add.html'
model = Todo
fields = ['title','deadline','progress']
success_url = '/'
class UpdateView(UpdateView):
template_name = 'edit.html'
model = Todo
fields = ['title','deadline','progress']
success_url = '/'
class DeleteView(DeleteView):
template_name = 'delete_confirm.html'
model = Todo
success_url = reverse_lazy('/')
The interesting part of the index.html:
<!--Table content-->
{% for todo in object_list %}
<tr>
<td class="text-left">{{todo.title}}</td>
<td> {{todo.deadline}}</td>
<td>
<div class="progress">
<div class="progress-bar" role="progressbar" aria-valuenow="{{todo.progress}}" aria-valuemin="0" aria-valuemax="100" style="width: {{todo.progress}}%">
{{todo.progress}}%
</div>
</div>
</td>
<td >
<div class="btn-group">
Edit
Delete
<button class="btn btn-default" data-toggle="tooltip" title="Done?" data-placement="right"><span class="glyphicon glyphicon-check"></button>
</div>
</td>
{% endfor %}
Would be great if some of your guys could help a newbie :)
The problem is this line in your delete view.
class DeleteView(DeleteView):
...
success_url = reverse_lazy('/')
You can either provide the url:
success_url = '/'
or use reverse_lazy with the url name that you wish to reverse:
success_url = reverse_lazy('index')

Categories