Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Now that we've created models for the [LocalLibrary](/en-US/docs/Learn_web_devel

The Django admin _application_ can use your models to automatically build a site area that you can use to create, view, update, and delete records. This can save you a lot of time during development, making it very easy to test your models and get a feel for whether you have the _right_ data. The admin application can also be useful for managing data in production, depending on the type of website. The Django project recommends it only for internal data management (i.e., just for use by admins, or people internal to your organization), as the model-centric approach is not necessarily the best possible interface for all users, and exposes a lot of unnecessary detail about the models.

All the configuration required to include the admin application in your website was done automatically when you [created the skeleton project](/en-US/docs/Learn_web_development/Extensions/Server-side/Django/skeleton_website) (for information about actual dependencies needed, see the [Django docs here](https://docs.djangoproject.com/en/5.0/ref/contrib/admin/)). As a result, all you **must** do to add your models to the admin application is to _register_ them. At the end of this article we'll provide a brief demonstration of how you might further configure the admin area to better display our model data.
All the configuration required to include the admin application in your website was done automatically when you [created the skeleton project](/en-US/docs/Learn_web_development/Extensions/Server-side/Django/skeleton_website) (for information about actual dependencies needed, see the [Django docs here](https://docs.djangoproject.com/en/6.1/ref/contrib/admin/)). As a result, all you **must** do to add your models to the admin application is to _register_ them. At the end of this article we'll provide a brief demonstration of how you might further configure the admin area to better display our model data.

After registering the models we'll show how to create a new "superuser", login to the site, and create some books, authors, book instances, and genres. These will be useful for testing the views and templates we'll start creating in the next tutorial.

Expand Down Expand Up @@ -141,11 +141,11 @@ You can further customize the interface to make it even easier to use. Some of t

In this section we're going to look at a few changes that will improve the interface for our _LocalLibrary_, including adding more information to `Book` and `Author` model lists, and improving the layout of their edit views. We won't change the `Language` and `Genre` model presentation because they only have one field each, so there is no real benefit in doing so!

You can find a complete reference of all the admin site customization choices in [The Django Admin site](https://docs.djangoproject.com/en/5.0/ref/contrib/admin/) (Django Docs).
You can find a complete reference of all the admin site customization choices in [The Django Admin site](https://docs.djangoproject.com/en/6.1/ref/contrib/admin/) (Django Docs).

### Register a ModelAdmin class

To change how a model is displayed in the admin interface you define a [ModelAdmin](https://docs.djangoproject.com/en/5.0/ref/contrib/admin/#modeladmin-objects) class (which describes the layout) and register it with the model.
To change how a model is displayed in the admin interface you define a [ModelAdmin](https://docs.djangoproject.com/en/6.1/ref/contrib/admin/#modeladmin-objects) class (which describes the layout) and register it with the model.

Let's start with the `Author` model. Open **admin.py** in the catalog application (**/django-locallibrary-tutorial/catalog/admin.py**). Comment out your original registration (prefix it with a #) for the `Author` model:

Expand Down Expand Up @@ -189,7 +189,7 @@ Currently all of our admin classes are empty (see `pass`) so the admin behavior

### Configure list views

The _LocalLibrary_ currently lists all authors using the object name generated from the model `__str__()` method. This is fine when you only have a few authors, but once you have many you may end up having duplicates. To differentiate them, or just because you want to show more interesting information about each author, you can use [list_display](https://docs.djangoproject.com/en/5.0/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_display) to add additional fields to the view.
The _LocalLibrary_ currently lists all authors using the object name generated from the model `__str__()` method. This is fine when you only have a few authors, but once you have many you may end up having duplicates. To differentiate them, or just because you want to show more interesting information about each author, you can use [list_display](https://docs.djangoproject.com/en/6.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_display) to add additional fields to the view.

Replace your `AuthorAdmin` class with the code below. The field names to be displayed in the list are declared in a _tuple_ in the required order, as shown (these are the same names as specified in your original model).

Expand Down Expand Up @@ -277,7 +277,7 @@ In your website go to the author detail view — it should now appear as shown b

#### Sectioning the detail view

You can add "sections" to group related model information within the detail form, using the [fieldsets](https://docs.djangoproject.com/en/5.0/ref/contrib/admin/#django.contrib.admin.ModelAdmin.fieldsets) attribute.
You can add "sections" to group related model information within the detail form, using the [fieldsets](https://docs.djangoproject.com/en/6.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.fieldsets) attribute.

In the `BookInstance` model we have information related to what the book is (i.e., `name`, `imprint`, and `id`) and when it will be available (`status`, `due_back`). We can add these to our `BookInstanceAdmin` class as shown below, using the `fieldsets` property.

Expand Down Expand Up @@ -306,7 +306,7 @@ Now navigate to a book instance view in your website; the form should appear as

Sometimes it can make sense to be able to add associated records at the same time. For example, it may make sense to have both the book information and information about the specific copies you've got on the same detail page.

You can do this by declaring [inlines](https://docs.djangoproject.com/en/5.0/ref/contrib/admin/#django.contrib.admin.ModelAdmin.inlines), of type [TabularInline](https://docs.djangoproject.com/en/5.0/ref/contrib/admin/#django.contrib.admin.TabularInline) (horizontal layout) or [StackedInline](https://docs.djangoproject.com/en/5.0/ref/contrib/admin/#django.contrib.admin.StackedInline) (vertical layout, just like the default model layout). You can add the `BookInstance` information inline to our `Book` detail by specifying `inlines` in your `BookAdmin`:
You can do this by declaring [inlines](https://docs.djangoproject.com/en/6.1/ref/contrib/admin/#django.contrib.admin.ModelAdmin.inlines), of type [TabularInline](https://docs.djangoproject.com/en/6.1/ref/contrib/admin/#django.contrib.admin.TabularInline) (horizontal layout) or [StackedInline](https://docs.djangoproject.com/en/6.1/ref/contrib/admin/#django.contrib.admin.StackedInline) (vertical layout, just like the default model layout). You can add the `BookInstance` information inline to our `Book` detail by specifying `inlines` in your `BookAdmin`:

```python
class BooksInstanceInline(admin.TabularInline):
Expand All @@ -323,7 +323,7 @@ Now navigate to a view for a `Book` in your website — at the bottom you should

![Admin Site - Book with Inlines](admin_improved_book_detail_inlines.png)

In this case all we've done is declare our tabular inline class, which just adds all fields from the _inlined_ model. You can specify all sorts of additional information for the layout, including the fields to display, their order, whether they are read only or not, etc. (see [TabularInline](https://docs.djangoproject.com/en/5.0/ref/contrib/admin/#django.contrib.admin.TabularInline) for more information).
In this case all we've done is declare our tabular inline class, which just adds all fields from the _inlined_ model. You can specify all sorts of additional information for the layout, including the fields to display, their order, whether they are read only or not, etc. (see [TabularInline](https://docs.djangoproject.com/en/6.1/ref/contrib/admin/#django.contrib.admin.TabularInline) for more information).

> [!NOTE]
> There are some painful limits in this functionality! In the screenshot above we have three existing book instances, followed by three placeholders for new book instances (which look very similar!). It would be better to have NO spare book instances by default and just add them with the **Add another Book instance** link, or to be able to just list the `BookInstance`s as non-readable links from here. The first option can be done by setting the `extra` attribute to `0` in `BooksInstanceInline` model, try it by yourself.
Expand All @@ -341,7 +341,7 @@ That's it! You've now learned how to set up the administration site in both its

## Further reading

- [Writing your first Django app, part 2: Introducing the Django Admin](https://docs.djangoproject.com/en/5.0/intro/tutorial02/#introducing-the-django-admin) (Django docs)
- [The Django Admin site](https://docs.djangoproject.com/en/5.0/ref/contrib/admin/) (Django Docs)
- [Writing your first Django app, part 2: Introducing the Django Admin](https://docs.djangoproject.com/en/6.1/intro/tutorial02/#introducing-the-django-admin) (Django docs)
- [The Django Admin site](https://docs.djangoproject.com/en/6.1/ref/contrib/admin/) (Django Docs)

{{PreviousMenuNext("Learn_web_development/Extensions/Server-side/Django/Models", "Learn_web_development/Extensions/Server-side/Django/Home_page", "Learn_web_development/Extensions/Server-side/Django")}}
Original file line number Diff line number Diff line change
Expand Up @@ -419,13 +419,17 @@ You'll be able to test the password reset functionality from the link in the log
Note that you won't be able to test account logout yet, because logout requests must be sent as a `POST` rather than a `GET` request.

> [!NOTE]
> The password reset system requires that your website supports email, which is beyond the scope of this article, so this part **won't work yet**. To allow testing, put the following line at the end of your settings.py file. This logs any emails sent to the console (so you can copy the password reset link from the console).
> The password reset system requires that your website supports email, which is beyond the scope of this article, so this part **won't work yet**. To allow testing, put the following lines at the end of your settings.py file. This logs any emails sent to the console (so you can copy the password reset link from the console).
>
> ```python
> EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
> MAILERS = {
> 'default': {
> 'BACKEND': 'django.core.mail.backends.console.EmailBackend',
> },
> }
> ```
>
> For more information, see [Sending email](https://docs.djangoproject.com/en/5.0/topics/email/) (Django docs).
> For more information, see [Sending email](https://docs.djangoproject.com/en/6.1/topics/email/) (Django docs).

## Testing against authenticated users

Expand Down Expand Up @@ -626,12 +630,12 @@ class LoanedBooksByUserListView(LoginRequiredMixin,generic.ListView):
def get_queryset(self):
return (
BookInstance.objects.filter(borrower=self.request.user)
.filter(status__exact='o')
.filter(status__exact=BookInstance.LoanStatus.ON_LOAN)
.order_by('due_back')
)
```

In order to restrict our query to just the `BookInstance` objects for the current user, we re-implement `get_queryset()` as shown above. Note that "o" is the stored code for "on loan" and we order by the `due_back` date so that the oldest items are displayed first.
In order to restrict our query to just the `BookInstance` objects for the current user, we re-implement `get_queryset()` as shown above. Note that `BookInstance.LoanStatus.ON_LOAN` is the stored code for "on loan" and we order by the `due_back` date so that the oldest items are displayed first.

### URL conf for on loan books

Expand Down
Loading