Skip to content

Commit aff19e5

Browse files
committed
initial commit
0 parents  commit aff19e5

22 files changed

+522
-0
lines changed

django_index_project/__init__.py

Whitespace-only changes.

django_index_project/asgi.py

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
"""
2+
ASGI config for django_index_project project.
3+
4+
It exposes the ASGI callable as a module-level variable named ``application``.
5+
6+
For more information on this file, see
7+
https://docs.djangoproject.com/en/5.1/howto/deployment/asgi/
8+
"""
9+
10+
import os
11+
12+
from django.core.asgi import get_asgi_application
13+
14+
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_index_project.settings")
15+
16+
application = get_asgi_application()

django_index_project/settings.py

+135
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
"""
2+
Django settings for django_index_project project.
3+
4+
Generated by 'django-admin startproject' using Django 5.1.3.
5+
6+
For more information on this file, see
7+
https://docs.djangoproject.com/en/5.1/topics/settings/
8+
9+
For the full list of settings and their values, see
10+
https://docs.djangoproject.com/en/5.1/ref/settings/
11+
"""
12+
13+
from pathlib import Path
14+
15+
# Build paths inside the project like this: BASE_DIR / 'subdir'.
16+
BASE_DIR = Path(__file__).resolve().parent.parent
17+
18+
19+
# Quick-start development settings - unsuitable for production
20+
# See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/
21+
22+
# SECURITY WARNING: keep the secret key used in production secret!
23+
SECRET_KEY = "django-insecure-+031!wnlhf@ij86qi%7mu^f+r4hhezl=tz&05mvbopvh^)g_@u"
24+
25+
# SECURITY WARNING: don't run with debug turned on in production!
26+
DEBUG = True
27+
28+
ALLOWED_HOSTS = ["*"]
29+
30+
31+
# Application definition
32+
33+
INSTALLED_APPS = [
34+
"django.contrib.admin",
35+
"django.contrib.auth",
36+
"django.contrib.contenttypes",
37+
"django.contrib.sessions",
38+
"django.contrib.messages",
39+
"django.contrib.staticfiles",
40+
"product",
41+
]
42+
43+
MIDDLEWARE = [
44+
"django.middleware.security.SecurityMiddleware",
45+
"django.contrib.sessions.middleware.SessionMiddleware",
46+
"django.middleware.common.CommonMiddleware",
47+
"django.middleware.csrf.CsrfViewMiddleware",
48+
"django.contrib.auth.middleware.AuthenticationMiddleware",
49+
"django.contrib.messages.middleware.MessageMiddleware",
50+
"django.middleware.clickjacking.XFrameOptionsMiddleware",
51+
]
52+
53+
ROOT_URLCONF = "django_index_project.urls"
54+
55+
TEMPLATES = [
56+
{
57+
"BACKEND": "django.template.backends.django.DjangoTemplates",
58+
"DIRS": [],
59+
"APP_DIRS": True,
60+
"OPTIONS": {
61+
"context_processors": [
62+
"django.template.context_processors.debug",
63+
"django.template.context_processors.request",
64+
"django.contrib.auth.context_processors.auth",
65+
"django.contrib.messages.context_processors.messages",
66+
],
67+
},
68+
},
69+
]
70+
71+
WSGI_APPLICATION = "django_index_project.wsgi.application"
72+
73+
74+
# Database
75+
# https://docs.djangoproject.com/en/5.1/ref/settings/#databases
76+
77+
# DATABASES = {
78+
# 'default': {
79+
# 'ENGINE': 'django.db.backends.sqlite3',
80+
# 'NAME': BASE_DIR / 'db.sqlite3',
81+
# }
82+
# }
83+
84+
DATABASES = {
85+
"default": {
86+
"ENGINE": "django.db.backends.postgresql",
87+
"HOST": "127.0.0.1",
88+
"PORT": 5432,
89+
"USER": "monitaur",
90+
"PASSWORD": "dummy",
91+
"NAME": "monitaur",
92+
}
93+
}
94+
95+
96+
# Password validation
97+
# https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators
98+
99+
AUTH_PASSWORD_VALIDATORS = [
100+
{
101+
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
102+
},
103+
{
104+
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
105+
},
106+
{
107+
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
108+
},
109+
{
110+
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
111+
},
112+
]
113+
114+
115+
# Internationalization
116+
# https://docs.djangoproject.com/en/5.1/topics/i18n/
117+
118+
LANGUAGE_CODE = "en-us"
119+
120+
TIME_ZONE = "UTC"
121+
122+
USE_I18N = True
123+
124+
USE_TZ = True
125+
126+
127+
# Static files (CSS, JavaScript, Images)
128+
# https://docs.djangoproject.com/en/5.1/howto/static-files/
129+
130+
STATIC_URL = "static/"
131+
132+
# Default primary key field type
133+
# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field
134+
135+
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"

django_index_project/urls.py

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
"""
2+
URL configuration for django_index_project project.
3+
4+
The `urlpatterns` list routes URLs to views. For more information please see:
5+
https://docs.djangoproject.com/en/5.1/topics/http/urls/
6+
Examples:
7+
Function views
8+
1. Add an import: from my_app import views
9+
2. Add a URL to urlpatterns: path('', views.home, name='home')
10+
Class-based views
11+
1. Add an import: from other_app.views import Home
12+
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
13+
Including another URLconf
14+
1. Import the include() function: from django.urls import include, path
15+
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
16+
"""
17+
18+
from django.contrib import admin
19+
from django.urls import path
20+
21+
urlpatterns = [
22+
path("admin/", admin.site.urls),
23+
]

django_index_project/wsgi.py

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
"""
2+
WSGI config for django_index_project project.
3+
4+
It exposes the WSGI callable as a module-level variable named ``application``.
5+
6+
For more information on this file, see
7+
https://docs.djangoproject.com/en/5.1/howto/deployment/wsgi/
8+
"""
9+
10+
import os
11+
12+
from django.core.wsgi import get_wsgi_application
13+
14+
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_index_project.settings")
15+
16+
application = get_wsgi_application()

manage.py

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#!/usr/bin/env python
2+
"""Django's command-line utility for administrative tasks."""
3+
import os
4+
import sys
5+
6+
7+
def main():
8+
"""Run administrative tasks."""
9+
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "django_index_project.settings")
10+
try:
11+
from django.core.management import execute_from_command_line
12+
except ImportError as exc:
13+
raise ImportError(
14+
"Couldn't import Django. Are you sure it's installed and "
15+
"available on your PYTHONPATH environment variable? Did you "
16+
"forget to activate a virtual environment?"
17+
) from exc
18+
execute_from_command_line(sys.argv)
19+
20+
21+
if __name__ == "__main__":
22+
main()

product/__init__.py

Whitespace-only changes.

product/admin.py

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from django.contrib import admin
2+
3+
# Register your models here.
4+
from .models import (
5+
ProductWithCompositeIndex,
6+
ProductWithSingleIndex,
7+
ProductWithoutIndex,
8+
)
9+
10+
admin.site.register(ProductWithCompositeIndex)
11+
admin.site.register(ProductWithoutIndex)
12+
admin.site.register(ProductWithSingleIndex)

product/apps.py

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from django.apps import AppConfig
2+
3+
4+
class ProductConfig(AppConfig):
5+
default_auto_field = "django.db.models.BigAutoField"
6+
name = "product"

product/management/__init__.py

Whitespace-only changes.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import factory
2+
import random
3+
4+
from product.models import (
5+
ProductWithCompositeIndex,
6+
ProductWithSingleIndex,
7+
ProductWithoutIndex,
8+
)
9+
10+
11+
class ProductFactoryMeta(factory.Factory):
12+
name = factory.Faker("name")
13+
category = lambda x: x.category
14+
price = factory.LazyAttribute(lambda _: random.randint(1, 1000))
15+
16+
class Meta:
17+
abstract = True
18+
19+
class Params:
20+
category = "category1"
21+
22+
23+
class ProductWithoutIndexFactory(
24+
factory.django.DjangoModelFactory, ProductFactoryMeta
25+
):
26+
27+
class Meta:
28+
model = ProductWithoutIndex
29+
30+
31+
class ProductWithSingleIndexFactory(
32+
factory.django.DjangoModelFactory, ProductFactoryMeta
33+
):
34+
35+
class Meta:
36+
model = ProductWithSingleIndex
37+
38+
39+
class ProductWithCompositeIndexFactory(
40+
factory.django.DjangoModelFactory, ProductFactoryMeta
41+
):
42+
43+
class Meta:
44+
model = ProductWithCompositeIndex
45+
+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
from django.core.management.base import BaseCommand, CommandParser
2+
3+
from pprint import pprint
4+
import json
5+
6+
from product.models import (
7+
ProductWithCompositeIndex,
8+
ProductWithSingleIndex,
9+
ProductWithoutIndex,
10+
)
11+
12+
from django.db.models import Q
13+
14+
15+
class Command(BaseCommand):
16+
help = "Test select queries with and without indexes"
17+
18+
def add_arguments(self, parser: CommandParser):
19+
parser.add_argument(
20+
"--table_type",
21+
type=int,
22+
default=1,
23+
help="1: ProductWithoutIndex, 2: ProductWithSingleIndex, 3: ProductWithCompositeIndex",
24+
)
25+
parser.add_argument(
26+
"--category",
27+
type=str,
28+
choices=["electronics", "clothing", "home appliances"],
29+
help="category",
30+
)
31+
32+
parser.add_argument(
33+
"--price",
34+
type=int,
35+
help="price",
36+
)
37+
38+
def handle(self, *args, **kwargs):
39+
print("Running tests...")
40+
41+
table_type = kwargs.get("table_type")
42+
if table_type < 1 or table_type > 3:
43+
print("Table type must be between 1 and 3")
44+
return
45+
46+
if table_type == 1:
47+
table_model = ProductWithoutIndex
48+
elif table_type == 2:
49+
table_model = ProductWithSingleIndex
50+
else:
51+
table_model = ProductWithCompositeIndex
52+
53+
category = kwargs.get("category", None)
54+
price = kwargs.get("price", None)
55+
56+
if category and price:
57+
queryset = table_model.objects.filter(Q(category=category) & Q(price__lte=price))
58+
elif category:
59+
queryset = table_model.objects.filter(category=category)
60+
elif price:
61+
queryset = table_model.objects.filter(price__lte=price)
62+
else:
63+
queryset = table_model.objects.all()
64+
65+
explain_output = queryset.explain(analyze=True, verbose=True, format="json")
66+
pprint(json.loads(explain_output))
+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
2+
from django.core.management.base import BaseCommand
3+
from django.core.management import call_command
4+
5+
from .factory_data import (
6+
ProductWithCompositeIndexFactory,
7+
ProductWithSingleIndexFactory,
8+
ProductWithoutIndexFactory,
9+
)
10+
11+
12+
class Command(BaseCommand):
13+
help = "Seed the database with dummy data with 3 different categories (electronics, clothing, home appliances)"
14+
15+
def handle(self, *args, **kwargs):
16+
print("Seeding data...")
17+
call_command("flush", "--noinput")
18+
19+
for category in ["electronics", "clothing", "home appliances"]:
20+
print(f"Seeding data for category: {category}")
21+
print("*" * 50)
22+
print("\nCreating 500,000 records for ProductWithoutIndex")
23+
ProductWithoutIndexFactory.create_batch(500000, category=category)
24+
print("#" * 50)
25+
print("\nCreating 500,000 records for ProductWithSingleIndex")
26+
27+
ProductWithSingleIndexFactory.create_batch(500000, category=category)
28+
print("#" * 50)
29+
print("\nCreating 500,000 records for ProductWithCompositeIndex")
30+
ProductWithCompositeIndexFactory.create_batch(500000, category=category)
31+
32+
print("#" * 50)
33+
print("Done")
34+
35+
print("Data seeded successfully")

0 commit comments

Comments
 (0)