In the previous part of the series we created the model classes for the Portfolio website. In this part we’ll feed some data to the database and talk about the admin site in general.
Table of Contents
What is the Admin Site?
The admin site is actually an application that we get out of the box when we create a Django website. It’s used to let us easily perform operations like creating, reading (viewing), updating and deleting records, so the typical CRUD operations. We’re going to use it to create the first instances of our models and then to perform the other operations on them. The admin site can be used in both development and production, in the letter mainly for our internal purposes, though. What I mean by that is that it’s not meant to be used by the final user of the app, because it’s too tightly coupled with the programmatic aspect of the application the user may not be acquainted with, but rather by the developers themselves. But it’s not a strict rule that must be obeyed at all times.
In order to use the admin site, there’s a couple things we have to take care of. First of all, we have to register the models we want to use. Next, we have to create a superuser and log in to the site. Once we’re done with that, we’ll be able to create the first instances of projects, categories and the other models.
Registering Models
There are currently four models in our website. Let’s register them now. The right place to do it is the admin.py file inside the catalog folder. Open the file and make sure it looks like this:
from django.contrib import admin
from .models import Category, Technology, Project, Link
admin.site.register(Category)
admin.site.register(Technology)
admin.site.register(Project)
admin.site.register(Link)
That’s it. Our models have been registered. Next, let’s create a superuser.
Superuser
We need to add a new superuser to the database in order to be able to log into the admin site. The superuser will have the permissions to manage all the objects. To create a new superuser, make sure you’re in the same directory as the manage.py file and run the following command:
python manage.py createsuperuser
You will need to enter some data in order to create the superuser, like username, email address and password. Speaking of the password, remember to make it at least 8 characters long. Otherwise, you’ll get a warning message. While you type in the password, you won’t see anything on your screen. The whole process of creating the superuser might look like so (provided you first enter a password that is too short):
PS D:\Projects\django_portfolio\portfolio> python manage.py createsuperuser
Username (leave blank to use 'pc'): prospero
Email address: p...s@gmail.com
Password:
Password (again):
This password is too short. It must contain at least 8 characters.
Bypass password validation and create user anyway? [y/N]: N
Password:
Password (again):
Superuser created successfully.
Once the superuser is added to the database, let’s restart the server:
python manage.py runserver
and enter the following address in the address bar of the browser:
http://localhost:8000/admin
We should now see the login site from which you can log into the admin site:
Enter the username and password you just created and log in:
Overview of the Admin Site
In the admin, site we can see all groups and users in the Authentication and Authorization section. We’ll talk in more detail about this section later on.
Below we can see all our models displayed by application. As we have only one application, catalog, that’s all we see.
If you click on one of the model names, you’ll navigate to the page where all records of that model are listed. Let’s click on Projects, for example:
We don’t have any records yet, so it says 0 projects, but we’ll start adding some records in a moment. Here we have also options to add new records of the Project type. Alternatively, we can add new records directly from the previous page:
Now that we know how to add new records, let’s actually add some. To start simple, let’s add some categories first.
Adding Categories
Let’s click on the Add button to add a new category:
In the page that opens fill in the data. The first category’s name is Web Projects (A) and the icon’s name is bi bi-globe (B). Don’t worry if the icon name doesn’t mean anything to you. It’s just a string used to identify the icon. Technically, it’s a Bootstrap Icons class. Next hit the Save and add another button (C) to add the other categories:
You’ll see a message after you successfully save a new category:
Here’s the full list of categories for our project:
Name | Icon |
Web Projects | bi bi-globe |
Games | bi bi-controller |
Desktop/Mobile Projects | bi bi-window-desktop |
Machine Learning Projects | bi bi-diagram-3 |
Blender Projects | bi bi-box |
Books | bi bi-book-half |
Magazines | bi bi-layout-text-window |
Online Courses | bi bi-easel |
Articles and Article Series | bi bi-body-text |
Videos and Video Series | bi bi-play-btn |
English | bi bi-people |
After you enter the data for the last category, hit the SAVE button instead of the Save and add another one. You will now see all the categories you added:
Next, let’s add the technologies.
Adding Technologies
Just like we added the categories, we can add the technologies. Here’s the list of all the technologies we’re going to need:
Name | Icon |
Python | devicon-python-plain |
Pandas | devicon-pandas-plain colored |
NumPy | devicon-numpy-plain colored |
matplotlib | devicon-matplotlib-plain colored |
PyTorch | devicon-pytorch-original colored |
scikit-learn | devicon-scikitlearn-plain colored |
TensorFlow | devicon-tensorflow-original colored |
SQLite | devicon-sqlite-plain colored |
Flask | devicon-flask-original colored |
Django | devicon-django-plain colored |
Blender | devicon-blender-original |
HTML | devicon-html5-plain |
CSS | devicon-css3-plain |
Bootstrap | devicon-bootstrap-plain |
JavaScript | devicon-javascript-plain |
Unity | devicon-unity-original |
C# | devicon-csharp-plain |
.NET | devicon-dotnetcore-plain |
English | bi bi-people |
Adding Projects
Projects are the meat of our app. There are way more fields to fill in. Let’s start with my Slug Race game that I made with Python and Kivy:
In the exact same way, I’ll add all my other projects. You can add yours, but if you want to follow along and use my projects instead, feel free to do so. You will find the images folder on Github, so just save it locally on your machine and select the respective image for each project. In the tables below, you can see the data related to the projects:
Slug Race
Name | Slug Race |
Description | A 2D game made with Python and Kivy. It can be played by up to four players. Each player places a bet on one of four racing slugs and they either win or lose money. The game is over when there’s only one player left with any money, but you can set a different ending condition in the settings screen too, like after a given number of races or after a set period of time. |
Image | Slugrace.png |
Date of Creation | 2022-01-25 |
Category | Games |
Technologies | Python |
Forest Monsters
Name | Forest Monsters |
Description | A 2D game made with Unity with C# scripting. Your task is to save the enchanted forest from a bad sorcerer. You have to kill lots of monsters on your way. This is a typical platformer game. You jump from platform to platform, collect items, shoot monsters, avoid bombs and poison, move toward the door to the next level. Some of the platforms can move, which makes the game more difficult. |
Image | Forest Monsters.png |
Date of Creation | 2024-01-20 |
Category | Games |
Technologies | C#, Unity |
Extreme Vacation
Name | Extreme Vacation |
Description | A portal that I made just for fun. You can use it to book your extreme vacation like in a burning city or sharing a den with a bear. The project is hosted in Azure, the backend was created using the ASP.NET Core Web API template and the frontend was made with Blazor WebAssembly. The data is stored in a SQL Server database. I used Entity Framework Core as the ORM. |
Image | extreme-vacation.png |
Date of Creation | 2024-02-22 |
Category | Web Projects |
Technologies | C#, .NET, HTML, CSS, Bootstrap |
CV Project
Name | CV Project |
Description | This is my first React project. In this app you can fill in a form with your personal information (like name, address, experience and education) to create a CV. You can also upload a photo. There’s also a live preview of the CV, so whatever you type in the form is instantly visualized in the preview on the right. |
Image | cv-project.png |
Date of Creation | 2023-10-15 |
Category | Web Projects |
Technologies | JavaScript, HTML, CSS |
Waldo
Name | Waldo |
Description | This is a simple version of the popular Where Is Waldo game where you have to find Waldo and some other characters in the image. This isn’t easy because there are a great number of characters in the image. If you find all three characters in an image, just try another image. There are three images to choose from. This project uses Firebase as the backend. |
Image | waldo.png |
Date of Creation | 2023-11-12 |
Category | Web Projects |
Technologies | JavaScript, HTML, CSS |
Arched Cellar
Name | Arched Cellar |
Description | A low-poly cellar model with simple texturing. You can import it in Unity or any other game engine and use as an environment for your project. |
Image | Arched Cellar.jpg |
Date of Creation | 2018-09-17 |
Category | Blender Projects |
Technologies | Blender |
Bacteria
Name | Bacteria |
Description | Bacteria as seen under an electron microscope. When you use an electron microscope, the object you watch is no longer alive, so the bacteria is not going to be animated. I also have a blog post where you can see how this model was built. |
Image | Bacteria.png |
Date of Creation | 2021-12-20 |
Category | Blender Projects |
Technologies | Blender |
Town Houses
Name | Town Houses |
Description | Five low-poly models of town houses, ready to export to Unity or any other game engine. The models are fully textured. |
Image | Town Houses.png |
Date of Creation | 2023-12-02 |
Category | Blender Projects |
Technologies | Blender |
Tunnel Animation
Name | Tunnel Animation |
Description | A simple first-person-perspective animated journey through a tunnel – a tunnel animation using the follow path constraint, in which the camera will move along a path inside a tunnel. |
Image | Tunnel.jpg |
Date of Creation | 2020-06-08 |
Category | Blender Projects |
Technologies | Blender |
GUI Programming with Python and Kivy
Name | GUI Programming with Python and Kivy |
Description | This is a book for Python developers who want to create GUI apps using this language. One option is to use the Kivy library. In the book a game project is created from scratch. |
Image | Kivy Book.png |
Date of Creation | 2021-12-20 |
Category | Books |
Technologies | Python |
Learn Over 400 Phrasal Verbs the Fun Way
Name | Learn Over 400 Phrasal Verbs the Fun Way |
Description | In this book you will learn over 400 hundred phrasal verbs. Phrasal verbs are verbs that consist of two parts, the actual verb and a particle, like ‘stand up’, ‘get off’ or ‘turn down’, to mention just a few. |
Image | Phrasal Verbs Book.png |
Date of Creation | 2022-01-16 |
Category | Books |
Technologies | English |
Python Jumpstart Course
Name | Python Jumpstart Course |
Description | A Python course for absolute beginners. Lots of examples, exercises and projects for you to do. Includes the object-oriented programming paradigm. |
Image | Python Jumpstart Course.png |
Date of Creation | 2019-11-30 |
Category | Online Courses |
Technologies | Python |
Your Panda3D Magazine
Name | Your Panda3D Magazine |
Description | This is the first (and so far only) issue of a magazine focused on game development with Python and the Panda3D game engine. There’s also quite a lot stuff related to 3D modeling with Blender. |
Image | Your Panda3D Magazine.png |
Date of Creation | 2022-02-11 |
Category | Magazines |
Technologies | Python |
Your American English Magazine
Name | Your American English Magazine |
Description | This is the first issue of Your American English Magazine. There’s quite a lot of stuff in it for you that you can use to improve your English, both grammar and vocabulary. Plus some American culture. |
Image | Your American English Magazine.png |
Date of Creation | 2022-02-14 |
Category | Magazines |
Technologies | English |
Adding Links
Finally, let’s add the links. Here, we have to fill in the name, icon and address, but also select the project the link belongs to.
Have a look at this example:
Here are the links to add:
Project: Slug Race
1)
Name | Github |
Icon | devicon-github-original |
Address | https://github.com/prospero-apps/slugraceKivy |
2)
Name | YouTube |
Icon | fa-brands fa-youtube |
Address | https://www.youtube.com/watch?v=z24eIFsbEl8 |
3)
Name | Prospero Coder Blog |
Icon | fa-solid fa-blog |
Address | https://prosperocoder.com/blog/posts/kivy/ |
Project: Forest Monsters
1)
Name | Github |
Icon | devicon-github-original |
Address | https://github.com/prospero-apps/forest-monsters |
2)
Name | YouTube |
Icon | fa-brands fa-youtube |
Address | https://youtu.be/i7xyMbhdg_8 |
3)
Name | Download |
Icon | fa-solid fa-download |
Address | https://prosperocoder.itch.io/forest-monsters |
Project: Extreme Vacation
1)
Name | Github |
Icon | devicon-github-original |
Address | https://github.com/prospero-apps/ExtremeVacation |
Project: CV Project
1)
Name | Github |
Icon | devicon-github-original |
Address | https://github.com/prospero-apps/cv-project |
2)
Name | Live |
Icon | fa-solid fa-rocket |
Address | https://prospero-apps.github.io/cv-project |
Project: Waldo
1)
Name | Github |
Icon | devicon-github-original |
Address | https://github.com/prospero-apps/waldo |
2)
Name | Live |
Icon | fa-solid fa-rocket |
Address | https://prospero-apps.github.io/waldo/ |
Project: Arched Cellar
1)
Name | Github |
Icon | devicon-github-original |
Address | https://github.com/prospero-apps/blender/tree/master/blend%20files |
Project: Bacteria
1)
Name | Github |
Icon | devicon-github-original |
Address | https://github.com/prospero-apps/blender/tree/master/blend%20files |
2)
Name | Prospero Coder Blog |
Icon | fa-solid fa-blog |
Address | https://prosperocoder.com/posts/blender/bacteria-model-under-electron-microscope |
Project: Town Houses
1)
Name | Github |
Icon | devicon-github-original |
Address | https://github.com/prospero-apps/blender/tree/master/blend%20files/Town%20Houses |
Project: Tunnel Animation
1)
Name | Github |
Icon | devicon-github-original |
Address | https://github.com/prospero-apps/blender/tree/master/blend%20files |
2)
Name | YouTube |
Icon | fa-brands fa-youtube |
Address | https://youtu.be/SPVJAwIuqJs |
3)
Name | Prospero Coder Blog |
Icon | fa-solid fa-blog |
Address | https://prosperocoder.com/posts/blender/tunnel-animation-follow-path-constraint |
Project: GUI Programming with Python and Kivy
1)
Name | Github |
Icon | devicon-github-original |
Address | https://github.com/prospero-apps/python/tree/master/GUI%20Programming%20with%20Python%20and%20Kivy%20BOOK |
2)
Name | YouTube |
Icon | fa-brands fa-youtube |
Address | https://youtu.be/3W8zDYMBoDk |
3)
Name | Prospero Coder Blog |
Icon | fa-solid fa-blog |
Address | https://prosperocoder.com/posts/kivy/my-gui-programming-with-python-and-kivy-book |
4)
Name | Amazon |
Icon | fa-brands fa-amazon |
Address | https://www.amazon.com/Programming-Python-Kivy-Kamil-Pakula/dp/B09M9CYRCX/ref=asc_df_B09M9CYRCX/?tag=hyprod-20&linkCode=df0&hvadid=564675582183&hvpos=&hvnetw=g&hvrand=10679525743492153029&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=1014434&hvtargid=pla-1595705564143&psc=1 |
5)
Name | Prospero Coder Store |
Icon | fa-solid fa-cart-shopping |
Address | https://prosperocoder.com/product/gui-programming-with-python-and-kivy-e-book |
6)
Name | TutorialsPoint |
Icon | fa-solid fa-globe |
Address | https://www.tutorialspoint.com/ebook/gui-programming-with-python-and-kivy/index.asp |
Project: Learn Over 400 Phrasal Verbs the Fun Way
1)
Name | YouTube |
Icon | fa-brands fa-youtube |
Address | https://youtu.be/yCFe0nKw8JM |
2)
Name | Prospero English Blog |
Icon | fa-solid fa-blog |
Address | https://prosperoenglish.com/posts/my-learn-over-400-phrasal-verbs-book |
3)
Name | Amazon |
Icon | fa-brands fa-amazon |
Address | https://www.amazon.com/-/es/Kamil-Pakula/dp/B09RM5XFLS |
4)
Name | Prospero English Store |
Icon | fa-solid fa-cart-shopping |
Address | https://prosperoenglish.com/product/learn-over-400-phrasal-verbs-the-fun-way |
Project: Python Jumpstart Course
1)
Name | Udemy |
Icon | fa-solid fa-globe |
Address | https://www.udemy.com/course/python-jumpstart-course/ |
2)
Name | TutorialsPoint |
Icon | fa-solid fa-globe |
Address | https://www.tutorialspoint.com/python-jumpstart-course/index.asp |
Project: Your Panda3D Magazine
1)
Name | YouTube |
Icon | fa-brands fa-youtube |
Address | https://youtu.be/N9_rrQXIuuo |
2)
Name | Prospero Coder Blog |
Icon | fa-solid fa-blog |
Address | https://prosperocoder.com/posts/your-panda3d-magazine-issue-1-2022-1 |
3)
Name | Amazon |
Icon | fa-brands fa-amazon |
Address | https://www.amazon.com/Your-Panda3D-Magazine-Kamil-Pakula-ebook/dp/B09SR785WV |
4)
Name | Prospero Coder Store |
Icon | fa-solid fa-cart-shopping |
Address | https://prosperocoder.com/product/your-panda3d-magazine-1-1-2022 |
Project: Your American English Magazine
1)
Name | YouTube |
Icon | fa-brands fa-youtube |
Address | https://youtu.be/XGlzwmBcsyY |
2)
Name | Prospero English Blog |
Icon | fa-solid fa-blog |
Address | https://prosperoenglish.com/posts/your-american-english-magazine-issue-1-2022-1 |
3)
Name | Amazon |
Icon | fa-brands fa-amazon |
Address | https://www.amazon.com/Your-American-English-Magazine-2022-ebook/dp/B09SQCZVF1 |
4)
Name | Prospero English Store |
Icon | fa-solid fa-cart-shopping |
Address | https://prosperoenglish.com/product/your-american-english-magazine-1-1-2022 |
If you now display all the links, they don’t look great:
It’s impossible to say which project each of them links to. We’ll make it more practical in a moment.
Updating and Deleting Objects
Now that we’ve entered all the projects, categories, technologies and links, we can easily edit (or update, in other words) them if need arises. To do that, we just click on the item we want to edit and a page will be displayed that looks almost the same as the page where we were creating them. This time, however, the title will read Change project (or category, etc.) instead of Add project, etc.:
Deleting items is easy, too. Let’s say we want to delete one or more of our projects. All we have to do is check the check box next to each of them, select Delete selected projects from the Action drop-down and hit the Go button:
Our admin site looks pretty good, but we can still improve it. Let’s customize it a bit so that it better suits our needs.
The ModelAdmin Class
All the items we’ve added so far, including the projects, categories, technologies and links, are displayed as simple lists. While this is fine with categories and technologies, because these are very simple models, it’s a bit problematic with projects, in particular, if there are many of them. You can have duplicate project names, so it wouldn’t be a bad idea to display the projects not as a simple list, but rather as a list view with some more information.
It’s even more true about the links. We just saw how difficult it is to say which projects they belong to by just looking at their names.
This is why we’ll change the way the projects and links are displayed. In order to do that, we have to define special classes that determine the way the models are displayed. They inherit from the ModelAdmin
class. The classes have to be then registered with the model.
So, let’s add the two classes in the admin.py file:
from django.contrib import admin
from .models import Category, Technology, Project, Link
class ProjectAdmin(admin.ModelAdmin):
pass
class LinkAdmin(admin.ModelAdmin):
pass
admin.site.register(Category)
admin.site.register(Technology)
admin.site.register(Project, ProjectAdmin)
admin.site.register(Link, LinkAdmin)
In the last two lines we’ve modified the registrations by adding the new classes as the second argument. These classes are now empty, but we’ll be gradually filling them in as we proceed.
List Views
Let’s start with the projects.
The Projects List View
Let’s say, apart from the name of each project, we want to display the date of creation, the category and the technologies. We just have to pass the names of the fields to the list_display
tuple in the order we want them to be displayed:
class ProjectAdmin(admin.ModelAdmin):
list_display = ('name', 'date_added', 'category', 'display_technologies')
As you can see, it’s different for the technologies
field. We can’t put it directly in the tuple because it’s a ManyToManyField
and it would be too costly in terms of database access. This is why it’s not allowed in Django. Instead, we pass a method that we have yet to define in the model class, display_technologies
. Here it is:
class Project(models.Model):
...
def get_absolute_url(self):
...
def display_technologies(self):
"""Create a string for the technologies in the admin site."""
return ', '.join(technology.name for technology in self.technologies.all())
display_technologies.short_description = 'technologies'
class Link(models.Model):
...
The string will just consist of all the names of the technologies separated by commas. We set short_description
to whatever we want to be displayed in the header.
This is how the projects are displayed now:
The Links List View
Next, in a similar way, let’s change the way the links are displayed. Besides the name of the link, it would be desirable to also display the project name, maybe even in the first position, followed by the project’s category and the name of the link in all uppercase to stand out.
This time, though, we’re going to display everything as a single string in one column. In order to do that, we’ll pass a method to list_display
and define it in the model class.
class LinkAdmin(admin.ModelAdmin):
list_display = ('display_link',)
We must pass a tuple to list_display
, hence the comma at the end.
In the model class, we have to define the method:
class Link(models.Model):
...
def __str__(self):
...
def display_link(self):
"""Create a string for the link in the admin site."""
return f'{self.project} ({self.project.category}) - {self.name.upper()}'
display_link.short_description = 'link'
The links are now displayed in a much more readable way:
List Filters
The projects and links lists are now much more readable than before, but it may be still difficult to view them when they grow to tens or even hundreds of items. Fortunately, we can easily add some filtering functionality to them. We do it by adding the fields we want to be able to filter by to the list_filter
tuple.
Let’s start with the links. We want to be able to filter them by name. Here’s the LinkAdmin
class:
class LinkAdmin(admin.ModelAdmin):
list_display = ('display_link',)
list_filter = ('name',)
That’s it. Now, there is a filter box to the right where we can select our filtering criteria:
By clicking on the eye icon near the top, we can display the number of items in each category:
Let’s say we only want to see the links to Github. All we have to do is click on Github in the filter box:
All other links have been filtered out.
Next, let’s implement some filtering for the projects:
class ProjectAdmin(admin.ModelAdmin):
list_display = ('name', 'date_added', 'category', 'display_technologies')
list_filter = ('category', 'date_added', 'technologies')
Filtering by category, date of creation and technology will do:
This is it, as far as filtering is concerned.
Fields Layout
The detail views are by default laid out vertically, with all the fields in the order they are declared in the model. Have a look at the Project
detail view:
But if you want, you can change it. It’s up to you which fields should be displayed and in which order. To this end, we use the fields
list in the ModelAdmin
class, in which we put just the fields we want to be displayed and in the order we want them to be displayed in. If we want some of the fields to be displayed side by side, so horizontally, we just wrap them in a pair of parentheses.
Let’s say, we want to display the fields a bit differently. date_added
should precede and be on the same line as image. Here’s how to do that:
class ProjectAdmin(admin.ModelAdmin):
list_display = ('name', 'date_added', 'category', 'display_technologies')
list_filter = ('category', 'date_added', 'technologies')
fields = ['name', 'description', ('date_added', 'image'), 'category', 'technologies']
Now the detail view looks like so:
Inlines
Now, when we add a project, we have to navigate to another view to add the links related to it. Wouldn’t it be more comfortable to add the links on the same page as the project itself? It sure would. And it’s not difficult to do. We just have to add the Add Link form as an inline to the Project detail view.
If we want a horizontal inline, we define a class that inherits from admin.TabularInline
. If we need a vertical inline, the class must inherit from admin.StackedInline
. So, first we define the inline class or classes, and then we add them to the inlines
list in the ModelAdmin
class:
from django.contrib import admin
from .models import Category, Technology, Project, Link
class LinkInline(admin.StackedInline):
model = Link
class ProjectAdmin(admin.ModelAdmin):
...
fields = ['name', 'description', ('date_added', 'image'), 'category', 'technologies']
inlines = [LinkInline]
class LinkAdmin(admin.ModelAdmin):
...
You can now add the links directly while adding the project. The inline is displayed in the lower part of the view. There are a couple link forms to fill in, but you can use the close buttons on the right to remove them if you don’t need them. And the other way around, you can add more links by clicking the Add another Link button at the bottom:
If you open an existing project for edition, all related links will be displayed correctly:
Sections
Finally, if there are lots of elements in the detail view, we may consider creating one or more sections to group them. We use the fieldsets
attribute to do that. It’s a tuple of tuples, where each inner tuple represents one section. Each section contains the title of the section and a dictionary with the fields that will sit in that section. If we don’t need a title for a section, we set it to None.
For example, in the Project
detail view, we’ll create two sections, one for the name and description and the other one for the remaining fields. The second section will have the title Project Details. We can’t have both fields
and fieldsets
, though, so let’s comment out the former. Here’s the modified ProjectAdmin
class:
class ProjectAdmin(admin.ModelAdmin):
list_display = ('name', 'date_added', 'category', 'display_technologies')
list_filter = ('category', 'date_added', 'technologies')
#fields = ['name', 'description', ('date_added', 'image'), 'category', 'technologies']
inlines = [LinkInline]
fieldsets = (
(None, {
'fields': ('name', 'description')
}),
('Project Details', {
'fields': (('date_added', 'image'), 'category', 'technologies')
}),
)
Now we can see the two sections:
The first one doesn’t have a title, so it looks like before.
Now we have a pretty robust admin site that we can use to easily add, edit and delete categories, technologies, projects and links. In the next part of the series, we’ll create our views and templates.