mirror of
https://expo.survex.com/repositories/troggle/.git
synced 2025-12-18 17:37:11 +00:00
124 lines
4.3 KiB
Python
124 lines
4.3 KiB
Python
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.
|
|
""" |