Сохраните все объекты в QuerySet и связанные с ними объекты в приспособлении
Я написал функцию для сохранения QuerySet в JSON-файл с фиксацией:
def save_as_fixture(query_set: QuerySet, fixture_name: str, app_label: str='mainapp'):
app_config = apps.get_app_config(app_label)
fixture_dir = os.path.join(app_config.path, "fixtures")
os.makedirs(fixture_dir, exist_ok=True)
fixture_path = os.path.join(fixture_dir, fixture_name)
data = serializers.serialize("json", query_set, indent=2, use_natural_foreign_keys=True, use_natural_primary_keys=True)
with open(fixture_path, 'w') as file:
file.write(data)
Но он не сохраняет связанные объекты.
Я хотел бы, чтобы он также сохранял объекты, которые ссылаются на один из объектов QuerySet через ForeignKey
, OneToOneField
и т. д. Как это сделать?
Ваша функция корректно сериализует QuerySet в JSON-фикс, сохраняя внешние и первичные ключи в их естественных значениях. Однако она не включает автоматически связанные объекты, что может стать проблемой, если вам нужен полный набор данных.
Расширение функции для включения связанных объектов Вам нужно убедиться, что все связанные объекты (например, внешние ключи, отношения «многие-ко-многим») включены в приспособление. Это можно сделать с помощью рекурсивной выборки связанных объектов.
Улучшенная версия
import os
from django.apps import apps
from django.core import serializers
from django.db.models import QuerySet
def get_related_objects(queryset):
"""Recursively collect all related objects for the given queryset."""
collected_objects = set(queryset)
for obj in queryset:
for field in obj._meta.get_fields():
if field.is_relation and not field.auto_created:
related_objects = getattr(obj, field.name)
if related_objects is None:
continue
if field.many_to_many or field.one_to_many:
related_queryset = related_objects.all()
else:
related_queryset = [related_objects]
collected_objects.update(related_queryset)
collected_objects.update(get_related_objects(related_queryset))
return collected_objects
def save_as_fixture(queryset: QuerySet, fixture_name: str, app_label: str = 'mainapp'):
"""Save a queryset and its related objects to a JSON fixture file."""
app_config = apps.get_app_config(app_label)
fixture_dir = os.path.join(app_config.path, "fixtures")
os.makedirs(fixture_dir, exist_ok=True)
fixture_path = os.path.join(fixture_dir, fixture_name)
# Collect all related objects
full_queryset = get_related_objects(queryset)
# Serialize to JSON
data = serializers.serialize("json", full_queryset, indent=2,
use_natural_foreign_keys=True,
use_natural_primary_keys=True)
# Write to file
with open(fixture_path, 'w') as file:
file.write(data)
Как это работает get_related_objects(queryset): Рекурсивно находит все связанные объекты (внешние ключи, многие-ко-многим, один-ко-многим). save_as_fixture(): Собирает полный набор данных, включая связанные объекты. Сериализует его в JSON-фикстуру. Сохраняет его в каталоге fixtures внутри указанного приложения Django. Почему это лучше ✅ Автоматически включает все связанные объекты. ✅ Обеспечивается полная целостность данных при загрузке фикстуры. ✅ Предотвращает отсутствие зависимостей при восстановлении базы данных.
Теперь, когда вы звоните:
save_as_fixture(MyModel.objects.filter(some_condition), "my_fixture.json")
Он сохранит экземпляры MyModel вместе со всеми связанными с ними объектами. 🚀