Django: как удалить элемент в одной модели И изменить отношения "многие ко многим" в другой модели, которая была связана с первой моделью?

Этот сайт позволяет пользователям выбирать концерты Rolling Stones, на которых они побывали. Он добавит концерт и песню в модель из API, если они их выберут. А Concert.song имеет отношение "многие ко многим" с моделью пользователя

Если пользователь удаляет концерт из списка концертов, песни все равно появляются. Я не обязательно хочу, чтобы песня была удалена, потому что они могли услышать песню с другого концерта. Я также не думаю, что это лучшая идея - изменить пользователя песни с usernmae на --- (потому что null=True). Я думаю, что мой единственный выбор - это как-то изменить теги шаблона usersonglist.html?

Models.py

class Concert(models.Model):
venue = models.CharField(max_length=200, null=True)
concertid = models.CharField(max_length = 200, null=False, default='didnotsaveproperly') 
date = models.DateField(null=True) 
city = models.CharField(max_length=100, null=True)
country = models.CharField(max_length=200, null=True)
user = models.ForeignKey(USER_MODEL, related_name="concerts", on_delete=models.CASCADE, null=True) 
song = models.ManyToManyField("Song", blank=True, null=True)

    def __str__(self): 
         return str(self.concertid) + " " + str(self.venue) + " " + str(self.date) 

class Song(models.Model): 
    name = models.CharField(max_length = 100, null=True) 
    user = models.ForeignKey(USER_MODEL, related_name="songs", on_delete=models.CASCADE, null=True)

    def __str__(self):
        return self.name

URLS.py

urlpatterns = [
    path("", views.display_concerts, name="choose_concerts"),
    path('add/<str:concertdict>/', views.log_concert_and_song, name='concert_add'),
    path('userconcerts/', views.ConcertListView.as_view(), name='user_concert_list'),
    path('<int:pk>/delete/', views.ConcertDeleteView.as_view(), name='delete_concert'),
    path('usersonglist/', views.SongListView.as_view(), name='user_song_list'),
]

Views.py/SongListView для usersonglist.html

class SongListView(LoginRequiredMixin, ListView):
model = Song 
template_name = "concerts/usersonglist.html" 

def get_queryset(self):
    queryset = Song.objects.filter(user=self.request.user)
    return queryset

Views.py/function view to log concert and respective songs for user

def log_concert_and_song(request, concertdict):
    if request.method == "POST":
        url = 'https://api.setlist.fm/rest/1.0/'
        setlist_path = f'setlist/{concertdict}'
        header = {
        "x-api-key": "******",
        "Accept": "application/json"
        } 
        params = {
        "p": 1
        }
        
        setlists = requests.get(f"{url}{setlist_path}", params=params, headers=header).json() 
        
        concertdict = {} 
        user_concert_list = []
        concertdict['venue'] = setlists['venue']['name']
        concertdict['eventDate'] = format_date(setlists['eventDate'])
        concertdict['city'] = setlists['venue']['city']['name']
        concertdict['country'] = setlists['venue']['city']['country']['name']
        concertdict['id'] = setlists['id'] 
        concert_id_to_generate_songs = concertdict['id']
        Concert_save = Concert(
            concertid=concertdict['id'], 
            date=concertdict['eventDate'], 
            venue=concertdict['venue'], 
            city=concertdict['city'], 
            country=concertdict['country'], 
            user = request.user
            )
        
        Concert_save.save() 
        user_concert_list.append(concertdict)  

        songdict = {} # {concertid: [song1, song2, etc.]} #not needed for saving song name but in case I need to reference 
        list_of_songs_from_api = setlists['sets']['set'][0]['song'] #[{"name": "Shame, Shame, Shame","cover": {},},{"name": "Down the Road Apiece", "cover": { },}]
        final_list = []
        
        for song in list_of_songs_from_api: #song = {"name": "Shame, Shame, Shame","cover": {},}
            song_name = song['name'] 
            try: 
                Song_save = Song.objects.get(name=song_name, user=request.user) 
            except: 
                Song_save = Song(
                    name=song_name,
                    user=request.user
                )
                Song_save.save() 
            
            Concert_save.song.add(Song_save) 

            final_list.append(song['name'])
            songdict[concert_id_to_generate_songs] = final_list 
        
        return redirect("user_concert_list")
    else:
        return render(request, 'concerts/concertslist.html')

Views/DeleteView для удаления концерта (но мне нужно, чтобы это также удаляло песню из usersonglist.html)

class ConcertDeleteView(DeleteView):
    model = Concert
    success_url = reverse_lazy('user_concert_list')

   def get(self, *a, **kw):
        return self.delete(*a, **kw)

HTML форма для удаления концерта

             <form method="post" action="{% url 'delete_concert' concert.pk %}">
                {% csrf_token %}
                <input type="submit" value="Delete" />             
            </form> 

Bryant, Когда мы связываем пользователя с другой моделью через ForeignKey, мы должны сказать django, что делать с моделью, если пользователь будет удален. поэтому мы говорим

 user = models.ForeignKey(USER_MODEL, related_name="songs", 
                          on_delete=models.CASCADE, null=True)

здесь мы говорим django удалить все песни, связанные с пользователем, если пользователь удален, потому что мы установили on_delete=models.CASCADE.

но если мы скажем on_delete=models.DO_NOTHING, то django не будет удалять песни или концерты, связанные с моделью django, если пользователь удален.

Вернуться на верх