DRF-фильтр поисков в HTML-формах
Я использую Django 3.05, Django Rest Framework 3.11.0, Python 3.7
Задний план
Я установил модель безопасности на уровне объектов, чтобы гарантировать User
может только читать / записывать данные в Organisation
или Venue
к которому у них есть доступ. Это контролируется черезOrganisationMembership
отображение User
к Organisation
.
Чтобы создать или обновить Venue
пользователь должен быть назначен Organisation
.
Все это работает через API Django Rest Framework, когда используется способ доступа моего приложения. Это требует небольшой настройки, но дает желаемые разрешения. Однако я также использую HTML-формы DRF для тестирования, и я не могу найти какой-либо механизм для изменения QuerySet, чтобы ограничить доступ к именам организаций в раскрывающемся списке.
Поэтому в раскрывающемся списке неправильно отображается Совершенно секретно. Organisation
данные, к которым мне не разрешено OrganisationMember
+-----------+--------------+
| Raw Data | HTML Form |
+----------------------------------------------+ +
| |
| Organisation: v☑︎ Org 2 - I have access (McDonald's) v |
| v Org 1 - I have access (Burger King) v |
| v Org 3 - I should not see (Top Secret) v |
+-------------------------------------------------------------+
Снимок экрана здесь 1 Примечание атрибуты на снимке экрана отличаются для упрощения
Проблема
Есть ли способ применить фильтры к автоматически генерируемым раскрывающимся спискам в HTML-формах Django Rest Framework?
Я понимаю, что это взаимодействие в HTML можно отключить в производственной среде, но я не хочу рисковать.
Код и вывод
Вывод API
локальный хост / API / организации
HTTP 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept
[
{
"id": 2,
"name": "Org 2 - I have access",
"code": "McDonalds",
},
{
"id": 1,
"name": "Org 1 - I have access",
"code": "Burger King",
}
]
Note: Organisation
ID 3 is not returned (correct)
locahost/api/venues/
HTTP 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept
[
{
"id": 48,
"address": "1 High Street, London",
"capacity": "200",
"organisation": 2
},
{
"id": 49,
"address": "18 High Street, London",
"capacity": "140",
"organisation": 1
}
}
Note: Venue
ID 50 from Organisation
ID 3 is not returned (correct)
CODE
models.py
class Organisation(models.Model):
name = models.CharField(max_length=100)
# confirm this user permitted to see Organisation
def permitted(self, obj, user):
print(user)
c = Organisation.objects.filter(
pk=obj.pk,
organisationmember__reg_user__user=user).count()
return c
class Venue(models.Model):
address = models.CharField(max_length=200)
capacity = models.InterField()
organisation = models.ForeignKey(Organisation, on_delete=models.CASCADE)
# confirm this user permitted to see Organisation Venues
def permitted(self, obj, user):
c = Venue.objects.filter(
pk=obj.pk,
organisation__organisationmember__reg_user__user=user).count()
return c
# User Django User security via RegUser to store email address (and others)
class RegUser(model.Model):
user = models.OneToOneField('auth.User', on_delete=models.CASCADE)
email = models.EmailField(max_length=100, blank=False, unique=True)
# Permission to view/edit if RegUser is a member of Organisation
class OrganisationMember(model.Model):
organisation = models.ForeignKey(Organisation, models.CASCADE)
reg_user = models.ForeignKey(RegUser, models.CASCADE)
serializer.py
class VenueSerializer(serializers.ModelSerializer):
class Meta:
model = Venue
fields = '__all__'
view.py
class VenueViewSet(viewsets.ModelViewSet):
serializer_class = VenueSerializer
# You must be authenticated, and have permission to see this Organisation (Update, Delete)
permission_classes = [IsAuthenticated, OrganisationPermission]
# get queryset filtering on user's organisation membership (Get/Query)
def get_queryset(self):
# You may only view organisation questions to which you are an active member
user = self.request.user
return OrganisationQuestion.objects.filter(
organisation__organisationmember__reg_user__user=user,
organisation__organisationmember__status='A')
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
if user_permitted(self.request.user, serializer.validated_data["organisation"]):
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
else:
return Response(serializer.data, status=status.HTTP_403_FORBIDDEN)