By KFSys
System Administrator
A Materialized View in PostgreSQL is like a snapshot of a SQL query result thatâs physically stored in the database. Unlike a regular view (which re-runs the query every time you access it), a materialized view stores the data and can be refreshed manually or on a schedule.
Performance Boost: Materialized views avoid running complex or expensive queries repeatedly.
Precomputed Aggregates: Great for analytics (e.g., leaderboards, dashboards, reports).
Simplifies Code: Complex joins or calculated fields can be offloaded to the database.
Can Be Indexed: Unlike regular views, you can add indexes to speed up access.
REFRESH MATERIALIZED VIEW my_view;
Concurrent Refresh (allows reads during refresh but requires a unique index):
REFRESH MATERIALIZED VIEW CONCURRENTLY my_view;
Django doesnât have native support for materialized views, but you can integrate them easily with:
CREATE MATERIALIZED VIEW user_leaderboard AS
SELECT user_id, COUNT(*) AS quizzes_played
FROM quiz_quizresult
GROUP BY user_id;
class UserLeaderboard(models.Model):
user = models.ForeignKey(User, on_delete=models.DO_NOTHING)
quizzes_played = models.IntegerField()
class Meta:
managed = False # So Django doesn't try to create the table
db_table = 'user_leaderboard'
from django.db import connection
def refresh_leaderboard():
with connection.cursor() as cursor:
cursor.execute("REFRESH MATERIALIZED VIEW CONCURRENTLY user_leaderboard;")
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
Accepted Answer
Letâs say you have a quiz platform and want to show a daily leaderboard showing who took the most quizzes yesterday.
CREATE MATERIALIZED VIEW daily_leaderboard AS
SELECT
user_id,
COUNT(*) AS quizzes_played
FROM
quiz_quizresult
WHERE
DATE(created_at) = CURRENT_DATE - INTERVAL '1 day'
GROUP BY
user_id;
You could also create this view via Django migration using RunSQL
.
class DailyLeaderboard(models.Model):
user = models.ForeignKey(User, on_delete=models.DO_NOTHING)
quizzes_played = models.IntegerField()
class Meta:
managed = False
db_table = 'daily_leaderboard'
def leaderboard_view(request):
leaderboard = DailyLeaderboard.objects.select_related('user').order_by('-quizzes_played')[:10]
return render(request, 'leaderboard.html', {'leaderboard': leaderboard})
Use a management command
or Celery periodic task
to refresh it nightly:
from django.core.management.base import BaseCommand
from django.db import connection
class Command(BaseCommand):
def handle(self, *args, **kwargs):
with connection.cursor() as cursor:
cursor.execute("REFRESH MATERIALIZED VIEW CONCURRENTLY daily_leaderboard;")
Then schedule it with cron
, Celery Beat
, or any task scheduler.
Materialized views are a powerful but underused tool in Django apps that rely on PostgreSQL. Theyâre especially helpful when:
Youâre building dashboards or reports
You need quick read access to expensive queries
You can tolerate slightly stale data
By combining Django models with manually refreshed materialized views, you get the best of both worlds: fast reads and clean ORM integration.
Heya, @kfsys
That is a great tutorial!
Also, for apps that rely heavily on PostgreSQL, tools like pg_cron or extensions like TimescaleDBâs continuous aggregates offer even more flexibility than materialized views alone â especially for time-series or event-driven data.
Regards
Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.
Full documentation for every DigitalOcean product.
The Wave has everything you need to know about building a business, from raising funding to marketing your product.
Stay up to date by signing up for DigitalOceanâs Infrastructure as a Newsletter.
New accounts only. By submitting your email you agree to our Privacy Policy
Scale up as you grow â whether you're running one virtual machine or ten thousand.
Sign up and get $200 in credit for your first 60 days with DigitalOcean.*
*This promotional offer applies to new accounts only.