2
0
mirror of https://expo.survex.com/repositories/troggle/.git synced 2025-12-18 05:37:14 +00:00

utility to find empty fields on databse classes: for tidying

This commit is contained in:
2025-10-11 21:07:43 +03:00
parent 9806212395
commit 905d9af978

View File

@@ -0,0 +1,124 @@
from django.core.management.base import BaseCommand
from django.apps import apps
from django.db.models import Q, CharField, TextField
"""Completely written by https://gemini.google.com/ 2.5
"""
def get_all_project_models():
"""
Returns a list of all concrete model.Model classes in the Django project.
It ignores abstract models and models from third-party apps that aren't
part of the project's own apps.
"""
# You can customize this list to include/exclude specific apps
# For example: installed_apps = settings.INSTALLED_APPS
all_models = []
# This gathers all models from all installed apps.
for app_config in apps.get_app_configs():
all_models.extend(list(app_config.get_models()))
return all_models
def find_empty_or_null_fields(model_class):
"""
Takes a model class and checks every field.
Returns a list of field names for which all database entries
are either NULL or an empty string.
"""
completely_empty_fields = []
# Get the total number of records for this model.
total_records = model_class.objects.count()
# If there are no records, all fields are technically "empty".
# We return an empty list to avoid reporting every field from an empty table.
if total_records == 0:
return []
# Iterate over all concrete fields of the model.
for field in model_class._meta.get_fields():
# We only want to check actual database columns, not relations.
if not hasattr(field, 'column'):
continue
field_name = field.name
# Build a query to find records that have a meaningful value.
# This is more efficient than counting all null/empty records.
# We exclude records that are NULL.
query_has_value = model_class.objects.exclude(Q(**{f'{field_name}__isnull': True}))
# For text-based fields, we also exclude empty strings.
if isinstance(field, (CharField, TextField)):
query_has_value = query_has_value.exclude(Q(**{f'{field_name}': ''}))
# If the query for records WITH a value returns FALSE (no such records exist),
# it means all records for this field are empty or null.
if not query_has_value.exists():
completely_empty_fields.append(field_name)
return completely_empty_fields
class Command(BaseCommand):
help = "Scans all project models to find fields where all entries are empty or null."
def handle(self, *args, **options):
self.stdout.write(self.style.SUCCESS("🚀 Starting scan for empty or null fields across all models..."))
all_models = get_all_project_models()
found_any = False
for model in all_models:
total_records = model.objects.count()
model_name = f"{model._meta.app_label}.{model._meta.object_name}"
self.stdout.write(f"\n🔍 Checking model: {self.style.HTTP_INFO(model_name)} ({total_records} instances found)")
empty_fields = find_empty_or_null_fields(model)
if empty_fields:
found_any = True
for field_name in empty_fields:
self.stdout.write(
self.style.WARNING(f" -> Field '{field_name}' is completely empty or null.")
)
else:
self.stdout.write(self.style.SUCCESS(" ✅ All fields contain data."))
if not found_any:
self.stdout.write(self.style.SUCCESS("\n🎉 Scan complete. No fields were found to be universally empty or null."))
"""
### How to Run the Command
After saving the file, you can run your new command from your project's root directory (where `manage.py` is located):
bash
uv run manage.py find_empty_fields
### Example Output
The output in your terminal will look something like this:
```
🚀 Starting scan for empty or null fields across all models...
🔍 Checking model: auth.Group
✅ All fields contain data.
🔍 Checking model: auth.User
-> Field 'last_name' is completely empty or null.
-> Field 'first_name' is completely empty or null.
🔍 Checking model: products.Product
-> Field 'notes' is completely empty or null.
-> Field 'discount_code' is completely empty or null.
🔍 Checking model: products.Category
✅ All fields contain data.
"""