Я работаю с Python 3.7.3 и Django 2.0.13.
По сути, я хочу показать на своем веб-сайте форму, в которую можно ввести пользователя (= участника в определении модели ниже). Django ModelForm автоматически делает это в поле выбора и показывает раскрывающийся список со всеми пользователями. Я не хочу показывать список всех пользователей в выпадающем меню и хочу вместо этого поле TextInput.
Код:
Во-первых, соответствующая часть от models.py:
class Invite(models.Model):
game = models.ForeignKey(Game, on_delete=models.CASCADE)
host = models.ForeignKey(User, on_delete=models.CASCADE, related_name = "invites_as_host")
participant = models.ForeignKey(User, on_delete=models.CASCADE, related_name = "invites_as_participant")
accepted = models.BooleanField(blank = True, default = False)
declined = models.BooleanField(blank = True, default = False)
date_created = models.DateTimeField(auto_now_add=True)
date_edited = models.DateTimeField(auto_now=True)
class Meta:
unique_together = ["game", "host", "participant"]
forms.py:
class GameInviteNewForm(forms.ModelForm):
class Meta:
model = Invite
fields = ["participant"]
Я пытался переписать поле ввода участника следующим образом:
class GameInviteNewForm(forms.ModelForm):
participant = forms.CharField(
label=_("User to invite"),
max_length=100,
widget = forms.TextInput
)
class Meta:
model = Invite
fields = ["participant"]
views.py (если уместно; я не думаю, что он даже доходит до "form_valid", не так ли?)
class GameInviteNewView(LoginRequiredMixin, UserIsLeaderMixin, FormView):
form_class = GameInviteNewForm
template_name = "app/game/new_invite.html"
pk_url_kwarg = "game_id"
def get_success_url(self):
return reverse_lazy("app:game_invite", kwargs={
"game_id": self.kwargs['game_id']
})
def form_valid(self, form):
participant = form.save(commit=False)
participant = User.objects.get(username=participant.name)
host = User.objects.get(username=self.request.user.username)
game = Game.objects.get(id=self.kwargs['game_id'])
invite.participant_id = participant.id
invite.host_id = host.id
invite.game_id = game.id
invite.save()
return redirect(self.get_success_url())
Это действительно показывает поле TextInput на веб-сайте, но если я ввожу имя пользователя («test»), я получаю ошибку:
Internal Server Error: /app/game/invite/7
Traceback (most recent call last):
File "/home/dremet/anaconda3/envs/django/lib/python3.7/site-packages/django/core/handlers/exception.py", line 35, in inner
response = get_response(request)
File "/home/dremet/anaconda3/envs/django/lib/python3.7/site-packages/django/core/handlers/base.py", line 128, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/home/dremet/anaconda3/envs/django/lib/python3.7/site-packages/django/core/handlers/base.py", line 126, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/dremet/anaconda3/envs/django/lib/python3.7/contextlib.py", line 74, in inner
return func(*args, **kwds)
File "/home/dremet/anaconda3/envs/django/lib/python3.7/site-packages/django/views/generic/base.py", line 69, in view
return self.dispatch(request, *args, **kwargs)
File "/home/dremet/anaconda3/envs/django/lib/python3.7/site-packages/django/contrib/auth/mixins.py", line 52, in dispatch
return super().dispatch(request, *args, **kwargs)
File "/home/dremet/anaconda3/envs/django/lib/python3.7/site-packages/django/contrib/auth/mixins.py", line 109, in dispatch
return super().dispatch(request, *args, **kwargs)
File "/home/dremet/anaconda3/envs/django/lib/python3.7/site-packages/django/views/generic/base.py", line 89, in dispatch
return handler(request, *args, **kwargs)
File "/home/dremet/anaconda3/envs/django/lib/python3.7/site-packages/django/views/generic/edit.py", line 141, in post
if form.is_valid():
File "/home/dremet/anaconda3/envs/django/lib/python3.7/site-packages/django/forms/forms.py", line 179, in is_valid
return self.is_bound and not self.errors
File "/home/dremet/anaconda3/envs/django/lib/python3.7/site-packages/django/forms/forms.py", line 174, in errors
self.full_clean()
File "/home/dremet/anaconda3/envs/django/lib/python3.7/site-packages/django/forms/forms.py", line 378, in full_clean
self._post_clean()
File "/home/dremet/anaconda3/envs/django/lib/python3.7/site-packages/django/forms/models.py", line 396, in _post_clean
self.instance = construct_instance(self, self.instance, opts.fields, opts.exclude)
File "/home/dremet/anaconda3/envs/django/lib/python3.7/site-packages/django/forms/models.py", line 60, in construct_instance
f.save_form_data(instance, cleaned_data[f.name])
File "/home/dremet/anaconda3/envs/django/lib/python3.7/site-packages/django/db/models/fields/__init__.py", line 838, in save_form_data
setattr(instance, self.name, data)
File "/home/dremet/anaconda3/envs/django/lib/python3.7/site-packages/django/db/models/fields/related_descriptors.py", line 197, in __set__
self.field.remote_field.model._meta.object_name,
ValueError: Cannot assign "'test'": "Invite.participant" must be a "User" instance.
В раскрывающемся списке указаны идентификаторы пользователя в атрибуте «value» каждой опции. Теперь строка введена. Поэтому я не удивлен, что это не работает, но я удивлен, что в сообщении об ошибке говорится, что это должен быть «Пользователь» (не идентификатор пользователя).
Я пытался переписать метод "clean ()" и использовать обычную форму, но оба безуспешно. Как это правильно обрабатывать?
Решение:
Как указывалось в ответах, мне нужен был метод "clean_participant", но я обернул вокруг него структуру try-Кроме (а также придерживался изменения forms.py, перезаписывая поле участника):
def clean_participant(self):
participant_string = self.cleaned_data['participant']
try:
participant = User.objects.get(username=participant_string)
except User.DoesNotExist:
raise forms.ValidationError("User does not exist.")
return participant