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, если пользователь удален.