Need Help With View Query Comparing Dates

Hi Ken, are you there? :wink:

I’ve hit a wall with the following view query. I’m trying to compare update dates on two objects, then assign the object with the latest update date to a variable which I can pass to a template. Not getting anything, and I’m sure it’s a newbie error:

def last_database_update(request):
    last_updated_collection_object = Collection.objects.latest('date_saved').get()
    last_updated_collector_object = Collector.objects.latest('date_saved').get()
    if last_updated_collection_object.date_saved > last_updated_collector_object.date_saved:
        last_updated_object = last_updated_collection_object
    else:
        last_updated_object = last_updated_collector_object
    template = 'collections_app/base.html'
    context = {'last_updated_object': last_updated_object}
    return render(request, template, context)

Drop the get call from your queries. Latest returns an object, not a queryset.

See latest.

Also, if you have null values in that field, I believe it sorts higher than any value - you might need to filter them out. (Same page reference.)

Look for any error message that may show up on the console when this view is being executed.

Verify that your template will work the same for either a Collection object or a Collector object.

Ken

I’m still getting zilch. I suspected get call was not right. Wondering why latest is in the queryset documentation if it does not return a queryset? No error messages. And there should be no null values since this is autonow per “date_saved = models.DateField(auto_now=True),” right? There is always a value?

Template:

 We're fresh! Directory last updated {{ last_updated_object.date_saved }}

If you look at the QuerySet API reference page, you’ll see the index on the right is divided into two sections.

The QuerySet API methods are those methods that operate on a queryset - so if you have a queryset and invoke a method that returns a queryset, you can chain it with another method. (That’s why you can do things like SomeItem.objects.filter(...).filter(...).filter(...) etc. But once you use a method that doesn’t return a queryset, you can’t chain anything beyond that.)

There’s nothing obviously wrong here that I can see. I’d either walk through this using the debugger or toss in a mess of print statements to verify what I’ve got at each step.

For example, I’d probably either toss these lines in after the template= line:

print(last_updated_collection_object)
print(last_updated_collector_object)
print(last_updated_object)
print(last_updated_collection_object.date_saved)
print(last_updated_collector_object.date_saved)
print(last_updated_object.date_saved)

Or, using the debugger, I’d set my breakpoint on the template= line and check out those variables at that point.

Also, for clarification - are you seeing the template at all? (Meaning the header of “We’re fresh!..”) or are you getting a completely blank page?

If you’re not getting anything at all, that means there’s an error being thrown somewhere and you’re not seeing it

Ken

OK, thanks, good direction. I’ll trouble shoot with those print lines. And the template is loading with no errors.

Here is my template code:

 We're fresh! Directory last updated {{ last_updated_object.date_saved }}

BTW, my query luck is shit today.

I’m getting nothing out of this one either:

def randomized_collection_object(request):
    random_collection_object = Collection.objects.filter(name__isnull=False).order_by('?').first()
    template = 'collections_app/navigation.html'
    context = {'random_collection_object': random_collection_object}
    return render(request, template, context)

I’ve tested this and the one for collector and can’t get anything to return. Also tried a different template page and nothing. Wonder what’s up?

last_updated_collection_object = Collection.objects.latest('date_saved')

Only way I know of to diagnose something like this is to start from the beginning and cover everything involved - directly involved and indirectly involved.
Would need to see your settings.py, urls.py, what command you’re using to run the server, the output from the runserver console when running it, the full template file being rendered, any template files being extended or included, etc, etc. Complete files and not snippets.

Ken, you’re indefatigable. I guess I am too!

python3 manage.py runserver is the command I use … I don’t see any issues … what else can I send from the console?

(artist-files-directory) $ python3 manage.py runserver
Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).

Everything is updated on GitHub. I think you know my project well enough by now to understand what you need to examine, right?

settings.py below:

"""
Django settings for artist_files_directory project.

Generated by 'django-admin startproject' using Django 3.0.5.

For more information on this file, see
https://docs.djangoproject.com/en/3.0/topics/settings/

    For the full list of settings and their values, see
    https://docs.djangoproject.com/en/3.0/ref/settings/
    """

    import os

    # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


    # Quick-start development settings - unsuitable for production
    # See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/

    # SECURITY WARNING: keep the secret key used in production secret!
    SECRET_KEY =

    # SECURITY WARNING: don't run with debug turned on in production!
    DEBUG = True

    ALLOWED_HOSTS = []


    # Application definition

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'collections_app',
        'collectors_app',
    ]

    MIDDLEWARE = [
        'django.middleware.security.SecurityMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
    ]

    ROOT_URLCONF = 'artist_files_directory.urls'

    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': ['collections_app/templates/collections_app', 'collectors_app/templates/collectors_app'],
            'APP_DIRS': True,
            'OPTIONS': {
                'context_processors': [
                    'django.template.context_processors.debug',
                    'django.template.context_processors.request',
                    'django.contrib.auth.context_processors.auth',
                    'django.contrib.messages.context_processors.messages',
                ],
            },
        },
    ]

    WSGI_APPLICATION = 'artist_files_directory.wsgi.application'

    # Database
    # https://docs.djangoproject.com/en/3.0/ref/settings/#databases

    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.postgresql_psycopg2',
            'NAME': 'artist_files_directory',
            'USER': 'afd_master',
            'PASSWORD':
            'HOST': 'localhost',
            'PORT': '5432',
        }
    }


    # Password validation
    # https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators

    AUTH_PASSWORD_VALIDATORS = [
        {
            'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
        },
        {
            'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
        },
        {
            'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
        },
        {
            'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
        },
    ]


    # Internationalization
    # https://docs.djangoproject.com/en/3.0/topics/i18n/

    LANGUAGE_CODE = 'en-us'

    TIME_ZONE = 'UTC'

    USE_I18N = True

    USE_L10N = True

    USE_TZ = True


    # Static files (CSS, JavaScript, Images)
    # https://docs.djangoproject.com/en/3.0/howto/static-files/

    STATIC_URL = '/static/'
    STATIC_ROOT = os.path.join(os.path.dirname(BASE_DIR), 'static')
    STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static'), ]
    MEDIA_URL = '/media/'
    MEDIA_ROOT = os.path.join(BASE_DIR, 'media')

Yep, mostly just wanted to confirm / ensure that it’s all up-to-date. I know you’re doing a lot of work on it and didn’t want to spend a lot of time looking at old code.

I don’t find any reference to either last_database_update or randomized_collection_object anywhere. I don’t see any URL referencing them or any other function calling them.

What makes you think it’s being called?

Have I lost it? Entirely possible. Oh dear.

So below, you set the template variable, which then makes the function available to access on the template page, right? Oops, I have to register the view in URLs … I’ll bet that’s the problem. Does that sound correct?

def last_database_update(request):
    last_updated_collection_object = Collection.objects.latest('date_saved')
    last_updated_collector_object = Collector.objects.latest('date_saved')
    if last_updated_collection_object.date_saved > last_updated_collector_object.date_saved:
        last_updated_object = last_updated_collection_object
    else:
        last_updated_object = last_updated_collector_object
    template = 'collections_app/base.html'
    context = {'last_updated_object': last_updated_object}
    return render(request, template, context)

Not quite - I’m getting the impression from this that you’re looking at this from the wrong angle.

Briefly:

  • Browser issues HTTP GET on a url
  • Django receives the request, and looks for a matching url.
  • When it finds the URL, it then calls the view for that url.
  • The view does whatever processing needs to be done and returns a result.
    • The returned result might be a web page
      • It could also be a fragment of a page to be inserted into the current page as a result of an AJAX call
      • It could be JSON data returned to an AJAX call
      • It could be an HTTP error status such as a 404 or 500

The key point here is to not look at the templates as a “page”. (It might be one, but it may not.) It’s what the view returns as the result of a request.

The purpose of the built-in render function is to convert a template into HTML, to be returned by the view.

Another key point then is that you’re not limited to only rendering one template per page. As long as what you’re returning is a proper response for the request, you can render multiple templates in your view.

Ken

Very helpful. I was so used to dealing with pages. So, I’m a little slow today, and I’m hoping you get lead me along a little further towards a solution. When you’ve got html files like “navigation.html” and “base.html” that are used on every page, what is the approach to activate the views I have written. I guess I need a little extra TLC this morning. So this one, help me conceptualize and fix it if you have the time. I feel I need to put more quarters in the machine to keep you going!!

def last_database_update(request):
    last_updated_collection_object = Collection.objects.latest('date_saved')
    last_updated_collector_object = Collector.objects.latest('date_saved')
    if last_updated_collection_object.date_saved > last_updated_collector_object.date_saved:
        last_updated_object = last_updated_collection_object
    else:
        last_updated_object = last_updated_collector_object
    template = 'collections_app/base.html'
    context = {'last_updated_object': last_updated_object}
    return render(request, template, context)
  • You were right in your previous reply:

I was just pointing out that this basic solution you’re using in this case shouldn’t limit your thinking in that this is all you can do. For example, it’s perfectly valid for one view to call another view to render a template that’s not a complete page, and integrate it into its own results.

When you are constructing a complete page from a context when using a template, you will find the extends and include tags to be very helpful.

Ken

I’m continuing to struggle with a way to get a function active in my “header.html” file. Templatetags seem promising, but I have not gotten it to work yet. What am I missing? Do you see anything obvious? I know the function works properly.

header.html file:

{% load static %}
<div style="flex: 2 1 1500px">
    
{% load database_update_date %}
    
<div id="entry-dates-database">&nbsp;<label>We're fresh! Directory last updated</label> <strong>
    {{ last_updated_object.date_saved}}</strong></div>

<h1 class="title">Artist Files Revealed: International Directory of Artist Files Collections</h1>
<h2 class="home">A Resource from the Art Libraries Society of North America, Artist Files Special
Interest Group</h2>

You’re still not quite getting it.

A template or page doesn’t activate a function.

A URL is assigned to a function in your urls.py. That’s what activates that function.

The function then retrieves data, and uses that data to render a template.

Ken

I’m still not quite sure how to set up the URL for something like this in urls.py, though I understand what you’re saying. What do I do here? i.e. what does the pattern look like for a html template that is used on every page. That’s the part I’ve been missing all along I think.

And, Ken, can I nominate you for some kind of Django support award?

So the basic idea is that you build a base template that uses the block tag to identify placeholders for other templates to fill.

Those other templates then extend the base template, and enclose its content in blocks that fill in the placeholders defined in the base templates.

Take your time and really review the Template Inheritance documentation. If you want to see it in action, you can find some good examples on the Django Girls tutorial website. (I generally recommend the Django Girls tutorial in total - it’s really quite good. But for your purposes right now, I don’t see why you shouldn’t go right to that page.)

(And naa… I appreciate the thought but I’m just one of many.)

Hey Ken, I’m using templates thoroughly throughout my site, and I understand them. It’s this quote above that I can never nail down guidance in the documentation. And I spent a good amount of time trying to find guidance on how this looks in urls.py. I know it’s easy.

Again, my header.html file in where I want to activate the function, and I’m still not sure how about the conventions for expressing that file in urls.py. I’ll keep experimenting.

There are some examples starting in the Tutorial