Django:如何删除一个模型中的项目并更改链接到第一个模型的另一个模型中的多对多关系?

Django: how to delete item in one model AND change many to many relationship in another model that was linked to the first model?

该网站允许用户 select 他们去过的滚石乐队的音乐会。如果它们 select 它会从 API 添加 Concert 和 Song 到模型。并且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'),
]

观看次数。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

查看次数。py/function查看以记录用户的音乐会和相应歌曲

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,当我们 link 用户通过 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 模型相关的歌曲或音乐会。