Лучший способ скрыть записи, не созданные текущим пользователем в Django?

Я довольно новичок в Django, и сейчас я создал сайт, который позволяет пользователям регистрироваться/входить в систему, делать записи, которые ассоциируются с этим пользователем через поле "user" в базе данных записей.

Мне удалось получить всю функциональность скрытия записей других пользователей, добавив методы get_queryset(), которые возвращают только записи текущего пользователя.

Но я чувствую, что это плохой способ сделать это. Мне кажется, что я повторно использую много кода, и что могут быть "черные ходы" для отображения записей других пользователей.

Есть ли способ полностью отключить записи других пользователей от текущего пользователя, а не просто не отображать их?

views.py

class EntryListView(LockedView, ListView):
    model = Entry

    def get_queryset(self):
        return super().get_queryset().filter(user=self.request.user).order_by("-date_created")

class EntryDetailView(LockedView, DetailView):
    model = Entry

    def get_queryset(self):
        return super().get_queryset().filter(user=self.request.user)

class EntryCreateView(LockedView, SuccessMessageMixin, CreateView):
    model = Entry
    fields = ["title", "content"]
    success_url = reverse_lazy("entry-list")
    success_message = "Your new entry was created!"

    def form_valid(self, form):
         user = self.request.user
         form.instance.user = user
         return super(EntryCreateView, self).form_valid(form)
    
    def get_queryset(self):
        return super().get_queryset().filter(user=self.request.user)

class EntryUpdateView(LockedView, SuccessMessageMixin, UpdateView):
    model = Entry
    fields = ["title", "content"]
    success_message = "Your entry was updated!"

    def get_success_url(self):
        return reverse_lazy(
            "entry-detail",
            kwargs={"pk": self.object.pk}
        )

    def get_queryset(self):
        return super().get_queryset().filter(user=self.request.user)

Виды Create, Detail и Update ссылаются на одну единственную запись (и связь с этой записью осуществляется по url kwarg (он может быть общим 'pk' или 'slug' и т.д.), поэтому get_queryset внутри этих 3 видов на самом деле не помогает.

Если вы откроете запись в браузере, вы увидите, что url будет выглядеть примерно так: /entry/<id_of_entry>, поэтому если вы измените это значение, вы получите доступ к другому объекту. Если вы хотите предотвратить доступ пользователей к записям, которые им не принадлежат, вы можете создать некоторый миксин, например, такой:

class EntryMixin:
"""
Prevent users to access entries that has different author
"""
def dispatch(self, request, *args, **kwargs):
    if not self.get_object().user == request.user:
        raise PermissionError
    return super().dispatch(request, *args, **kwargs)

Здесь происходит следующее: каждый раз, когда пользователь получает доступ к определенному представлению, он будет проверять, назначен ли он на этот объект (обратите внимание, что этот миксин будет работать только с представлениями одного объекта (detail, update, delete), для списка потребуется модификация.

).

Создайте сериализатор для модели Entry и предоставьте поле, которое вы хотите отобразить. Сделайте пользовательское поле доступным только для чтения, чтобы.

serializers.py

from rest_framework import serializers

class EntriesSerializer(serializers.ModelSerializer):
    class Meta:
        model = Entry
        fields = '__all__'
        extra_kwargs = {
            'user': {'read_only': True}
        }

Затем создайте Viewset для записей, которые могут легко выполнять грубые операции. переопределите метод get_queryset для получения записей текущего пользователя. Также переопределите метод perform_create для предоставления текущего пользователя в качестве пользователя записи при создании новой записи.

views.py

from rest_framework import viewsets, mixins
from .serializers import EntriesSerializer

class EntriesViewSet(
        mixins.CreateModelMixin,
        mixins.ListModelMixin,
        mixins.RetrieveModelMixin,
        mixins.DestroyModelMixin,
        mixins.UpdateModelMixin,
        viewsets.GenericViewSet
    ):
    serializer_class = EntriesSerializer

    def get_queryset(self):
        queryset = Entry.objects.filter(user=self.request.user)
        return queryset

    def perform_create(self, serializer):
        serializer.save(user=self.request.user)

Создайте маршрутизатор для viewset и зарегистрируйте viewset в маршрутизаторе. Затем включите урлы маршрутизатора в urlpatterns.

urls.py

from django.urls import path, include
from rest_framework.routers import DefaultRouter
from . import views

router = DefaultRouter()
router.register('entries', EntriesViewSet, basename='entries')

urlpatterns = [
    path('', include(router.urls)),
]

Теперь вы можете получить доступ к списку всех записей, созданных текущим пользователем, через /entries/, а для получения подробной информации об отдельной записи используйте /entries/<entry_id>/.

Вернуться на верх