30 Jul 2025
Django community aggregator: Community blog posts
Django: split ModelAdmin.get_queryset() by view
Within Django's popular admin site, you can override ModelAdmin.get_queryset()
to customize the queryset used by the admin views. It's often used for performance optimizations, such as adding a select_related()
call to batch-fetch related objects:
from django.contrib import admin
from example.models import Book
@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
def get_queryset(self, request):
return super().get_queryset(request).select_related("author")
However, one thing this approach lacks is granularity-the queryset returned by get_queryset()
is used for all admin views, such as the change list, change form, and any custom views that you might add. That can mean that adding an optimization in get_queryset()
for one view can impose a performance cost on other views that don't need it. For example, the above select_related()
call might optimize showing author details shown on the change list view, but other pages that don't show the author will still incur the cost of the join.
There isn't an easy way to customize the queryset for individual views without overriding a lot of their code. However, the queryset()
method is passed the current request
object as context, which allows you to differentiate between views based on request.resolver_match
. I think the most robust way to check the current admin view from there is with the __name__
attribute of the func
:
from django.contrib import admin
from example.models import Book
@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
def get_queryset(self, request):
queryset = super().get_queryset(request)
if request.resolver_match.func.__name__ == "changelist_view":
queryset = queryset.select_related("author")
return queryset
request.resolver_match.func
is the current view function, which will be a method of the current ModelAdmin
instance, wrapped with the AdminSite.admin_view
decorator. Its __name__
attribute gives the name of the view function, which you can use to differentiate between views. For the built-in admin views, it will be one of the following:
changelist_view
change_view
delete_view
history_view
(add_view
is not included here as it does not call get_queryset()
.)
30 Jul 2025 4:00am GMT
29 Jul 2025
Django community aggregator: Community blog posts
Our tools are still not designed for the AI future
First a disclaimer on this one: I am making the assumption that the AI trend is here to stay in some form and an economic crash/bubble doesn't make the usage of them untenable, also I have yet experiment with every tool out there!
With that said, a brief personal history of my usage of LLM's and the current wave of AI. I tried out ChatGPT when it was first released and was fairly impressed by the results, but the cruical missing step for me was the lack of browser integration, searching Google was still much quicker from a new tab page and the results from ChatGPT felt isolated, there was too much friction in my workflow for it be usable. I tried out a different product (I forget the name), which allowed me to search from a new tab page and I got AI results and normal search results in one go. This was better, but it still didn't stick, and so I kept experimenting with the tools on an ad-hoc basis, solving small challenges, but it not being a daily driver. In this I experimented with local LLMs and Zed's AI integration.
This changed earlier this year where I experimented with Manus.im and using Claude with Zed's agent mode. Both of these unlocked ideas or wrote decent code directly into my project for me to review, saving me time that I could measure. Since then I have used Zed's agent mode more frequently, that said I do still enjoy coding myself so sometimes forget to use the tools available.
This daily to weekly usage has led me to consider what an AI-first IDE would look like. At this point the newly released Kiro or Cursor comes to mind or others such as Zed or VSCode plus extensions, they are all really designed for a developer-first point of view since their beginning's were from a time before agent workflows existed.
Personally I am looking forward to the IDE that is built ground up to create, run and manage agents that follows the trend of 'spec-driven-development' that has started to form recently within AI circles. Generally I would expect the following:
- that the tool to have viewing and editing files (like we are used to) come secondary to managing a number of different agents, reviewing their output as they finish, with the UX to be something closer to one of the many git GUI tools around or Github's PR review experience.
- the rules to be part of the onboarding experience of a project (similar to the interactive prompts when setuping a project on the command line - eg cookiecutter) and allow for fluid automatic updates as part of a conversation flow. Perhaps even a rules generator for existing projects by scanning files and styles.
- The prompt window would be, of course be the main window and not off to the side.
- A search for semantic inclusion of elements over files would be the default allowing for specific, precise context when creating new code.
- A mobile experience for reviewing agents would also be key, perhaps the tool would be mobile-first even? The mobile experience for me would be key to allow reviewing code on the go when I am away from the desk.
- Finally we would likely still need to normal editing experience, however switching back to a traditional editor would be sufficient for me.
Is this something of a wishlist? Yes, but I could easily a version of this starting soon, because there a paradigm shift coming I think, where the day to day activity goes from one of writing on our local machines, to one of review on our local machines being the priority. Let me know what you think!
29 Jul 2025 5:00am GMT
28 Jul 2025
Django community aggregator: Community blog posts
User Timezones in Django
When you create a local website, the local time usually matches your country's timezone, and all visitors see times in that timezone. That's not a big issue if your country has only one timezone and your audience is local.
But when building a social platform like pybazaar.com, users are international and need to see times in their timezones. In this article, I'll show you how to handle that in Django.
Time Zone Database
Since version 4.0, Django has used the zoneinfo
library for managing timezones, and it used pytz
up to version 3.2. Both rely on the IANA Time Zone Database (tzdata
). IANA is the same organization that manages the DNS root zone, IP addresses, and other global internet resources.
Install tzdata
in your virtual environment as usual:
(venv)$ pip install --upgrade tzdata
Timezone Changes
Timezone information changes several times a year due to:
- Daylight Saving Time (DST) adjustments
- Political and border changes
- Shifts in standard time offset
Daylight Saving Time (DST) was first introduced in 1914 in Canada and later standardized in the U.S. in 1966. When dealing with historic dates before 1966-or future dates with uncertain timezone rules-precise time calculations can be unreliable.
# Before U.S. DST standardization:
old_date = datetime(1960, 6, 15, 12, 0)
# DST rules may change in the future:
future_date = datetime(2030, 6, 15, 12, 0)
Some timezone changes are driven by politics:
- Country splits or mergers - new countries may adopt different timezones.
- Regional preferences - states or provinces may change timezone alignment.
- Symbolic actions - e.g., North Korea introduced "Pyongyang Time" in 2015 by shifting 30 minutes back to symbolically break from Japan's colonial legacy.
And countries sometimes adjust their UTC offsets:
- Russia - changed its timezone policy multiple times
- Venezuela - changed from UTC-4 to UTC-4:30 in 2007, then back in 2016
- Samoa - jumped from UTC-11 to UTC+13 in 2011, skipping Dec 30 entirely
Best Practices for Django
- Use named timezones, not fixed UTC offsets.
- Update
tzdata
monthly or quarterly. - Test with historic and future dates.
- Handle conversion errors gracefully, falling back to UTC.
- Store all times in UTC internally.
- Convert to user's timezone only in the UI.
- Include
tzdata
updates in deployment (Docker, Ansible, etc.).
Timezone Management for a Social Platform
For platforms with global users:
- Store all datetimes in UTC.
- Store each user's preferred timezone.
- Convert times on input/output according to the user's timezone.
1. Enable Timezone Support in Django Settings
Set the default timezone to UTC:
# settings.py
USE_TZ = True
TIME_ZONE = "UTC" # Store everything in UTC
2. Add a timezone
Field to the Custom User
Model
Use a function for dynamic timezone choices, so you don't need new migrations when the list changes.
def get_timezone_choices():
import zoneinfo
return [(tz, tz) for tz in sorted(zoneinfo.available_timezones())]
class User(AbstractUser):
# ...
timezone = models.CharField(
_("Timezone"), max_length=50, choices=get_timezone_choices, default="UTC"
)
3. Detect Timezone on the Frontend
Add hidden fields in your Login and Signup forms to capture the user's timezone from their browser:
document.addEventListener('DOMContentLoaded', function () {
const userTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
const timezoneInput = document.getElementById('id_timezone');
if (timezoneInput) {
timezoneInput.value = userTimezone;
}
});
You can also let users change their timezone manually in account settings.
4. Use a Custom DateTime Field in Forms
This field will convert datetimes between UTC and the user's local timezone:
import datetime
from zoneinfo import ZoneInfo
from django import forms
from django.utils import timezone
from django.utils.dateparse import parse_datetime
class TimezoneAwareDateTimeField(forms.DateTimeField):
widget = forms.DateTimeInput(attrs={"type": "datetime-local"})
def __init__(self, user_timezone=None, *args, **kwargs):
self.user_timezone = user_timezone
super().__init__(*args, **kwargs)
def prepare_value(self, value):
if value and self.user_timezone:
try:
user_tz = ZoneInfo(self.user_timezone)
if timezone.is_aware(value):
value = value.astimezone(user_tz)
except Exception:
pass
return value
def to_python(self, value):
if value in self.empty_values:
return None
if isinstance(value, datetime.datetime):
result = value
elif isinstance(value, datetime.date):
result = datetime.datetime(value.year, value.month, value.day)
else:
try:
result = parse_datetime(value.strip())
except ValueError:
raise forms.ValidationError(
self.error_messages["invalid"], code="invalid"
)
if not result:
result = super(forms.DateTimeField).to_python(value)
if result and self.user_timezone:
try:
user_tz = ZoneInfo(self.user_timezone)
if timezone.is_naive(result):
result = result.replace(tzinfo=user_tz)
result = result.astimezone(ZoneInfo("UTC"))
except Exception:
pass
return result
The type="datetime-local"
widget uses the browser's native date/time picker.
Use the custom field like this:
from django import forms
from django.utils.translation import gettext_lazy as _
from myproject.apps.core.form_fields import TimezoneAwareDateTimeField
from .models import Post
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ["title", "content", "published_from"]
def __init__(self, request, *args, **kwargs):
super().__init__(*args, **kwargs)
self.request = request
self.fields["published_from"] = TimezoneAwareDateTimeField(
label=_("Published from"),
help_text=_("Enter date and time in your local timezone."),
required=False,
user_timezone=self.request.user.timezone,
)
5. Output Dates and Times in User's Timezone
{% load tz %}
{% with user_timezone=request.user.timezone|default:"UTC" %}
{{ post.published_from|timezone:user_timezone|date:"j M, Y H:i" }}
{% endwith %}
Other Options
You can also detect the visitor's timezone in JavaScript and send it via Ajax to be saved in the Django session. Then you can use it even for anonymous users.
Final Words
Timezones aren't so scary if you follow Django's best practices:
- Store all times in UTC.
- Update
tzdata
regularly. - Use the user's timezone only at input/output stages.
- Detect the user's timezone via JavaScript-no need to ask them manually.
This keeps your website accurate, user-friendly, and ready for global audiences.
Cover photo by Andrey Grushnikov
28 Jul 2025 5:00pm GMT