Я ужасно трачу время на поиск правильного способа инициализации TemplateHTMLRenderer для отображения формы для создания объекта. Мой API отлично работает для публикации (форма API для просмотра в формате DRF), но это не решение для внешнего интерфейса.
Я могу создать страницу с подробностями, используя документы и пакеты шаблонов: https://www.django -rest-framework.org / themes / html-and-forms / # render-forms . В документах очень ясно, как создать форму ОБНОВЛЕНИЯ.
Но я не могу на всю жизнь инициализировать одну и ту же форму, чтобы выполнить первоначальное создание.
Мне не нужно вручную писать формы для взаимодействия с API для создания объектов, когда есть функция для автоматически сгенерированных форм ... но я в полном недоумении.
Из views.py рабочий вид обновления:
class LicensedSoftwareDetail(APIView):
model = LicensedSoftware
renderer_classes = [TemplateHTMLRenderer]
template_name = 'licsoftware-detail.html'
def get(self, request, pk):
if pk:
licensedsoftware = get_object_or_404(LicensedSoftware, pk=pk)
serializer = LicensedSoftwareSerializer(licensedsoftware)
return Response({'serializer': serializer, 'licensedsoftware': licensedsoftware})
else:
serializer = LicensedSoftwareSerializer()
return Response({'serializer': serializer})
def post(self, request, pk):
if pk:
licensedsoftware = get_object_or_404(LicensedSoftware, pk=pk)
serializer = LicensedSoftwareSerializer(licensedsoftware, data=request.data)
if not serializer.is_valid():
return Response({'serializer': serializer, 'licensedsoftware': licensedsoftware})
serializer.save()
else:
serializer = LicensedSoftwareSerializer(data=request.data)
serializer.save()
return redirect('../../licsoftware/')
Это вложенный (OneToOne) сериализатор с пользовательскими методами обновления и создания.
из serializers.py:
class SoftwareSerializer(WritableNestedModelSerializer):
class Meta:
model = Software
fields = '__all__'
class LicensedSoftwareSerializer(WritableNestedModelSerializer):
software = SoftwareSerializer()
available = serializers.SerializerMethodField()
class Meta:
model = LicensedSoftware
fields = '__all__'
read_only_fields = ('available',)
def get_available(self, obj):
return int(obj.numpurchased) - obj.software.assignees.count()
def update(self, instance, validated_data):
software_data = validated_data.pop('software')
software = instance.software
for attr, value in software_data.items():
if attr == 'assignees':
instance.software.assignees.set(value)
else:
setattr(software, attr, value)
software.save()
for attr, value in validated_data.items():
setattr(instance, attr, value)
instance.save()
return instance
def create(self, instance, validated_data):
software_data = validated_data.pop('software')
software = instance.software
for attr, value in software_data.items():
if attr == 'assignees':
instance.software.assignees.set(value)
else:
setattr(software, attr, value)
software.save()
for attr, value in validated_data.items():
setattr(instance, attr, value)
instance.save()
return instance
У меня есть шаблон, ссылающийся на форму TemplateHTMLRenderer, и он отлично работает для обновления, когда он может вызвать PK. Однако я не могу создать представление или URL-адрес, который будет извлекать форму для создания / публикации.
Модель:
class Software (models.Model):
brand = models.CharField(max_length=50, blank=True, null=False)
title = models.CharField(max_length=50, blank=True, null=False, verbose_name="Software Title")
version = models.CharField(max_length=50, blank=True, null=False)
website = models.CharField(max_length=100, blank=True, null=False)
active = models.BooleanField()
notes = models.CharField(max_length=1000, blank=True, null=True)
assignees = models.ManyToManyField(User, related_name='software_assigned', blank=True, verbose_name="Installed Users:")
def __str__(self):
return "{0} {1} Version {2}".format(self.brand, self.title, str(self.version))
class LicensedSoftware(models.Model):
software = models.OneToOneField(Software, primary_key=True, on_delete=models.CASCADE)
vehicle = models.CharField(max_length=50, blank=True, null=False, verbose_name="Contract/Purchase Vehicle")
vendor = models.CharField(max_length=50, blank=True, null=False)
licensekey = models.CharField(max_length=50, blank=True, null=False)
subscription = models.BooleanField()
term = models.CharField(max_length=50, blank=True, null=False)
renewaldate = models.DateField(blank=True, null=True, verbose_name="Renew By")
supportincluded = models.BooleanField(verbose_name="Support Included")
numpurchased = models.IntegerField(blank=True, null=False, verbose_name="Licenses Purchased")
Дополнительный вид, который не работает и не включает PK:
class LicensedSoftwareList(APIView):
queryset = LicensedSoftware.objects.all()
serializer_class = LicensedSoftwareSerializer
renderer_classes = [TemplateHTMLRenderer]
template_name = 'licsoftware-detail.html'
def get(self, request, format=None):
licsoftware = LicensedSoftware.objects.all()
serializer = LicensedSoftwareSerializer(licsoftware)
return Response({'result': serializer.data})
def post(self, request, format=None):
serializer = LicensedSoftwareSerializer(data=request.DATA)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Шаблон:
{% extends 'base.html' %}
{% load rest_framework %}
{% block content %}
<h1>Licensed Software - {{ licensedsoftware.software.brand }} {{ licensedsoftware.software.title }} {{ licensedsoftware.software.version }}</h1>
<form class="form-horizontal" method="post" novalidate>
{% csrf_token %}
{% render_form serializer template_pack='rest_framework/horizontal'%}
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-default">Submit!</button>
</div>
</div>
</form>
{% endblock %}
URL:
urlpatterns = [
path('', views.index, name='index'),
path('inventory/', views.inventory, name='inventory'),
path('schema/', schema_view),
path('admin/', admin.site.urls),
path('api/', include(router.urls)),
path('inventory/mobile-detail/<int:pk>/', views.MobileDetail.as_view()),
path('inventory/licsoftware-detail/<int:pk>/', views.LicensedSoftwareDetail.as_view()),
path('inventory/licsoftware-detail/', views.LicensedSoftwareList.as_view()),
path('api-auth/', include('rest_framework.urls', namespace='rest_framework')),
path('docs/', include_docs_urls(title='API Documentation')),
path('profiles/', views.ProfileList.as_view()),
path('profile-detail/<int:pk>/', views.ProfileDetail.as_view()),
path('inventory/licsoftware/', licensedsoftware_view, name='licensed_table'),
path('inventory/mobile/', mobile_view, name='mobile_table'),
API URL работают. Доступный для просмотра API позволит создавать / публиковать.
путь ('инвентарь / licsoftware-detail //', views.LicensedSoftwareDetail.as_view ()), работает
путь ('inventory / licsoftware-detail /', views.LicensedSoftwareList.as_view ()) выдает ошибку:
Получена ошибка AttributeError при попытке получить значение для поля software
на сериализаторе LicensedSoftwareSerializer
.
Поле сериализатора может иметь неправильное имя и не соответствовать ни одному атрибуту или ключу в экземпляре QuerySet
.
Исходный текст исключения был: объект «QuerySet» не имеет атрибута «программное обеспечение».