Package: gdrfile
Генератор файлов для django rest приложенияGdrfile - генератор начальных файлов приложения, который за основу берет модели
из приложения. К начальным файлам относятся: представления, сериализаторы,
тесты, админ-панель, init файлы, роутер.Как установитьPip:pipinstallgdrfilePoetry:poetryaddgdrfileИспользованиеДля генерации файлов в консоли django проекта необходимо прописать команду:gdrfile-pm=path/to/folder/models-pa=path.to.api-an=app_nameДля очистки сгенерированных файлов:gdrfile-clearКоманда имеет следующиеобязательныеаргументы для работы.-pm- Путь до папки models из текущей директории.
Пример: server/apps/name_app/models-pa- Путь до приложения. Пример: server.apps.name_app
Используется для указания корректных импортов-an- Название приложения. Пример: app_nameНеобязательныеаргументы для работы:-pmc- Названия родительских классов моделей, кроме от models.Model и
BaseModel. Пример: BaseModel, MPTTModel
и др. Доступны разделители ';' и ','.-mf- Поля в моделях могут быть из сторонних пакетов. Для их корректного
анализа необходимо указать информацию о них.Необходимо указать тип поля в
модели, тип поля в сериализаторе и тип поля в тестах.
Пример: PhoneField, CharField(), fake.number();
Для корректной работы необходимо поля разделить ',', а в конце поставить ';'-r- Флаг для генерации файлов с учетом прав доступа
(библиотеки django-rules). По умолчанию False.Чтобы не указывать в ручную параметры, существует возможность указать путь до
.env файла.$gdrfile-env=settings/configВ .env файле также необходимо прописать три обязательные переменные:# Путь до папки models из текущей директории.GDRFILE_PATH_TO_MODELS=server/apps/app_name/models# Путь до приложения.GDRFILE_PATH_TO_API=server.apps.app_name# Название приложения.GDRFILE_APP_NAME=app_name# Типы полей могут использоваться из сторонних библиотек.# Первое значение - тип поля для моделей.# Второе значение - тип поля в сериализаторе.# Третье значение - тип поля для тестов в библиотеке faker.GDRFILE_MODEL_FIELDS=TreeForeignKey, None, fake.pyint();# Названия родительских классов моделей, кроме models.Model и BaseModelGDRFILE_PARENT_MODEL_CLASS=MPTTModel, ExampleModel# Флаг для генерации файлов с учетом прав доступаGDRFILE_RULES=FalseИнформация, которая будет получена из моделей:{{path_to_app}} - путь до приложения
{{app_name}} - название приложения
{{AppName}} - название приложения в верблбюжем стиле
{{app-name}} - название приложения с '-'
{{MainClass}} - название модели в верблбюжем стиле
{{main_class}} - название модели с '_'
{{mainclass}} - слитное название модели маленькими буквами 
{{main-class}} - название приложения с '-'
{{docs}} - документация модели
{{list_main_fields}} - список полей модели
fields_django_model - список полей модели с типами, указаннами в моделе
fields_for_serializers - список полей модели с типами для сериализатора
fields_for_conftest - список полей модели с типами для тестовСуществует возможность переопределить шаблоны файлов для генерации.
Для этого в текущем каталоге необходимо создать папку sample
со следующей структурой:sample
  ├── conftest
  │    ├── conftest_factory.py
  │    ├── conftest_fixture.py
  │    └── conftest_import.py
  ├── example_admin.py
  ├── example_init_serializer.py
  ├── example_init_view.py
  ├── example_routers.py
  ├── example_rules.py
  ├── example_serializers.py
  ├── example_tests.py
  ├── example_views.py
  └── example_views_this_rules.pyПримеры сгенерированных файловСериализатор:fromrest_frameworkimportserializersfromserver.apps.mobile_provision.modelsimportAccountclassAccountSerializer(serializers.ModelSerializer):"""Аккаунт."""classMeta(object):model=Accountfields=['user','photo','birth_date','passport_series','passport_number']classAccountSerializer(serializers.Serializer):"""Аккаунт."""user=serializers.None(__change_me__)photo=serializers.ImageField()birth_date=serializers.DateField()passport_series=serializers.CharField()passport_number=serializers.CharField()Представление (доступно как с правами, так и без прав доступа)fromrest_framework.viewsetsimportModelViewSetfromserver.apps.mobile_provision.api.serializersimportAccountSerializerfromserver.apps.mobile_provision.modelsimportAccountclassAccountViewSet(ModelViewSet):"""Аккаунт."""queryset=Account.objects.all()serializer_class=AccountSerializerordering_fields=['user','photo','birth_date','passport_series','passport_number']search_fields=['user','photo','birth_date','passport_series','passport_number']fromrest_framework_extensions.mixinsimportNestedViewSetMixinfromrest_framework.viewsetsimportModelViewSetfromrules.contrib.rest_frameworkimportAutoPermissionViewSetMixinfromserver.apps.mobile_provision.api.serializersimportAccountSerializerfromserver.apps.mobile_provision.modelsimportAccountclassAccountViewSet(NestedViewSetMixin,AutoPermissionViewSetMixin,ModelViewSet,):"""Аккаунт."""queryset=Account.objects.all()serializer_class=AccountSerializerordering_fields=['user','photo','birth_date','passport_series','passport_number']search_fields=['user','photo','birth_date','passport_series','passport_number']permission_type_map={**AutoPermissionViewSetMixin.permission_type_map,'list':'list','metadata':None,}Права доступаimportrulesfromrules.predicatesimportis_authenticatedrules.add_perm('mobile_provision.view_account',is_authenticated)rules.add_perm('mobile_provision.add_account',is_authenticated)rules.add_perm('mobile_provision.change_account',is_authenticated)rules.add_perm('mobile_provision.delete_account',is_authenticated)rules.add_perm('mobile_provision.list_account',is_authenticated)ТестыimportpytestfromfakerimportFakerfromrest_frameworkimportstatusfromrest_framework.reverseimportreversefake=Faker()@pytest.mark.django_db()deftest_account_format(api_client,account,account_format,):"""Формат Account."""url=reverse('api:mobile-provision:account-detail',[account.pk],)json_response=api_client.get(url).json()assertjson_response==account_format(account)@pytest.mark.django_db()deftest_account_post(api_client,):"""Создание Account."""url=reverse('api:mobile-provision:account-list')json_response=api_client.post(url,data={},format='json',)assertjson_response.status_code==status.HTTP_201_CREATED@pytest.mark.django_db()deftest_account_delete(api_client,account,):"""Удаление Account."""url=reverse('api:mobile-provision:account-detail',[account.pk],)json_response=api_client.delete(url)assertjson_response.status_code==status.HTTP_204_NO_CONTENT@pytest.mark.django_db()deftest_account_change(api_client,account,):"""Изменение Account."""url=reverse('api:mobile-provision:account-detail',[account.pk],)json_response=api_client.put(url,data={},format='json',)assertjson_response.status_code==status.HTTP_200_OKАдминкаfromdjango.contribimportadminfromserver.apps.mobile_provision.modelimportAccount@admin.register(Account)classConfigurableAdmin(admin.ModelAdmin[Account]):"""Аккаунт."""list_filter=['user','photo','birth_date','passport_series','passport_number']search_fields=['user','photo','birth_date','passport_series','passport_number']list_display=['user','photo','birth_date','passport_series','passport_number']Файл conftest для тестовimportpytestfromfactoryimportLazyAttribute,SubFactoryfromfactory.djangoimportDjangoModelFactoryfromfakerimportFakerfrompytest_factoryboyimportregisterfromrest_framework.fieldsimportDateTimeFieldfromrest_framework.testimportAPIClientfromserver.apps.mobile_provision.modelsimportAccountfake=Faker()classAccountFactory(DjangoModelFactory):"""Фабрика для Account."""classMeta(object):model=Accountuser=factory.SubFactory(__change_me__)photo=factory.LazyAttribute(lambdaaccount:fake.file_name())birth_date=factory.LazyAttribute(lambdaaccount:fake.date_between())passport_series=factory.LazyAttribute(lambdaaccount:fake.paragraph())passport_number=factory.LazyAttribute(lambdaaccount:fake.paragraph())register(Account)@pytest.fixturedefaccount_format():"""Формат Account."""def_account_format(account:Account):return{'id':account.pk,'user':account.user,'photo':account.photo,'birth_date':account.birth_date,'passport_series':account.passport_series,'passport_number':account.passport_number,}return_account_formatФайл init в папке с сериализаторами. Аналогичный создается для представленийfromserver.apps.app_name.api.serializer.measure_recommendationimportAccountSerializer__all__=['AccountSerializer',]Файл routerfromdjango.utils.translationimportgettext_lazyas_fromdrf_nova_router.api_routerimportApiRouterfromrest_framework.routersimportAPIRootViewfromserver.apps.app_name.api.viewsimportAccountViewSetclassAppNameAPIRootView(APIRootView):"""Корневой view для app."""__doc__=_('Приложение AppName')name=_('app_name')router=ApiRouter()router.APIRootView=AppNameAPIRootViewrouter.register('accounts',AccountViewSet,'accounts')