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:
124
core/management/commands/find_empty_fields.py
Normal file
124
core/management/commands/find_empty_fields.py
Normal 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.
|
||||
"""
|
||||
Reference in New Issue
Block a user