So I've spent the day trying to chase down a custom thing that I wanted to achieve using FormView. When I use FormView with HTML form method="POST", I am able to get the desired result, mostly.
If a user clicks to submit a form and an empty field exists, they get an error message telling them the form is required. I'm aware that I can make the ModelChoiceField required on the form, but was trying to implement my own logic for this.
I found through my searching that if I'm not updating anything via the form, form method="GET" may be more appropriate. So I switched to that, and basically got this method working, but my error logic still doesn't quite work the way I'd expect.
Long story short, I can use the form method="GET", but when I try to do validation on the form, it doesn't work. Worse yet, if I try to include an empty label, that creates an invalid literal message, because based on this SO...In a Django template, how to specify a dictionary key which is itself an attribute? It doesn't seem possible to specify error logic/validation if the first field is essentially empty, which it is in order to create a blank first choice on ModelChoiceField.
Here's my code...
The Form...
dropdown = forms.ModelChoiceField(queryset=Author.objects.filter(is_active=True),required=False)
def __init__(self, *args, **kwargs):
# q = kwargs.pop('dropdown', None)
dropdown = kwargs.pop('dropdown', None)
super(AuthorByNameForm, self).__init__(*args, **kwargs)
self.fields['dropdown'].empty_label = ''
The HTML...
<form method="GET" action="{% url 'Main:author_detail' %}">
<h1 class="class">View By Author</h1>
<div>
{{ form.dropdown }}
</div>
The Views...FORMVIEW
class AuthorByNameView(LoginRequiredMixin,FormView):
form_class = AuthorNameForm
template_name = 'author_by_name.html'
def get_form_kwargs(self):
kwargs = super(AuthorByNameView, self).get_form_kwargs()
kwargs['dropdown'] = self.request.GET.get("dropdown")
return kwargs
DetailView....
class AuthorDetailView(LoginRequiredMixin,DetailView):
model = Author
template_name = 'author_detail.html'
def get_object(self, queryset=None):
return get_object_or_404(Author, id=self.request.GET.get("dropdown"))
return get_object_or_404
Model...
Essentially just User...with a One to One with UserProfile...
class UserProfile(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE)
Essentially, if I removed the empty_label line from my form, the form validates, provided that the queryset isn't empty. If I include the empty_label line of code and the user clicks on the submit button without selecting anything, they get an invalid literal for int() with base 10: '' message. It seems the only way to work around this is to make the ModelChoiceField required=True, with the empty_label reference.
Using the request.GET appears to behave differently than the POST for good reason, I'm aware. When I used the POST instead, everything works exactly as I want it to, except there doesn't appear to be a way to prevent the error message that I'm using to show up if the user clicks on the BACK button.
I explored some Javascript solutions today that were recommeneded via this SO, How To Clear self.add_error in Django if user clicks on browser back button? but to no avail.
Has anyone else encountered this struggle? Based on my knowledge up until this point, in this case since I'm not updating the records in question and just displaying them, form method="GET" would seem to make the most sense, but I seem to be pretty limited as to my options on how I can keep a blank first position in my ModelChoiceField and also do any kind of my own validation on the field in question without encountered the invalid literal message.
Thanks in advance for any thoughts.