Creating a Django-Oscar App with Dashboard (Part 1)
In this tutorial, you are going to learn how to create a new Django app and integrate it into Oscar e-commerce framework. Particularly, we will create a new sample Django app called boutique
and integrate it to Oscar's default front and dashboard.
Getting ready (django-oscar)
First, it is necessary to create a virtual environment to work in. I use pipenv as a virtual environment for its simplicity and ease of use. Create a directory called /myoscarapp
, move inside and run the following command:
$ pipenv shell
Then install the django-oscar using pip:
$ pip install django-oscar[sorl-thumbnail]
Now create a brand new Dango project using the following command and rename the created directory to src
for convenience:
$ django-admin startproject myoscarproject
$ mv myoscarproject src
Next, configure Django settings.py
and urls.py
as described in Oscar's corresponding documentation. Run makemigrations
and migrate
:
$ python manage.py makemigrations
$ python manage.py migrate
Test the website:
python manage.py runserver
The following screen should be now available:
Creating “boutique” app for Django-Oscar
The new app is created as usual using the following command:
python manage.py startapp boutique
Once again as usual after the app is created, it is necessary to register the app in INSTALLED_APPS
in settings.py
as shown below:
INSTALLED_APPS = [
...
'boutique.apps.BoutiqueConfig',
]
Similarly, your urls.py
should look like this:
from django.apps import apps
from django.urls import include, path
from django.contrib import adminurlpatterns = [
path('i18n/', include('django.conf.urls.i18n')),
path('admin/', admin.site.urls),
#path('dashboard/boutique/', apps.get_app_config('boutique_dashboard').urls),
path('boutique/', apps.get_app_config('boutique').urls),
path('', include(apps.get_app_config('oscar').urls[0])),
]
In the code above, line with boutique_dashboard
URL configuration is temporarily commented out and will be turned on when Oscar's dashboard app is forked.
Models for “boutique” app
Create the following model that will represent a single boutique with three fields.
from django.db import modelsclass Boutique(models.Model):
name = models.CharField(max_length=255, blank=True, null=True)
manager = models.CharField(max_length=150, blank=True, null=True)
city = models.CharField(max_length=150, blank=True, null=True)class Meta:
app_label = 'boutique'
App configs for “boutique” app
While usual Django app’s config class in apps.py
inherits Django's default django.apps.AppConfig
class, Oscar app's must inherit oscar.core.application.OscarConfig
instead. Your apps.py
should look like this:
from oscar.core.application import OscarConfig
from django.urls import path, re_path
from oscar.core.loading import get_classclass BoutiqueConfig(OscarConfig):
name = 'boutique'
namespace = 'boutique'def ready(self):
super().ready()
self.boutique_list_view = get_class(
'boutique.views', 'BoutiqueListView')
self.boutique_detail_view = get_class(
'boutique.views', 'BoutiqueDetailView')def get_urls(self):
urls = super().get_urls()
urls += [
path('', self.boutique_list_view.as_view(), name='index'),
re_path(r'^view/(?P<pk>\d+)/$',
self.boutique_detail_view.as_view(), name='details'),
]
return self.post_process_urls(urls)
It is optional to use get_class
and get_model
when developing your own app but required when overriding Oscar apps. However, I prefer using Oscar's approach in all cases as I previously encountered various errors when importing modules using import
statement.
Admin for “boutique” app
This step is optional and Oscar’s dashboard is sufficient to add, modify and remove Boutique
elements to the database. However, for early testing let's register our model in Django's admin. Add the following code to the admin.py
in the app's directory.
from django.contrib import admin
from oscar.core.loading import get_modelBoutique = get_model('boutique', 'Boutique')class BoutiqueAdmin(admin.ModelAdmin):
passadmin.site.register(Boutique, BoutiqueAdmin)
Now that the model is registered in Django’s admin, go on and add few items for testing.
To access Django’s admin you will need to create a super user using command
python manage.py createsuperuser
Views for “boutique” app
There is nothing special in the implementation of views that will deliver context to the front pages. Following is a working views.py
based on Django's generic class-based views.
from django.views import generic
from oscar.core.loading import get_modelBoutique = get_model('boutique', 'Boutique')class BoutiqueListView(generic.ListView):
model = Boutique
template_name = 'boutique/boutique_list.html'
context_object_name = 'boutique_list'class BoutiqueDetailView(generic.DetailView):
model = Boutique
template_name = 'boutique/boutique_details.html'
context_object_name = 'boutique'
Front-end templates for “boutique” views
First and foremost, let’s override Oscar’s navigation template by adding a URL to our BoutiqueListView
. First, create a directory called oscar
in in /src/templates
directory. Any template file with the same relative path Oscar's templates from source code will be overridden by Oscar and become a higher priority template. Because Oscar is developed in a very smart and customizable way, it is very easy to add an element to the original Oscar template navigation. The original template HTML file from Oscar's source code can be found in /templates/oscar/partials/nav_primary.html
. Accordingly, we need to create a file oscar/partials/nav_primary.html
that will contain the following code:
{% extends "oscar/partials/nav_primary.html" %}
{% load i18n %}{% block nav_items %}
{{ block.super }}
<li class="nav-item dropdown">
<a class="nav-link" href="#" role="button">
{% trans "Boutiques" %}
</a>
</li>
{% endblock %}
In the code above, we first extend the original Oscar’s template. Then we override the block nav_items
by adding new elements to Oscar's default front-end navigation. After restarting the server, the following front should show up:
Template for list of boutiques
Previously we created a view BoutiqueListView
, which is responsible for delivering the context with a list of Boutique
instances to the template boutique/boutique_list.html
. Therefore, we first create an HTML file /src/templates/boutique/boutique_list.html
. Notice that this template file is not placed under /src/templates/oscar
the directory. This is because we do not override Oscar's template and merely creating a new custom template. However, in our case, it does extend the default Oscar layout template as shown:
{% extends "oscar/layout.html" %}{% load i18n %}
{% load product_tags %}{% block title %}
{% trans "Boutiques" %} | {{ block.super }}
{% endblock %}{% block breadcrumbs %}
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a href="{{ homepage_url }}">{% trans "Home" %}</a>
</li>
<li class="breadcrumb-item active" aria-current="page">{% trans "Boutiques" %}</li>
</ol>
</nav>
{% endblock %}{% block headertext %}
{% trans "Boutique" %}
{% endblock %}{% block content %}
{% if not boutique_list %}
<p>{% trans "There are no boutique at the moment." %}</p>
{% else %}
{% for boutique in boutique_list %}
<p>
<h2><a href="{% url 'boutique:details' boutique.pk %}">{{ boutique.name }}</a></h2>
The boutique is in: {{ boutique.city }}
</p> <hr/>
{% endfor %}
{% endif %}
{% endblock content %}
The result should look like this:
Template for boutique details
Now that we have a page with a list of our boutique elements let’s add a page where users can view details of any given boutique. Similarly to the listing template, let’s create a new HTML file /src/templates/boutique/boutique_details.html
with the following code:
{% extends "oscar/layout.html" %}{% load i18n %}
{% load product_tags %}{% block title %}
{% trans "Boutiques" %} | {{ block.super }}
{% endblock %}{% block breadcrumbs %}
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a href="{{ homepage_url }}">{% trans "Home" %}</a>
</li>
<li class="breadcrumb-item" aria-current="page">
<a href="{% url 'boutique:index' %}">{% trans "Boutiques" %}</a>
</li>
<li class="breadcrumb-item active" aria-current="page">{{ boutique.name }}</li>
</ol>
</nav>
{% endblock %}{% block headertext %}
{% trans "Boutique" %}
{% endblock %}{% block content %}
<p>
<h2>{{ boutique.name }}</h2> <br>
The boutique is in: {{ boutique.city }} <br>
The boutique's manager is Mr/Mrs: <strong>{{ boutique.manager }} </strong>
</p>
{% endblock content %}
The result should look like this:
At this point the app’s model, configs, and front-end templates are ready. In the next tutorial, we will develop an Oscar dashboard for the boutique
app.
Originally published at https://mmtechslv.com on March 16, 2021.