Если у меня есть представление, которое обрабатывает управление друзьями, то есть имеется представление для добавления, удаления, блокировки, разблокировки и принятия / отклонения приглашений стать друзьями. Проблема, с которой я столкнулся, заключается в том, что я пытаюсь предоставить значимые ошибки пользователям, которые в конечном итоге получают URL, которого не должно быть.
Например, если Пользователь1 и Пользователь2 уже являются друзьями, а Пользователь1 переходит на URL для добавления Пользователь2 в качестве друга вместо друга форма представляется так, как если бы они не были друзьями, а форма не работает unique_together = (('user_from', 'user_to'),)
, она отображает предупреждающее сообщение и перенаправляет их на соответствующую страницу перед отображением формы.
Как это
def add_friend(request, username):
try:
user = User.objects.get(username=username)
except User.DoesNotExist:
messages.error(request, 'A user with the username %s does not exist. \
Try searching for the user below.' % username)
return HttpResponseRedirect(reverse('friends_find_friend'))
if Friend.objects.are_friends(request.user, user):
messages.error(request, 'You are already friends with %s' % user)
return HttpResponseRedirect(reverse('profiles_profile_detail', args=[user]))
Сюда также входит проверочное и значимое сообщение об ошибке (вместо 404), если такого пользователя нет.
Это легко обрабатывать, но с другими проверками оно увеличивается до
def add_friend(request, username):
try:
user = User.objects.get(username=username)
except User.DoesNotExist:
messages.error(request, 'A user with the username %s does not exist. \
Try searching for the user below.' % username)
return HttpResponseRedirect(reverse('friends_find_friend'))
if user == request.user:
messages.error(request, 'You are already friends with yourself')
return HttpResponseRedirect(reverse('friends_find_friend'))
if Enemy.objects.is_blocked(request.user, user):
messages.error(request, '%s has blocked you from adding them as a friend' % user)
return HttpResponseRedirect(reverse('friends_find_friend'))
if Enemy.objects.has_blocked(request.user, user):
messages.error(request, 'You have blocked %s so you cannot add them as a friend' % user)
return HttpResponseRedirect(reverse('profiles_profile_detail', args=[user]))
if Friend.objects.are_friends(request.user, user):
messages.error(request, 'You are already friends with %s' % user)
return HttpResponseRedirect(reverse('profiles_profile_detail', args=[user]))
if FriendRequest.objects.invitation_sent(request.user, user):
messages.error(request, 'You already sent %s a request. You need to \
wait for them to reply to it.' % user)
return HttpResponseRedirect(reverse('friends_pending'))
if FriendRequest.objects.invitation_received(request.user, user):
messages.error(request, '%s already sent you a request and is waiting \
for you to respond to them.' % user)
return HttpResponseRedirect(reverse('friends_pending'))
Все это снова дублируется в
- remove_friend
- block_user
- unblock_user
- pending_invitations
И далее дублируется как ошибки проверки формы в случае, если представление обойдено в оболочке и форма используется независимо.
Я спрашиваю, есть ли более питонский способ сделать это без чрезмерного копирования и вставки?
Редактировать
Я пытался решить эту проблему и задавался вопросом, будет ли что-то подобное хорошим способом.
tests = ((Enemy.objects.is_blocked, 'This user has blocked you', reverse('friends_find_friend')),
(Enemy.objects.has_blocked, 'You have blocked this user', reverse('profiles_profile_detail', args=[user])),)
for test in tests:
if test[0](request.user, user):
messages.error(request, test[1])
return HttpResponseRedirect(test[2])
Тесты будут определены в другом файле, похожем на шаблоны URL, и декоратор обернет функцию просмотра для выполнения всех тестов, перенаправит, если что-то не получится, и, наконец, передаст ее функции просмотра, если все хорошо. Будет ли это эффективным способом управления без засорения файла представления сотнями строк стандартного кода?
Редактировать2 :
Мне также интересно посмотреть, как другие делают подобные вещи. Я сомневаюсь, что я первый, кто хочет показать сообщение пользователю, а не просто выбросить страницу 404.