0

I have created DeleteView for my 'Album' model, but it's now working as expected. Here is my scripts:

urls.py

from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^albums/create/$', views.AlbumCreateView.as_view(), name='album_create'),
    url(r'^albums/(?P<slug>[-\w]+)/update/$', views.AlbumUpdateView.as_view(), name='album_update'),
    url(r'^albums/(?P<slug>[-\w]+)/delete/$', views.AlbumDeleteView.as_view(), name='album_delete'),
    url(r'^albums/(?P<slug>[-\w]+)/$', views.AlbumDetailView.as_view(), name='album_detail'),
    url(r'^albums/$', views.AlbumListView.as_view(), name='album_index'),
    url(r'^songs/create/$', views.SongCreateView.as_view(), name='song_create'),
    url(r'songs/$', views.SongListView.as_view(), name='song_index'),
    url(r'^(?P<song_id>[0-9]+)/favorite/$', views.make_song_favorite, name='song_favorite'),
    url(r'^$', views.AllAlbumListView.as_view(), name='index'),
]

views.py

from django.views.generic import ListView, DeleteView
from django.contrib.auth.mixins import LoginRequiredMixin

from .models import Album

class AlbumListView(LoginRequiredMixin, ListView):
    template_name = 'music/album_index.html'
    context_object_name = 'all_albums'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['album_active'] = True
        return context

    def get_queryset(self):
        queryset = Album.objects.filter(owner=self.request.user).order_by('-release_date')
        return queryset

class AlbumDeleteView(DeleteView):
    model = Album
    template_name = 'music/album_index.html'
    success_url = '/albums/'

album_index.html

{% extends "base.html" %}

{% block content %}
<div class="row">
  <div class="col-md-9">
    <h1>Your Albums</h1>
    <a class="btn btn-primary" href="{% url 'music:album_create' %}">Add Album
      <span class="oi oi-plus" title="Add New Album"></span>
    </a>
    <div class="card-columns" style="margin-top: 10px;">
      {% for album in all_albums %}
      <div class="card">
        <img class="card-img-top img-fluid" src="{{ album.logo.url }}"
             style="background-size: cover;">
        <div class="card-body">
          <h4 class="card-title">{{ album.title }}</h4>
          <h6 class="card-subtitle mb-2 text-muted">{{ album.artist }}</h6>
          <a class="btn btn-primary" href="{% url 'music:album_detail' album.slug %}">Look Inside</a>
          <a class="btn btn-primary" href="{% url 'music:album_update' album.slug %}">
            <span class="oi oi-pencil" title="Edit Album"></span>
          </a>
          <a class="btn btn-primary" href="{% url 'music:album_delete' album.slug %}"
             data-toggle="modal" data-target="#albumDeleteConfirm">
            <span class="oi oi-trash" title="Delete Album"></span>
          </a>
          <div class="modal fade" id="albumDeleteConfirm"
               tabindex="-1" role="dialog" aria-labelledby="confirmAlbumDelete">
            <div class="modal-dialog" role="document">
              <div class="modal-content">
                <div class="modal-header">
                  <h5 class="modal-title" id="confirmAlbumDelete">Remove album '{{ album.title }}'</h5>
                  <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                  </button>
                </div>
                <div class="modal-body">
                  <p>
                    Are you sure to remove this album? Please, note that all songs
                    associated with this album will be also removed.
                  </p>
                </div>
                <div class="modal-footer">
                  **<form method="post" action="{% url 'music:album_delete' album.slug %}">{% csrf_token %}
                    <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
                    <button type="submit" class="btn btn-primary" value="Confirm">Remove</button>
                  </form>**
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
      {% endfor %}
    </div>
  </div>
  <div class="col-md-3">
  </div>
</div>
{% endblock %}

As you see in the views.AlbumListView I've ordered albums by their release date. My problem is, when I click the remove button, DeleteView removes the first album (i.e. the album with the newest release date), instead of the clicked one. I couldn't figure out where is the problem. Can you help?

Thanks in advance!

Elgin Cahangirov
  • 1,932
  • 4
  • 24
  • 45
  • Rather than using slugs in the URLs for identifiers, I would use the primary key of the model record. – Jason Jan 04 '18 at 18:21
  • Why? Urls with slugs are nicer than pks. Besides, django.utils.slugify, I've implemented my now unique slug generator and guaranteed that there same slug can't be used for two different albums, even if their name are the same. So, I don't think that, using slugs in urls will cause any problem. – Elgin Cahangirov Jan 04 '18 at 18:42

2 Answers2

2

An id should be unique, but you have a div with id="albumDeleteConfirm" for each album.

Make the id unique (e.g. by including the slug or pk), and update data-target as well.

In your DeleteView, I would not use the same template music/album_index.html that you use for the list view. There is an example delete template in the docs. This template will only be a fallback - if your modal works then it won't be seen.

Alasdair
  • 298,606
  • 55
  • 578
  • 516
1

Try this I am doing same thing so, i use this one. view.py

class AlbumDeleteView(DeleteView):
    model = Album
    success_url = reverse_lazy('music:index')

in url.py

url(r'album/(?P<pk>[0-9]+)/delete/$', views.AlbumDeleteView.as_view(), name="album_delete")
common sense
  • 3,775
  • 6
  • 22
  • 31
Nirav Patel
  • 1,297
  • 1
  • 12
  • 23