Django CRUD (Create, Retrieve, Update, Delete)

UPDATE 1: The main example use Class Based Views, I also added Function Based Views version of the same functionality.

UPDATE 2: I added a new example application with user access, user must login and each user has his own list.
Sample Code: You can download a sample application from https://github.com/rayed/django_crud

UPDATE 3: You might be interested in Django CRUD Parent/Child Edition

In this post I briefly cover the step needed to create a CRUD app in Django, the steps we will need are:

  • Create an App
  • Create the Model
  • Create the Admin Interface (optional)
  • Create the View
  • Define the URLs (i.e. URL to View mapping)
  • Create the Templates

Create new App

From the Django project directory we will create the new app called “servers” to store our servers information:

 ./manage.py startapp servers

We will also need to register the new app in our Django project, add the app ‘server’ to the INSTALLED_APPS in your django_proj_name/settings.py:

INSTALLED_APPS = (
  :
  'servers',
  :
)

Create the Model

The model file would be servers/models.py:

from django.db import models
from django.core.urlresolvers import reverse

class Server(models.Model):
    name = models.CharField(max_length=200)
    ip = models.GenericIPAddressField()
    order = models.IntegerField()

    def __unicode__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('server_edit', kwargs={'pk': self.pk})

After defining the model you need to provision it to the database:

./manage.py makemigrations
./manage.py migrate

To create the table for the new model.

Admin Interface (optional)

Django will give you free CRUD interface from the admin site, just define the file servers/admin.py as:

from django.contrib import admin
from servers.models import Server

admin.site.register(Server)

The Views

We will use Django Class-based views to crete our app pages, the file servers/views.py would look like:

from django.http import HttpResponse
from django.views.generic import TemplateView,ListView
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.core.urlresolvers import reverse_lazy

from servers.models import Server

class ServerList(ListView):
    model = Server

class ServerCreate(CreateView):
    model = Server
    success_url = reverse_lazy('server_list')
    fields = ['name', 'ip', 'order']

class ServerUpdate(UpdateView):
    model = Server
    success_url = reverse_lazy('server_list')
    fields = ['name', 'ip', 'order']

class ServerDelete(DeleteView):
    model = Server
    success_url = reverse_lazy('server_list')

Define the URLs

We need to define app URLs in the file __servers/urls.py:

from django.conf.urls import patterns, url

from servers import views

urlpatterns = patterns('',
  url(r'^$', views.ServerList.as_view(), name='server_list'),
  url(r'^new$', views.ServerCreate.as_view(), name='server_new'),
  url(r'^edit/(?P<pk>\d+)$', views.ServerUpdate.as_view(), name='server_edit'),
  url(r'^delete/(?P<pk>\d+)$', views.ServerDelete.as_view(), name='server_delete'),
)

This URLs wouldn’t work unless you include the servers/urls.py in the main URLs file django_proj_name/urls.py:

urlpatterns = patterns('',
  :
  url(r'^servers/', include('servers.urls')),
  :
)

Templates

templates/servers/server_form.html This file will be used by Edit and Update views:

<form method="post">{% csrf_token %}
    {{ form.as_p }}
    <input type="submit" value="Submit" />
</form>

templates/servers/server_list.html This file will be used by the ListView:

<h1>Servers</h1>
<ul>
    {% for server in object_list %}
    <li>{{ server.name }}  :  
    <a href="{% url "server_edit" server.id %}">{{ server.ip }}</a>
    <a href="{% url "server_delete" server.id %}">delete</a>
    </li>
    {% endfor %}
</ul>

<a href="{% url "server_new" %}">New</a>

templates/servers/server_confirm_delete.html This file will be used by DeleteView:

<form method="post">{% csrf_token %}
    Are you sure you want to delete "{{ object }}" ?
    <input type="submit" value="Submit" />
</form>

Function Based View Version

The example above uses Class Based Views (or CBV for short) to implement the views, what I will cover now is how to implement the same functionality but with Function Based Views i.e. using functions instead of classes, we will be using the same templates:

servers/views.py:

from django.shortcuts import render, redirect, get_object_or_404
from django.forms import ModelForm

from servers.models import Server

class ServerForm(ModelForm):
    class Meta:
        model = Server
        fields = ['name', 'ip', 'order']

def server_list(request, template_name='servers/server_list.html'):
    servers = Server.objects.all()
    data = {}
    data['object_list'] = servers
    return render(request, template_name, data)

def server_create(request, template_name='servers/server_form.html'):
    form = ServerForm(request.POST or None)
    if form.is_valid():
        form.save()
        return redirect('server_list')
    return render(request, template_name, {'form':form})

def server_update(request, pk, template_name='servers/server_form.html'):
    server = get_object_or_404(Server, pk=pk)
    form = ServerForm(request.POST or None, instance=server)
    if form.is_valid():
        form.save()
        return redirect('server_list')
    return render(request, template_name, {'form':form})

def server_delete(request, pk, template_name='servers/server_confirm_delete.html'):
    server = get_object_or_404(Server, pk=pk)    
    if request.method=='POST':
        server.delete()
        return redirect('server_list')
    return render(request, template_name, {'object':server})

servers/urls.py:

from django.conf.urls import patterns, url

from servers import views

urlpatterns = patterns('',
  url(r'^$', views.server_list, name='server_list'),
  url(r'^new$', views.server_create, name='server_new'),
  url(r'^edit/(?P<pk>\d+)$', views.server_update, name='server_edit'),
  url(r'^delete/(?P<pk>\d+)$', views.server_delete, name='server_delete'),
)

p.s. personally I prefer using FBV over CBV, the article Django’s CBVs were a mistake explains why.

63 thoughts on “Django CRUD (Create, Retrieve, Update, Delete)”

  1. Really useful and a great starting point. Thank you!

    On a side note, please note that IPAddressField has been deprecated for Django 1.7 in favour of GenericIPAddressField.

  2. Really a great way to get started with CRUD

    Noticed something that snippets like {% url "server_new" %} should contain the url names without quotes {% url server_new %}

  3. with the functions way, in the server_delete function, don’t show the name the object, I add :

    data = {}
    data['object'] = server

    And now I can see it.
    *sorry for my english

  4. Thank you @Angel,
    I changed this line:
    return render(request, template_name, {‘server’:server})
    to this:
    return render(request, template_name, {‘object’:server})

  5. Firstly congratulations on the post.
    How do I put a message of success and it shows in the template in views for example Create and Update?
    (Using CBV)

  6. Hello,
    Thanks for this tutorial.
    I used the FBV and it worked the first time then it says there is no reverse match for server_new what should I do.

  7. @Samuel make sure you have this line in urls.py:

    urlpatterns = patterns('',
    :
    url(r'^new$', views.server_create, name='server_new'),
    :
    )

    the “name” part will be used for reverse match.

  8. Great! It works, but now I can’t delete it says “delete() missing 1 required positional argument: ‘self'”
    and also if I try to edit it says the object has no id.

  9. thankyou very much. now i understand how django work. can you give a tutorial that can authenticate user from model ?
    thank you

  10. @ranggatry
    You are welcome.

    About the authentication, you should do it in the view not the model.

    Django already have a pretty good authentication system:
    https://docs.djangoproject.com/en/1.7/topics/auth/

    You can use “login_required” decorator to protect a given view:
    https://docs.djangoproject.com/en/1.7/topics/auth/default/#django.contrib.auth.decorators.login_required

    To implement custom login/logout check this post:
    https://rayed.com/wordpress/?p=1350

  11. @rayed: thank you very much rayed. i’ve following your tutorial about authentication. But, if i want to create an authentication that authenticated by our custom models. Can we do it ?

    example: i have models name ‘staff’ and it contains 3 field, that is username, password, and authorization. Can i create an authentication from staff models ?

  12. I would suggest “Extending the existing User model” instead of having new model:
    https://docs.djangoproject.com/en/1.7/topics/auth/customizing/#extending-the-existing-user-model

    If you don’t think extending the user model would help, you can build your own authentication backend:
    https://docs.djangoproject.com/en/1.7/topics/auth/customizing/#specifying-authentication-backends

    If both solution don’t work for you, you can build your own authentication system.

  13. @rayed: thank your very much again rayed. i think i will use authentications by extending default user model. And i can do it with one to one relationship. Alhamdulillah

  14. Really a great tutorial ! Thank you !

    I would like to know how i can create a search form together server_form. thanks

  15. Nice solution mate!
    The other stuff i found over the internet was really confusing.

    Anyway, i will put this in my blog, but i will keep the original poster 😉

    Thanks a lot!

  16. For Django 1.8, the ModelForm needs a fields attribute to avoid
    “Creating a ModelForm without either the ‘fields’ attribute or the ‘exclude’ attribute is prohibited”.

  17. Nice tutorial, surprisingly this is not covered on djangoproject website.

    I am wondering, is there a reason to use the following in the model:

    success_url = reverse_lazy(‘server_list’)

    Later in your view you use redirect() function anyway, so its kind of maintained in both locations. I have seen another tutorial where there was only redirect on success inside the view, i.e.

    return HttpResponseRedirect(reverse(‘article:detail’, args=(article.id,)));

    Is there any good reason to use on or another approach?

  18. What is the project name at this case…?
    Is project name = ‘Server’ ?
    And
    At step of defining URL, in my app folder does’nt contain urls.py. Is that mean I must creating this file before…?
    Great tutorial. Thanks.

  19. I have a doubt. Where is the exact path for the following:
    “templates/servers/server_form.html”

    Is it under django_proj_name (the directory which contains the file manage.py)
    or is it under the app “servers” (the directory which contains the file models.py)
    or are you referring to some other place.

    Please help out.
    Thanks.

  20. Thanks a lot for your help for new Django users. A real nice ‘non-scary’ tutorial to help us get started!! Jazakallah khairan!

  21. Love your post and project, I wonder if you have a similar minimalistic app for users/groups/admin (without the django admin).

    So if I want to have a managing dashboard for a CRUD app to handle users, products/servers/items, and other things such as logging info.
    – admin: handle users and their products
    – users: handle their products
    – visitor: handle their selections

    Not sure how much code you will need for something that like that.

  22. @JZA I’ve built it previously using the same structure, but of course using the Django built in User model, instead of building my own.

Leave a Reply

Your email address will not be published. Required fields are marked *