Условные кверисеты Django
Я пытаюсь показать сервер пользователю, только если пользователь является модератором или создателем сервера.
поэтому я написал такой код:
class ServerModeratingView(LoginRequiredMixin, View):
def get(self, request, server_tag):
moderator = ServerModerator.objects.get(user=request.user)
server = Server.objects.get(Q(tag=server_tag), Q(creator=request.user) | Q(moderators=moderator))
...
Я думал, что объект Q сделает этот код условным, например, если
request.user
не является создателем, то пользователь является модератором.
Это работает нормально, если пользователь является модератором сервера
но создатель (создатель не является одним из модераторов, поэтому moderator
queryset будет пуст)
показывает эту ошибку:
ServerModerator matching query does not exist.
models.py:
class Server(models.Model):
...
tag = models.CharField(max_length=50, unique=True)
moderators = models.ManyToManyField('ServerModerator', related_name='server')
...
class ServerModerator(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='moderator_of')
allow_create_tag = models.BooleanField(default=True)
allow_create_rule = models.BooleanField(default=False)
allow_remove_user = models.BooleanField(default=True)
allow_remove_moderator = models.BooleanField(default=False)
allow_delete_post = models.BooleanField(default=False)
Если пользователь не существует, ServerModerator .get()
вернет ошибку. Подобную той, что вы видите выше. В качестве альтернативы, вы можете фильтровать следующим образом:
server = Server.objects.get(
models.Q(moderators__user={{your user}}) \
| models.Q(creator={{your user}}) \
& models.Q(tag=server_tag))
Он проверит, если тег и пользователь оба фильтруют до одного экземпляра, ИЛИ если пользователь является модератором сервера A. Если он не может найти ни одного, то выдает ошибку.
Кроме того, если вы используете .get на сервере, а ваш пользователь владеет 2 серверами, это приведет к ошибке MultipleObjectsReturned
.
(Хотя я не знаю, относится ли это к вашему проекту)
Другой способ написать это с некоторыми самодельными проверками, которые вы также можете сделать на уровне QuerySet, если вы планируете использовать это чаще:
try:
#Filter if the user is a creator of the server.
server = Server.objects.get(creator=self.request.user, tag=server_tag)
except Server.DoesNotExist:
# User is not a creator. Check if he's a moderator.
moderator = get_object_or_404(ServerModerator, user=self.request.user) #If not moderator, raise 404.
server = Server.objects.get(moderators=moderator)
# Or without making an extra query,
# which is preferred if you don't do anything else with
# the moderator in this view.
# Use the below:
# server = get_object_or_404(Server, moderators__user=self.request.user)
Вы сказали:
Я думал, что объект Q сделает этот код условным, например, если request.user не является создателем, то пользователь является модератором.
По этой логике любой пользователь, не являющийся создателем, БУДЕТ модератором, а не МОЖЕТ им быть.
Во-первых, используйте get_object_or_404()
вместо get()
, так как он вызывает get() на данном менеджере моделей, но вызывает Http404 вместо DoesNotExist исключение .
Вызовет ошибку Http404, если ничего не найдено.
<<<Во-вторых, при использовании представлений на основе классов используйте, как указано @nigel239.self.request.user
Со:
class ServerModeratingView(LoginRequiredMixin, View):
def get(self, request, server_tag):
moderator = get_object_or_404(ServerModerator,user=self.request.user)
server = Server.objects.get(Q(tag=server_tag), Q(creator=self.request.user) | Q(moderators=moderator))
...