How to order_by() last content `saved` in Admin Dashboard rather than by `date` or `id`.

According to the official Django docs for the API QuerySet reference, there are many ways to order the way objects are sorted and rendered when Django serves a template. The offiical Django docs demonstrate how to order (and reverse order) like by alphabetical title or by publication date:

Entry.objects.order_by('blog')

Or:

Entry.objects.order_by('headline').order_by('-pub_date')

The second code snippet above sorts the data first alphabetically according to headline and then by publication date in ascending order.

In my use case, I need to order a list of entires according the to the time they were last updated (saved) by the content owner in the Admin Dashboard. Ordering by id is not the solution because when, say, for example, an entry that was initially created with an id integer value of 6 (among 50 subequent entries), when the Admin user updates the 6th entry, that entry needs to be shuffled to the top of the list of 56 entries. That’s what I am trying to do.

If I understand correctly and based on how Django is currently behaving, when the Admin user updates a content entry, that promotes the positioning to appear as the one closest to the bottom of the list when the template is served. Instead, I need to reverse this ordering so the list ascends (rather than descends) according to the one saved most recently. I figure this will involve appending a negation to a certain string value (like -pub_date above) but since my project doesn’t have a pub_date model field, I can’t locate the passage to the Django doc linked to above which identifies how to re-order content according to most recently saved.

Hey there!
Can you post your model and admin code?

Below you can see my models.py and CBV’s in my views.py. I’m not sure why you want to see my admin code, but here it is:

admin.py:

from django.contrib import admin

# Register your models here.
from .models import Preamble,Induction, ScriptSuggestion, Research,StockScript

admin.site.register(Preamble)
admin.site.register(Induction)
admin.site.register(ScriptSuggestion)
admin.site.register(Research)
admin.site.register(StockScript)

Here is a sample of my models.py:

from django.db import models

class Content(models.Model):
    pass

# Create your models here.
class Preamble(models.Model):
    title = models.CharField(max_length=300,blank=True)
    body = models.TextField(max_length=300000,blank=True)
    author = models.CharField(max_length=30,blank=True)
    slug = models.SlugField(unique=True,blank=True)
    # posting_date = models.DateField(auto_now=False, auto_now_add=False, **options), https://docs.djangoproject.com/en/4.1/ref/models/fields/#django.db.models.DateField
    
    def __str__(self):
        return f'{self.title}'
    
class Induction(models.Model):
    title = models.CharField(max_length=300,blank=True)
    body = models.TextField(max_length=300000,blank=True)
    author = models.CharField(max_length=30,blank=True)
    slug = models.SlugField(unique=True,blank=True)
    
    def __str__(self):
        return f'{self.title}'

views.py:

from django.shortcuts import render
from django.urls import reverse_lazy
from django.views.generic import ListView,DetailView
from .models import Preamble, Induction, Research, ScriptSuggestion,StockScript,Content
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.views import LoginView
from django.contrib.auth.decorators import login_required

'''
class CustomLoginView(LoginView):
    form_class = LoginForm
    template_name = 'registration/login.html'
    fields = '__all__'
    redirect_authenticated_user = True

    #def get_success_url(self):
    #    return reverse_lazy('/')

def index(request):
    return render(request,'contents/index.html')
'''

class ContentListView(LoginRequiredMixin,ListView):
    # model_list.html
    # model = Induction
    model = Content
    # login_url = '/'
    # template_name = 'home.html'
    
    # fields =['author','title',]
    
    def get_context_data(self, **kwargs):
        # Call the base implementation first to get a context
        context = super(ContentListView, self).get_context_data(**kwargs)
        # Add in a QuerySet of all the Baklawa
        context['inductions'] = Induction.objects.all()
        context['preambles'] = Preamble.objects.all()
        context['research'] = Research.objects.all()
        context['scriptsuggestions'] = ScriptSuggestion.objects.all()
        context['stockscripts'] = StockScript.objects.all()
        return context

class PreambleDetailView(LoginRequiredMixin,DetailView):
    model = Preamble
    context_object_name = 'preambles'

Thank you for posting the code here.
I asked for the admin code, because i was thinking that you wanted this ordering on the admin. But i think that’s not the case. You want to order the objects on the view.

But just to be really clear, which model are you trying to sort?

Note: You’re going to need a date field in order to do this ordering.

If you are looking to access the Django Admin Log entries, see The Django admin site | Django documentation | Django.

Hi @KenWhitesell: Thank you. I haven’t had a chance yet to try the LogEntry object in my project yet, but based on what I see in this Django doc, it looks like the precise answer to my question.

Hi Ken,

I am experimenting with LogEntry model you refered to and I can’t quite get it to work.

As per the doc you shared, to the top of my views.py I’ve appended:

from django.contrib.admin.models import LogEntry

My CBV looks like this now:

class ContentListView(LoginRequiredMixin,LogEntry,ListView):
    model = Content
 
    def get_context_data(self, **kwargs):
        context = super(ContentListView, self).get_context_data(**kwargs)
        context['stockscripts'] = StockScript.objects.all().LogEntry.objects.order_by('-action_time')
        return context

Notice above how I have included LogEntry in the ContentListView class declaration.

Django renders a server error and the traceback in my Django dev server shell says:

context['stockscripts'] = StockScript.objects.all().LogEntry.objects.order_by('-action_time')
AttributeError: 'QuerySet' object has no attribute 'LogEntry'

I thought about moving the LogEntry call inside my models.py somewhere but that didn’t work because LogEntry is not a Field.

@KenWhitesell or anyone else you may be reading this: How should I call LogEntry the right way?

Django docs are helpful but sometimes but other times I feel like it isn’t specific enough. Of course I reached out to Google with different combinations of search terms such as:

  • order_by "action_time" django logentry
  • order by logentry django
  • log entry field django
  • action_time logentry django 4

No dice.

As you’ve identified above:

LogEntry is a model. You work with it the same way you work with any other model.

You run queries on it in exactly the same manner as you use your StockScript model.

I feel Django docs are sparse and not detailed enough for me to see how to call the LogEntry properly. So I went looking on Google for examples on how to query my db and sort the output of the data according to when a LogEntry ‘CHANGE’ action takes place and then Django serves the template. There were lots of 10+ year old Stack Overflow questions and even those didn’t really answer the question I am looking for.

Here is one of the models I am working with now for my web app:

from django.contrib.admin.models import CHANGE, LogEntry
 
class ScriptSuggestion(LogEntry,models.Model):
   # id = models.IntegerField(blank=False, null=False)
   title = models.CharField(max_length=300,blank=True)
   body = models.TextField(max_length=300000,blank=True)
   author = models.CharField(max_length=300,blank=True)
   slug = models.SlugField(unique=True,blank=True)
   changed = LogEntry.objects.filter(action_flag=CHANGE,blank=False, null=False)
  
   def __str__(self):
       return f'{self.title}'
 

Notice the last declared attribute I’ve called: changed. That is where I believe is the right place to call the LogEntry model.

Here is my corresponding CBV:

class ContentListView(LoginRequiredMixin,ListView):
   model = Content
   def get_context_data(self, **kwargs):
       # Call the base implementation first to get a context
       context = super(ContentListView, self).get_context_data(**kwargs)
       # Add in a QuerySet of all the Baklawa
       context['inductions'] = Induction.objects.all()
       context['preambles'] = Preamble.objects.all()
       context['research'] = Research.objects.all()
       context['scriptsuggestions'] = ScriptSuggestion.objects.all().order_by('-changed')
 
       context['stockscripts'] = StockScript.objects.all()
       return context

Notice the context dictionary keyword argument showing: 'scriptsuggestions'. I’ve appended .order_by('-changed') to the end which is also my best attempt at putting the LogEntry’s model attribute reference in the right place.

There are now two major issues I’ve encountered with the above arrangements:

  1. When I created the db migrations initially, it prompted me to enter a default value. The message suggested entering timezone.now. I’ve seen this before so I went ahead and entered it. Big mistake. Afterwards if I recall correctly Django was saying that the id needs to be an integer. Below was the Django traceback. I invoked the Django shell and tried to manually re-assign an integer value to the id attribute for this class instance to replace the erroneous date data. But that didn’t work. Afterwards I added blank=False, null=False to the LogEntry attribute in models.py but it’s too late. Here was the error:
    raise FieldError(
django.core.exceptions.FieldError: Local field 'id' in class 'ScriptSuggestion' clashes with field of the same name from base class 'LogEntry'.

So while I still need to resolve the issue outlined above, now I have got a new issue that needs to be resolved first:

  1. I am not sure what I did exactly to trigger it but now the Django dev server log is showing:
File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/venv/lib/python3.10/site-packages/django/apps/registry.py", line 143, in check_models_ready
    raise AppRegistryNotReady("Models aren't loaded yet.")
django.core.exceptions.AppRegistryNotReady: Models aren't loaded yet.

The most upvoted questions on Stack Overflow for this new second issue point to a misconfigured asgi.py.

In another Django forum thread @jeff answered a similar question 3 years ago writing:

The Django doc referred to is for AppConfig methods. I’m not sure why this is a problem all of a sudden or what I did to cause this. Should I begin building an AppConfig Django app?

I don’t understand why you keep trying to add LogEntry as a model field, it’s not. You’re headed in completely the wrong direction with this entire approach.

See my previous reply. LogEntry is a model, you query it like any other model.

Think about how you use the system-provided User model in other circumstances. It’s that type of pattern that you would use - nothing like what you’re trying here.

Hi @KenWhitesell,

I heard you the first time when you said it was a model. When you say model I thought you were referring to models.py. But now that you have clarified that it needs to be called like a User model, that means it needs to be referenced inside the views.py, perhaps also like a Mixin.

I am now importing the admin models LogEntry inside the views.py and trying to build from there.

Here was my next attempt:

class ContentListView(LoginRequiredMixin,LogEntry,ListView):
    model = Content
    def get_context_data(self, **kwargs):
        # Call the base implementation first to get a context
        context = super(ContentListView, self).get_context_data(**kwargs)
        # Add in a QuerySet of all the Baklawa
        context['scriptsuggestions'] = ScriptSuggestion.objects.all().LogEntry.objects.order_by(action_flag=CHANGE)
        return context

That didn’t work. My LogEntry reference was clearly not in the right position. So I changed the context reference back to:

        context['scriptsuggestions'] = ScriptSuggestion.objects.all()

My next try I went down to the CBV to add a queryset attribute. I experimented with the following class structure:

class ScriptSuggestionDetailView(LoginRequiredMixin,LogEntry,DetailView):
    model = ScriptSuggestion
    queryset = ScriptSuggestion.objects.all().LogEntry.objects.order_by(action_flag=CHANGE)
    context_object_name = 'scriptsuggestions'

Django didn’t really like that either. Next I changed the queryset line to this:

    queryset = LogEntry.objects.order_by(action_flag=CHANGE)

Still no dice. I am stabbing in the dark here. What am I continuing to overlook?

How do I properly query my database in my CBV and sort the output in descending order by most recent LogEntry change?

edit: Updated first the first attempt with the queryset attribute declaration to reflect my actual attempt. I meant to include the ScriptSuggestion objects call. That is what I actually tested with. Not sure how I managed to miss that when I wrote the post. Anyways, it’s there now.

NO.

You do add any other models as a mixin? No.

You are on the right track that you would use it in a query in your view.

However, since your detail view is intended to be a DetailView of ScriptSuggestion, it won’t be your queryset for that view either.

Let’s take a step back for a moment.

First, keep in mind that LogEntry is itself a log file - this means that there is going to be multiple LogEntry for each row of ScriptSuggestion. (Every change to ScriptSuggestion in the admin generates a new entry.) So trying to order_by a query on ScriptSuggestion by LogEntry itself doesn’t make a whole lot of sense. (How is the ORM going to know which LogEntry to use?)

Also, LogEntry uses a Generic ForeignKey to link to all the different models that can be edited in the admin, which means that your query needs to account for that.

Hmmm… I just tried a couple things that didn’t work. I’m going to need to take a closer look at this.

Right now I’m thinking you’re going to need to annotate your ScriptSuggestion query with the results of a subquery to retrieve the most recent change for each individual element, and then order_by on that annotated value.

Ok, this is what I came up with - it should be close:

script_type = ContentType.objects.get_for_model(ScriptSuggestion)

ScriptSuggestion.objects.annotate(
    last_change=Subquery(
        LogEntry.objects.filter(
            content_type=script_type,
            action_flag=CHANGE,
            object_id=Cast(OuterRef('id'), CharField()
        ).order_by('-action_time').values('action_time')[:1]
    )
).order_by('-last_change')

(Note that any rows in ScriptSuggestion that doesn’t have any changes associated with it in the admin will be sorted before those that do.)

@KenWhitesell: A thousand thank-yous! I appreciate you taking the time to experiment and come up with a solution tailored specifically for my situation.

I tested it just now and my Python linter in vscode indicates an issue with an unclosed parentheses. The parenthenses that begins with the .annotate( method doesn’t close anywhere after the fact, if I understand correctly. I was sure where I should finish the parentheses, like after which of the many .order_by() function/method calls. There are so many different possibilities.

See here for a screenshot of my editor with my linter showing various squiggly lines indicating an outstanding syntax issue:

For future reference, please don’t post images of code. Go ahead and copy/paste the code itself into the body of the comment, surrounded by the lines of three backtick - ` characters. (Line of ```, code, another line of ```.)

Anyway, yes, there’s a close paren missing at the end of the object_id= line.

And again, remove the LogEntry from the class definition.

I am usually pretty good about using the proper ``` back ticks to wrap code snippets however this time I decided to use a screenshot to demonstrate the syntax errors indicated by my Python linter.

I added a close paren as per your recommendation. Here is a copy and paste of the full class declaration in full (with LogEntry removed from the class definition):

class ScriptSuggestionDetailView(LoginRequiredMixin,DetailView):
    model = ScriptSuggestion
    
    script_type = ContentType.objects.get_for_model(ScriptSuggestion)
    
    ScriptSuggestion.objects.annotate(
        last_change=Subquery(
            LogEntry.objects.filter(
                content_type=script_type,
                action_flag=CHANGE,
                object_id=Cast(
                    OuterRef('id'), 
                    CharField()
                    )
            ).order_by('-action_time').values('action_time')[:1]
        )
    ).order_by('-last_change')
        
    context_object_name = 'scriptsuggestions'

There are still linting errors. When I run the Django server, here is the shell traceback:

› python manage.py runserver 9000
Watching for file changes with StatReloader
Performing system checks...

Exception in thread django-main-thread:
Traceback (most recent call last):
  File "/usr/lib/python3.10/threading.py", line 1016, in _bootstrap_inner
    self.run()
  File "/usr/lib/python3.10/threading.py", line 953, in run
    self._target(*self._args, **self._kwargs)
  File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/venv/lib/python3.10/site-packages/django/utils/autoreload.py", line 64, in wrapper
    fn(*args, **kwargs)
  File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/venv/lib/python3.10/site-packages/django/core/management/commands/runserver.py", line 134, in inner_run
    self.check(display_num_errors=True)
  File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/venv/lib/python3.10/site-packages/django/core/management/base.py", line 475, in check
    all_issues = checks.run_checks(
  File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/venv/lib/python3.10/site-packages/django/core/checks/registry.py", line 88, in run_checks
    new_errors = check(app_configs=app_configs, databases=databases)
  File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/venv/lib/python3.10/site-packages/django/core/checks/urls.py", line 14, in check_url_config
    return check_resolver(resolver)
  File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/venv/lib/python3.10/site-packages/django/core/checks/urls.py", line 24, in check_resolver
    return check_method()
  File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/venv/lib/python3.10/site-packages/django/urls/resolvers.py", line 494, in check
    for pattern in self.url_patterns:
  File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/venv/lib/python3.10/site-packages/django/utils/functional.py", line 57, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/venv/lib/python3.10/site-packages/django/urls/resolvers.py", line 715, in url_patterns
    patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
  File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/venv/lib/python3.10/site-packages/django/utils/functional.py", line 57, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/venv/lib/python3.10/site-packages/django/urls/resolvers.py", line 708, in urlconf_module
    return import_module(self.urlconf_name)
  File "/usr/lib/python3.10/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 883, in exec_module
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/hypno_juicer/urls.py", line 11, in <module>
    path('', include('contents.urls')),
  File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/venv/lib/python3.10/site-packages/django/urls/conf.py", line 38, in include
    urlconf_module = import_module(urlconf_module)
  File "/usr/lib/python3.10/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 883, in exec_module
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/contents/urls.py", line 2, in <module>
    from .views import ContentListView, InductionDetailView,ResearchDetailView, PreambleDetailView, ScriptSuggestionDetailView,StockScriptDetailView # index
  File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/contents/views.py", line 52, in <module>
    class ScriptSuggestionDetailView(LoginRequiredMixin,DetailView):
  File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/contents/views.py", line 55, in ScriptSuggestionDetailView
    script_type = ContentType.objects.get_for_model(ScriptSuggestion)
NameError: name 'ContentType' is not defined

It’s not a “syntax” issue.

All of those functions that are underlined are indicating that they need to be imported from the appropriate modules.

For example, ContentType is defined in django.contrib.contenttypes.models.

Each one of those functions need to be imported from their respective modules, or import the modules and use the qualified name.

Hi @KenWhitesell:

Thanks again for helping come up with this Python subquery scripting gymnastic so far because there is no way I could have figured this out on my own.

Here is the latest code snippet I am working with based on your suggestion:

class ScriptSuggestionDetailView(LoginRequiredMixin,DetailView):
    model = ScriptSuggestion
    
    script_type = ContentType.objects.get_for_model(ScriptSuggestion)
    
    ScriptSuggestion.objects.annotate(
        last_change=Subquery(
            LogEntry.objects.filter(
                content_type=script_type,
                action_flag=CHANGE,
                object_id=Cast(
                    OuterRef('id'), 
                    CharField()
                    )
            ).order_by('-action_time').values('action_time')[:1]
        )
    ).order_by('-last_change')
        
    context_object_name = 'scriptsuggestions'

To resolve the issues referred to by my editor’s Python linter, I found all the modules in the Django docs and added the proper import references at the top of my views.py:

from django.contrib.admin.models import CHANGE, LogEntry
from django.db.models import OuterRef, Subquery
from django.contrib.contenttypes.models import ContentType
from django.db.models.functions import Cast
from django.db.models import CharField

That’s everything. All the linting errors are gone. When I run the server, there is no traceback and I can access the Admin Dashboard and view the full site. That’s progress.

The problem now is, when the Admin changes existing content, the way the list of objects are ordered remains unchanged when Django serves the ListView template. It’s like the the new code is having no impact. It’s the same as before. I also tried creating brand new test content and the new list item continues to appear at the bottom of the list like it always has instead of appearing at the top. For the .order_by() string paramaters, I tried combinations of changing with and without “-” that is part of the string but there is no change in the sorting behaviour.

For what it is worth, here is my for loop and how my unordered list is constructed in my template:

    <ul>        
        <h4> CUSTOMIZED <br> SCRIPTS </h4>
        <div class="box">
        {% for script in scriptsuggestions %}
            <li class="flex-item"><a href="/scripting/{{script.slug}}">{{script.title}}</a></li>
        {% endfor %}
         </div> <!-- end  box -->
    </ul>

Earlier in this thread, Ken said:

I’m not sure I completely understand this quote but could the issue I am describing above involve the way the list is sorted based on changes made by the Admin as you explain here?

My Django shell is also pointing to an issue with my models. Django says:

You have 2 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): contents.
Run ‘python manage.py migrate’ to apply them.

When I migrate the db, the traceback points to an id integer field issue, captured below at the bottom of this post. I am not sure if resolving the LogEntry sorting issue with subquery ‘gymnastic’ we have been working on so far is related to this, but I thought I would mention it.

As you can see below, Python is saying that the entry in the database needs to a number (integer) but it’s a datetime value. I think I made this mistake previously when I made a migration a few weeks ago and Django prompted me for a default entry. I realize my mistake now. I tried appending id = models.IntegerField(blank=False, null=False) to my ScriptSuggestion class in models.py and generating some new migrations but Django didn’t like that either so I commented it back out.

In my next attempt to fix this, I moved the 2 most recent auto-generated migrations into a backup directory. I then tried to re-generate new migrations but Django says “No changes detected”. When I run the server, Django says:

System check identified no issues (0 silenced).

The Django server proceeds to run without showing any other issues and my site seems to otherwise be working. Was this the right next step - - to backup the offending migrations?

The original issue remains: Class objects are still not being sorted according to log entries in Descending order when the ListView template is being served.

$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contents, contenttypes, sessions
Running migrations:
  Applying contents.0009_alter_scriptsuggestion_managers_and_more...Traceback (most recent call last):
  File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/venv/lib/python3.10/site-packages/django/db/models/fields/__init__.py", line 2018, in get_prep_value
    return int(value)
TypeError: int() argument must be a string, a bytes-like object or a real number, not 'datetime.datetime'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/manage.py", line 22, in <module>
    main()
  File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/manage.py", line 18, in main
    execute_from_command_line(sys.argv)
  File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/venv/lib/python3.10/site-packages/django/core/management/__init__.py", line 446, in execute_from_command_line
    utility.execute()
  File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/venv/lib/python3.10/site-packages/django/core/management/__init__.py", line 440, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/venv/lib/python3.10/site-packages/django/core/management/base.py", line 402, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/venv/lib/python3.10/site-packages/django/core/management/base.py", line 448, in execute
    output = self.handle(*args, **options)
  File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/venv/lib/python3.10/site-packages/django/core/management/base.py", line 96, in wrapped
    res = handle_func(*args, **kwargs)
  File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/venv/lib/python3.10/site-packages/django/core/management/commands/migrate.py", line 349, in handle
    post_migrate_state = executor.migrate(
  File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/venv/lib/python3.10/site-packages/django/db/migrations/executor.py", line 135, in migrate
    state = self._migrate_all_forwards(
  File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/venv/lib/python3.10/site-packages/django/db/migrations/executor.py", line 167, in _migrate_all_forwards
    state = self.apply_migration(
  File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/venv/lib/python3.10/site-packages/django/db/migrations/executor.py", line 252, in apply_migration
    state = migration.apply(state, schema_editor)
  File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/venv/lib/python3.10/site-packages/django/db/migrations/migration.py", line 130, in apply
    operation.database_forwards(
  File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/venv/lib/python3.10/site-packages/django/db/migrations/operations/fields.py", line 108, in database_forwards
    schema_editor.add_field(
  File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/venv/lib/python3.10/site-packages/django/db/backends/base/schema.py", line 636, in add_field
    definition, params = self.column_sql(model, field, include_default=True)
  File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/venv/lib/python3.10/site-packages/django/db/backends/base/schema.py", line 353, in column_sql
    " ".join(
  File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/venv/lib/python3.10/site-packages/django/db/backends/base/schema.py", line 304, in _iter_column_sql
    default_value = self.effective_default(field)
  File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/venv/lib/python3.10/site-packages/django/db/backends/base/schema.py", line 423, in effective_default
    return field.get_db_prep_save(self._effective_default(field), self.connection)
  File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/venv/lib/python3.10/site-packages/django/db/models/fields/related.py", line 1146, in get_db_prep_save
    return self.target_field.get_db_prep_save(value, connection=connection)
  File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/venv/lib/python3.10/site-packages/django/db/models/fields/__init__.py", line 925, in get_db_prep_save
    return self.get_db_prep_value(value, connection=connection, prepared=False)
  File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/venv/lib/python3.10/site-packages/django/db/models/fields/__init__.py", line 2703, in get_db_prep_value
    value = self.get_prep_value(value)
  File "/home/<user>/dev/projects/python/2018-and-2020/hypno_juicer/venv/lib/python3.10/site-packages/django/db/models/fields/__init__.py", line 2020, in get_prep_value
    raise e.__class__(
TypeError: Field 'id' expected a number but got datetime.datetime(2022, 12, 4, 9, 51, 33, 379630, tzinfo=datetime.timezone.utc).

You don’t put a query at the module level of a class. Queries should be executed in one of the functions that you override within that class.

You’re also showing a DetailView here and not a list view.

I’m still grappling with where the right position is for this query. You say that it doesn’t belong in the module level of a class and that instead it should be called to overide a function within that class.

So with all CBV’s (like I am working with in this case), they come with a host of default functions (class methods, right?). When using CBVs, we can override the default class variables to add unique functionality. In my situation I am using both DetailViews and ListViews. As defined in the official Django docs for ListView, one of them is called get_context_data. Is this an example of a CBV method that needs to be overriden with the special ScriptSuggestion.objects.annotate(... query that you have designed, @KenWhitesell?

If so, then you can see my latest fresh code snippet below where I have positioned your algorithm. It’s over riding a CBV method. This is my best attempt at over riding what I think is the necessary function.

In my previous attempts, you correctly noted that I was contructing a class view in my code snippet with a DetailView. But earlier I was trying to integrate the LogEntry sorting feature for a ListView template.

To this end, here is my latest views.py in full:

from django.shortcuts import render
from django.urls import reverse_lazy
from django.views.generic import ListView,DetailView
from .models import Preamble, Induction, Research, ScriptSuggestion,StockScript,Content
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.views import LoginView
from django.contrib.auth.decorators import login_required
from django.contrib.admin.models import CHANGE, LogEntry
from django.db.models import OuterRef, Subquery
from django.contrib.contenttypes.models import ContentType
from django.db.models.functions import Cast
from django.db.models import CharField

class ContentListView(LoginRequiredMixin,ListView):
    model = Content
    # template_name = 'home.html'   
        
    def get_context_data(self, **kwargs):
    
        # Call the base implementation first to get a context
        context = super(ContentListView, self).get_context_data(**kwargs)
        script_type = ContentType.objects.get_for_model(Research)
        script_type = ContentType.objects.get_for_model(ScriptSuggestion)
    
        context['inductions'] = Induction.objects.all()
        context['preambles'] = Preamble.objects.all()
        context['scriptsuggestions'] = ScriptSuggestion.objects.annotate(
            last_change=Subquery(
                LogEntry.objects.filter(
                    content_type=script_type,
                    action_flag=CHANGE,
                    object_id=Cast(
                        OuterRef('id'), 
                        CharField()
                        )
                    ).order_by('-action_time').values('action_time')[:1]
                )
            ).order_by('-last_change')
        context['stockscripts'] = StockScript.objects.all()
        context['research'] = Research.objects.annotate(
            last_change=Subquery(
                LogEntry.objects.filter(
                    content_type=script_type,
                    action_flag=CHANGE,
                    object_id=Cast(
                        OuterRef('id'), 
                        CharField()
                        )
                    ).order_by('-action_time').values('action_time')[:1]
                )
            ).order_by('-last_change')
        return context

class PreambleDetailView(LoginRequiredMixin,DetailView):
    model = Preamble
    context_object_name = 'preambles'

class InductionDetailView(LoginRequiredMixin, DetailView):
    model = Induction
    context_object_name = 'inductions'
    
class ScriptSuggestionDetailView(LoginRequiredMixin,DetailView):
    model = ScriptSuggestion        
    context_object_name = 'scriptsuggestions'

class StockScriptDetailView(LoginRequiredMixin,DetailView):
    model = StockScript
    context_object_name = 'stockscripts'

class ResearchDetailView(LoginRequiredMixin, DetailView):
    model = Research    
    context_object_name = 'research'

As you can see, I’ve moved the LogEntry algorithm from the classes with DetailViews and placed it in the main ContentListView CBV. While my Django server runs and shows no errors or tracebacks (it’s not broken), my lists are still not being sorted by most recent changes by LogEntry.

What could we try next?