pythondjangodjango-adminadminchangelist

How is my list_display and list_editable clashing?


When I started building this project, it went pretty smoothly. But when I reached the admin, list_display and list_editable clashed:

admin.py Code:

from django.contrib import admin
from .models import Article, Author

# Register your models here.
@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
    list_display = ['title', 'main_txt', 'date_of_publication']
    list_editable = ['title', 'main_txt']
    def __str__(self):
        return self.title
@admin.register(Author)
class AuthorAdmin(admin.ModelAdmin):
    list_display = ['first_name', 'last_name', 'join_date', 'email']
    def __str__(self):
        return f"{self.first_name} {self.last_name[0]}"

models.py:

from django.db import models

# Create your models here.

class Author(models.Model):
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)
    date_of_birth = models.DateField()
    email = models.CharField(max_length=300)
    phone_num = models.CharField(max_length=15)
    join_date = models.DateField()
    participated_art = models.ManyToManyField('Article', blank=True)


class Article(models.Model):
    title = models.CharField(max_length=500)
    date_of_publication = models.DateField()
    creaters = models.ManyToManyField('Author', blank=False)
    main_txt = models.TextField()
    notes = models.TextField()

Error Code:

Exception in thread Django-main-thread:
Traceback (most recent call last):
  File "C:\Users\Zhiyue\AppData\Local\Programs\Python\Python39\lib\threading.py", line 980, in _bootstrap_inner
    self.run()
  File "C:\Users\Zhiyue\AppData\Local\Programs\Python\Python39\lib\threading.py", line 917, in run
    self._target(*self._args, **self._kwargs)
  File "C:\Users\Zhiyue\PycharmProjects\djangoProject1\venv\lib\site-packages\django\utils\autoreload.py", line 64, in wrapper
    fn(*args, **kwargs)
  File "C:\Users\Zhiyue\PycharmProjects\djangoProject1\venv\lib\site-packages\django\core\management\commands\runserver.py", line 134, in inner_run
    self.check(display_num_errors=True)
  File "C:\Users\Zhiyue\PycharmProjects\djangoProject1\venv\lib\site-packages\django\core\management\base.py", line 546, in check
    raise SystemCheckError(msg)
django.core.management.base.SystemCheckError: SystemCheckError: System check identified some issues:

ERRORS:
<class 'CodeJangoHome.admin.ArticleAdmin'>: (admin.E124) The value of 'list_editable[0]' refers to the first field in 'list_display' ('title'), which cannot be used unless 'list_display_links' is set.

System check identified 1 issue (0 silenced).

After I read the error, as shown above, I tried adding list_display_links = ['title', 'main_txt'] into the code:

@admin.register(Article)
class ArticleAdmin(admin.ModelAdmin):
    list_display = ['title', 'main_txt', 'date_of_publication']
    list_editable = ['title', 'main_txt']
    def __str__(self):
        return self.title

But it didn't work out the way it was supposed to. I got another error, that was between list_display_links and list_editable:

Exception in thread django-main-thread:
Traceback (most recent call last):
  File "C:\Users\Zhiyue\AppData\Local\Programs\Python\Python39\lib\threading.py", line 980, in _bootstrap_inner
    self.run()
  File "C:\Users\Zhiyue\AppData\Local\Programs\Python\Python39\lib\threading.py", line 917, in run
    self._target(*self._args, **self._kwargs)
  File "C:\Users\Zhiyue\PycharmProjects\djangoProject1\venv\lib\site-packages\django\utils\autoreload.py", line 64, in wrapper
    fn(*args, **kwargs)
  File "C:\Users\Zhiyue\PycharmProjects\djangoProject1\venv\lib\site-packages\django\core\management\commands\runserver.py", line 134, in inner_run
    self.check(display_num_errors=True)
  File "C:\Users\Zhiyue\PycharmProjects\djangoProject1\venv\lib\site-packages\django\core\management\base.py", line 546, in check
    raise SystemCheckError(msg)
django.core.management.base.SystemCheckError: SystemCheckError: System check identified some issues:

ERRORS:
<class 'CodeJangoHome.admin.ArticleAdmin'>: (admin.E123) The value of 'title' cannot be in both 'list_editable' and 'list_display_links'.
<class 'CodeJangoHome.admin.ArticleAdmin'>: (admin.E123) The value of 'main_txt' cannot be in both 'list_editable' and 'list_display_links'.

System check identified 2 issues (0 silenced).

So, with list_display, list_editable, and list_display_links, I have a problem fitting them into the code in admin.py.I don't exactly know how to use them so a bit of help would be useful.


Solution

  • Django automatically set the first column of list_display as a link to the change form.

    You can either add another column (recommended), like

    @admin.register(Article)
    class ArticleAdmin(admin.ModelAdmin):
        list_display = ['__str__', 'title', 'main_txt', 'date_of_publication']
        list_editable = ['title', 'main_txt']
        def __str__(self):
            return self.title
    

    or explicitly set list_display_links to None

    @admin.register(Article)
    class ArticleAdmin(admin.ModelAdmin):
        list_display = ['title', 'main_txt', 'date_of_publication']
        list_editable = ['title', 'main_txt']
        list_display_links = None
        def __str__(self):
            return self.title
    

    EDIT:

    It is not required to put __str__ in list_display. It is just the first column of list_display that makes it special: Django automatically convert it to a link, if not specified.

    PS: What can be used in list_display?

    According to Django's docs,

    1. A field of model.
    2. A callable.
    3. A string representing a ModelAdmin attribute.
    4. A string representing a model attribute.

    Example list_displays:

    @admin.display(descriptor='Title')
    def upper_case_title(obj):
        return obj.title.upper()
    
    @admin.register(Article)
    class ArticleAdmin(admin.ModelAdmin):
        list_display = ['__str__', 'title', 'main_txt', 'date_of_publication']
        # 1. list_display = ['id', 'title', 'main_txt', 'date_of_publication']
        # 2. list_display = ['article_title', 'title', 'main_txt', 'date_of_publication']
        # 3. list_display = ['__str__', 'title', 'main_txt', 'date_of_publication']
        # 4. list_display = ['id_title', 'title', 'main_txt', 'date_of_publication']
        list_editable = ['title', 'main_txt']
        def __str__(self):
            return self.title
    

    To implement 4. you need to modify model definition

    #models.py
    from django.contrib import admin
    from django.db import models
    
    class Article(models.Model):
        title = models.CharField(max_length=500)
        date_of_publication = models.DateField()
        creaters = models.ManyToManyField('Author', blank=False)
        main_txt = models.TextField()
        notes = models.TextField()
    
        @admin.display(descriptor='Title')
        def id_title(self):
            return f'{self.id}. {self.title}'
    

    Again, I am just giving examples, you are not required to code exactly as above.