Installing and developing local apps

First we need to set up static files serving during the development process. Ideally we should install a testing web server (nginx or apache) and develop the site in an environment as similar as possible with the production environment.

To set up static and media files serving during development, add the following to your “urls.py” file:

from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    # ... the rest of your URLconf goes here ...
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

To create a new app named “inventory” run the following:

./manage startapp inventory

the following python package has been added to your project:

inventory
├── __init__.py
├── admin.py
├── apps.py
├── migrations
│   └── __init__.py
├── models.py
├── tests.py
└── views.py

Make the following changes:

inventory/settings.py:

INSTALLED_APPS = [
    ...
    'inventory',
    ]

Now we have an empty app named “inventory” which is registered with the django project. We want to build a simple app containing 3 pieces of information:

  • a list of machines in the department
  • a list of machine owners
  • a pcs price list

Add models

inventory/models.py:

class Machine(models.Model):
    name = models.CharField(max_length=20)
    mac = models.CharField('MAC address', max_length=20)
    ip = models.GenericIPAddressField(blank=True, null=True)
    notes = models.TextField(blank=True)
    owner = models.ManyToManyField("Owner", related_name='owner')
    price = models.ForeignKey("Price")

    def __str__(self):
        return self.name + ', ' + self.ip


class Owner(models.Model):
    name = models.CharField(max_length=255)
    email = models.EmailField()
    phone = models.CharField(max_length=255)

    def __str__(self):
        return self.name


class Price(models.Model):
    name = models.CharField(max_length=255)
    price = models.FloatField()

    def __str__(self):
        return "{0}, ${1}".format(self.name, self.price)

Now run the migrations to create the necessary tables in the database:

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

You can now inspect the generated models and tables with the following command:

./manage.py inspectdb

Set up the admin

inventory/admin.py:

from .models import Machine, Owner, Price

class MachineInline(admin.TabularInline):
    model = Machine
    fields = ['name', 'mac', 'ip']


class MachineAdmin(admin.ModelAdmin):
    fields = ['name', 'mac', 'ip', 'notes', 'owner', 'price']
    list_display = ['name', 'mac', 'ip', 'price']
    list_filter = ['ip', 'name']
    filter_horizontal = ['owner']


class OwnerAdmin(admin.ModelAdmin):
    list_display = ['name', 'email', 'phone']


class PriceAdmin(admin.ModelAdmin):
    list_display = ['name', 'price']
    inlines = [MachineInline]


admin.site.register(Machine, MachineAdmin)
admin.site.register(Owner, OwnerAdmin)
admin.site.register(Price, PriceAdmin)

Show content on the ‘public’ web

Set up templates

Create a directory “templates” in the root of your project. Register the template folder in the settings.

settings.py:

TEMPLATES = [
    {
    ...
    'DIRS': [
            os.path.join(BASE_DIR, 'templates'),
        ],
    ...
    }
]

In the template dir create a html file named “base.html”. This template is the parent of all the other templates in the project. It is the best place to insert boilerplate code like css and js which will be inherited by all other child templates.

templates/base.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<!--
<div><b>Inventory app logo</b></div>
-->

{% block content %}
    <h1>This is the base.html file</h1>
{% endblock content %}

</body>
</html>

Write views

We will write 3 views (class based generic).

  • One is a plain main inventory page.
  • One lists machines.
  • One shows details about machines.

inventory/views.py:

from django.views.generic import DetailView, ListView, TemplateView

from .models import Machine


class InventoryHome(TemplateView):
    template_name = 'inventory/index.html'


class MachineListView(ListView):
    model = Machine


class MachineDetailView(DetailView):
    model = Machine

Create templates for inventory app

Create a folder named “templates/inventory” in the inventory app.

There create the following html files:

index.html:

{% extends 'base.html' %}

{% block content %}
    <h1>This is the inventory/index.html file</h1>
{% endblock content %}

machine_list.html:

{% extends 'base.html' %}

{% block content %}
<h1>Machines Inventory</h1>

<ul>
    {% for machine in object_list %}
        <li>
            <a href="{% url 'inventory:machine-detail' machine.pk %}">
                {{ machine }}
            </a>
        </li>
    {% endfor %}
</ul>

{% endblock content %}

machine_detail.html:

{% extends 'base.html' %}

{% block content %}
<h1>Machine Details</h1>
<dl>
    <dt>name</dt>
    <dd>{{ object.name }}</dd>
    <dt>mac</dt>
    <dd>{{ object.mac }}</dd>
    <dt>price</dt>
    <dd>${{ object.price.price }}</dd>
    <dd>{{ object.price.name }}</dd>
    <dt>owner(s)</dt>
    {% for owner in  object.owner.all %}
        <dd>{{ owner.name }}, {{ owner.email }}</dd>
    {% empty %}
        {{ object }} has no owner.
    {% endfor %}

</dl>
{% endblock content %}

setup urls

First we need to create a urls.py file in the ‘inventory’ app

inventory/urls.py:

from django.conf.urls import url

from .views import InventoryHome, MachineDetailView, MachineListView

urlpatterns = [
    url(r'^$', InventoryHome.as_view(), name="home"),
    url(r'^machines/$', MachineListView.as_view(), name="machine-list"),
    url(r'^machines/(?P<pk>\d+)/$', MachineDetailView.as_view(),
        name="machine-detail"),
]

We also nedd to connect the inventory urls to the project urls:

someproj/urls.py:

urlpatterns = [
 ...
 url(r'^inventory/', include('inventory.urls', namespace='inventory')),
 ...
]

Now we browse to:

http://localhost:8000/inventory

and visit the app. Also we can add some more machines through the admin.

Our inventory app is installed and functional