Am I being too redundant in this Django view (or can I reduce the repetition in my code)? I'm new to Django and learning my ways around it. I'm writing a fake basic CRUD app to get me started. In the following code I pretty much copy and paste the same code four times with minor adjustments between each. I only pasted it here twice for the Bands and Album models.

Am I doing this right? 

from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.decorators import login_required
from django.template import RequestContext

from models import Band, Album, Song, Instrument

from forms import BandForm, AlbumForm


# Bands Functions:


def bands_index(request):
    latest_band_list = Band.objects.all().order_by('-added_on')[:5]
    return render(request,
                  "bands/index.html", {
                  'latest_band_list': latest_band_list
                  })


def band_detail(request, band_id):
    b = get_object_or_404(Band, pk=band_id)
    return render(request, 'bands/detail.html', {'band': b})


@login_required
def band_add(request):
    form = BandForm(request.POST or None)

    if request.method == 'POST' and form.is_valid():
        instance = form.save(commit=False)
        instance.added_by = request.user
        instance.save()

        return redirect('/bands/')
    else:
        return render(request, 'bands/add.html',
            {'form': form},
            context_instance=RequestContext(request))


@login_required
def band_remove(request, band_id):
    b = get_object_or_404(Band, pk=band_id)
    b.delete()

    return redirect('/bands/')


@login_required
def band_edit(request, band_id):
    b = get_object_or_404(Band, pk=band_id)

    form = BandForm(request.POST or None, instance=b)

    if request.method == 'POST' and form.is_valid():
        instance = form.save(commit=False)
        instance.save()

        return(redirect('/bands/'))
    else:
        return render(request, 'bands/edit.html',
            {'form': form, 'band_id': band_id},
            context_instance=RequestContext(request))


# Album Functions


def albums_index(request):
    latest_album_list = Album.objects.all().order_by('-added_on')[:5]
    return render(request, "albums/index.html", {
        'latest_album_list': latest_album_list
        })

def albums_detail(request, album_id):
    a = get_object_or_404(Album, pk=album_id)
    return render(request, 'albums/detail.html', {'album': a})


@login_required
def album_add(request):
    form = AlbumForm(request.POST or None)

    if request.method == 'POST' and form.is_valid():
        instance = form.save(commit=False)
        instance.added_by = request.user
        instance.save()

        return redirect('/albums/')
    else:
        return render(request, 'albums/add.html',
            {'form': form},
            context_instance=RequestContext(request))


@login_required
def album_remove(request, album_id):
    a = get_object_or_404(Album, pk=album_id)
    a.delete()
    return redirect('/albums/')


@login_required
def album_edit(request, album_id):
    a = get_object_or_404(Album, pk=album_id)

    form = AlbumForm(request.POST or None, instance=a)

    if request.method == 'POST' and form.is_valid():
        instance = form.save(commit=False)
        instance.save()

        return(redirect('/albums/'))
    else:
        return render(request, 'albums/edit.html',
            {'form': form, 'album_id': album_id},
            context_instance=RequestContext(request))
I'd say the best way to be "less redundant" would be to use the already-existing generic views - e.g. DetailView instead of your band_detail.

(I assume you're looking for "the right way to do things" rather than "I'm reinventing the wheel to learn"...)