Django Search form not submitting value - django

I have a search form in my django app. I want to add a filter option and so I'm adding a radio button for filtering by name alphabetically ascending and descending. The value for the search is getting passed through, but the radio button value is
<form method='GET' action='{% url "search:catalog-query" %}' class="form my-2 my-lg-0 search-form">
<div class='input-group'>
<input class="form-control" type="text" placeholder="Search" name='q' aria-label="Search" value='{{ request.GET.q }}'>
<span class='input-group-btn'>
<button class="btn btn-outline-success" type="submit">Search</button>
</span>
</div>
<div>
Sort Name:
<label for="id_sort_up">Ascending</label><input type="radio" name="name_sort" id="id_sort" value='{{ request.GET.name_sort }}'>
<label for="id_sort_down">Descending</label><input type="radio" name="name_sort" id="id_sort" value='{{ request.GET.name_sort }}'>
</div>
</form>
urls.py
url(r'^catalog/$', SearchCatalogView.as_view(), name='catalog-query'),
view.py
class SearchCatalogView(ListView):
template_name = "search/view-catalog.html"
print('search catalog')
def get_context_data(self, *args, **kwargs):
context = super(SearchCatalogView, self).get_context_data(*args, **kwargs)
query = self.request.GET.get('q')
context['query'] = query
return context
def get_queryset(self, *args , **kwargs):
print('get_queryset')
request = self.request
method_dict = request.GET
query = method_dict.get('q', None) # method_dict['q']
print(method_dict)
if query is not None:
return AAAA.objects.search(query)
return AAAA.objects.features()
When I print method_dict, I get <QueryDict: {'q': ['searched_option'], 'name_sort': ['']}> regardless of which radio button I am choosing.

Sort Name:
<label for="id_sort_up">Ascending</label>
<input type="radio" name="name_sort" id="id_sort_up" value='Ascending'>
<label for="id_sort_down">Descending</label>
<input type="radio" name="name_sort" id="id_sort_down" value='Descending'>
would give
method dict <QueryDict: {'q': ['searched_option'], 'name_sort': ['Ascending']}>
or
method dict <QueryDict: {'q': ['searched_option'], 'name_sort': ['Descending']}>

Related

Django form is saved but result field is empty in database

Django form is saved but "result" field is showing empty in database.
Even after populating the filed from admin panel, it is saved but it still shows empty.
Models.py
class Result(models.Model):
class Choises(models.TextChoices):
POSITIVE = "POSITIVE", "Positive"
NEGATIVE = "NEGATIVE", "Negative"
user = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=50, default=None)
result = models.CharField(max_length = 100, choices=Choises.choices, blank=False
)
resultDoc = models.ImageField(upload_to='testResults', height_field=None, width_field=None,)
def __str__(self):
return self.user.username
Forms.py
class resultForm(forms.ModelForm):
class Meta:
model = Result
fields = ['name', 'result', 'resultDoc']
views.py
def inputResult(request, pk):
user = User.objects.filter(id=pk).first()
profile = newProfile.objects.filter(user=user).first()
if profile == None:
profile = oldProfile.objects.filter(user=user).first()
rForm = resultForm(request.POST, request.FILES)
if request.method == 'POST':
rForm = resultForm(request.POST, request.FILES)
if rForm.is_valid():
order = rForm.save(commit=False)
order.user_id = pk
order.save()
return redirect('stored_records')
else:
rForm = resultForm()
context = {'user' : user, 'profile':profile, 'rForm': rForm}
return render(request, 'Testing booth End/input-result-customer-info.html', context)
input-result-customer-info.html
<form action="" method = "POST" enctype= "multipart/form-data">
{% csrf_token %}
<div class="mb-3">
<label for="name" class="form-label">Name</label>
<input type="text" class="form-control" id="name" name="name" placeholder="Uploaded By/Doctor Name">
</div>
<div class="mb-3">
<label for="result" class="form-label">Result</label>
<select class="form-select" id="result" name="result" class="form-control">
<option value="POSITIVE">Positive</option>
<option value="NEGATIVE">Negative</option>
</select>
</div>
<div class="mb-3">
<label>Upload Scan File</label>
<div class="upload d-flex justify-content-between">
<div class="file-placeholder">Upload Scan File</div>
<input type="file" class="form-control d-none" id="resultDoc" name="resultDoc" >
<label for="resultDoc" class="form-label cam-img"> <img src="{% static 'user/images/Camera.png' %}"> </label>
</div>
</div>
<button class="btn btn-primary w-50 ms-auto d-block h-100" type="submit">Upload</button>
</form>
enter image description here
I think that the reason this doesnt work is that you created a form (rForm) in the backend but then you don't use it in the frontend.
This is how you should render your form in the the frontend:
<form method="post">
{{ rForm.as_p }} # This is the easiest possible implementation
<button type="submit">Submit</button>
</form>
If you want to take control of how the form is rendered, then you have to make sure that the input fields are named in the way that your backend expects. You can do it entirely manually or semi-manually, but your field names have to be set correctly or nothing will work.
Example of typical approach, say in case you have several similar text inputs
{% for field in rForm %}
<label for="{{ field.auto_id }}">{{ field.name }}</label>
<input type="text" name="{{ field.html_name }}" id="{{ field.auto_id }}" />
{% endfor %}
Example of fully hands-on approach
<select class="form-select" id="{{ rForm.result.auto_id }}" name="{{ rForm.result.html_name }}" class="form-control">
<option value="POSITIVE">Positive</option>
<option value="NEGATIVE">Negative</option>
</select>
In order to make sure that the inputs are being parsed correctly, add a print statement in your view to print the POST request:
print("Post Request : ", request.POST)
From there you will be able to see if the result field is being picked up correctly or if it's being ignored. Usually when fields get ignored is because they are not named correctly or sometimes it's because they fail validation.
If the rest of the data is saved correctly and just result is being left out then it's almost for sure an issue with the field name because if the form failed validation it would have aborted the entire operation.
P.S. I just noticed that you select input has the class attribute declared twice

Form not submitting CSRF token missing although it is in rendered html

I'm getting a "CSRF token missing" error, when submitting a form in Django.
I'm using django-crispy-forms in combination with htmx.
The form is rendered via render_crispy_form:
def SwapFormView(request, partialform):
ctx = {}
ctx.update(csrf(request))
mitglied = model_to_dict(request.user.mitglied)
if request.method == 'POST':
# do form things
return HttpResponse("""POST""")
else:
form = ChangeDataForm(
initial=mitglied,
partialform=partialform,
)
html = render_crispy_form(form, helper=form.helper, context=ctx)
return HttpResponse(html)
My helper is contructed like this:
def __init__(self, *args, **kwargs):
super(ChangeDataForm, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.form_id = 'change-form'
self.helper.attrs = {
'hx-post': reverse('back-to-same-url'),
'hx-target': '#change-form',
'hx-swap': 'outerHTML',
}
self.helper.add_input(Submit('submit', 'absenden'))
The thing is, that as soon as I change the helper to a 'normal' POST-Request it works - but I need this to be done via HTMX to only change out the specific parts in the DOM.
Weirdest thing for me is, that the token is rendered into the final html of the form:
<form hx-post="/profil/nameform/" hx-swap="outerHTML" hx-target="#change-form" id="change-form" method="post" enctype="multipart/form-data" class="">
<input type="hidden" name="csrfmiddlewaretoken" value="token-value">
<label for="id_title" class="">Titel</label>
<input type="text" name="title" value="Hau" maxlength="50" class="textinput textInput form-control" id="id_title">
<label for="id_first_name" class=" requiredField">Vorname<span class="asteriskField">*</span> </label>
<input type="text" name="first_name" value="Test" maxlength="50" class="textinput textInput form-control" required="" id="id_first_name">
<label for="id_last_name" class=" requiredField">Nachname<span class="asteriskField">*</span></label>
<input type="text" name="last_name" value="aBVIpzRJoBKP" maxlength="50" class="textinput textInput form-control" required="" id="id_last_name">
<input type="submit" name="submit" value="absenden" class="btn btn-primary" id="submit-id-submit"> </div> </div> </form>
Any help is appreciated...
EDIT:
The problem solved itself after I removed some kwargs I passed from the view to the form. Still don't know, what the real problem was, but I found a workaround.

how to make text stay after the search has been made

I have a serch field on my page
<form method="GET" class="container mb-5">
<input type="search" class="form-control rounded" placeholder="Write a name" aria-label="Search"
aria-describedby="search-addon" name="search"/>
<button type="submit" class="btn btn-outline-primary px-5" >Search</button>
</form>
And here is my views
def my_view(request):
value_one = request.GET.get("search", None)
objects = MyModel.objects.all()
if value_one:
objects = objects.filter(field_one=value_one)
After I input something in a search field and push the button 'search', text which was in search field dissapears, I want it to stay until the next input. Is it possible to do with Django or not? Don't even know how to google it, everything I found was on different topic
on your template add value to your input:
<form method="GET" class="container mb-5">
<input type="search" class="form-control rounded" placeholder="Write a name" aria-label="Search" value="{{value_one"}}
aria-describedby="search-addon" name="search"/>
<button type="submit" class="btn btn-outline-primary px-5" >Search</button>
</form>
and on your view add that value to your context :
def my_view(request):
value_one = request.GET.get("search", None)
objects = MyModel.objects.all()
if value_one:
objects = objects.filter(field_one=value_one)
return render(request,'template.html',{'value_one':value_one,'objects':objects})
Have you heard of django's Form class ? You should be using the Form class to create forms in Django and that would allow you to preserve data between "submit" calls as well as handle errors. Some example code snippets for you:
forms.py
from django import forms
class SearchForm(forms.Form):
search = forms.CharField(label="Search Query", widget=forms.TextInput(attrs={"class": "form-control rounded", "placeholder": "Write a name", "aria-label": "Search", "aria-describedby": "search-addon"}))
views.py
from django.shortcuts import render
from .forms import SearchForm
def my_view(request):
form = SearchForm({"search": request.GET.get("search", None)})
if form.is_valid():
search_query = form.cleaned_data.get("search")
if search_query:
objects = MyModel.objects.filter(field_one=search_query).all()
# ...snip...
return render(request, 'searchform.html', {"form": form})
searchform.html
<form action="{% url 'my_view' %}" method="get">
{{ form }}
<input type="submit" value="Submit" class="btn btn-outline-primary px-5">
</form>

How to get the value of a specific field in a form in Django view function?

I am trying to achieve a load-up process in my system where the user will input the load amount and add it to a user's current load.
How can I get the amount entered in my view function?
Here's my function in my views.py
def LoadWallet(request, pk):
user = get_object_or_404(User, id=request.POST.get('user_id'))
user_wallet = user.wallet
if request.method == 'POST':
form = LoadForm(request.POST)
if form.is_valid():
user_wallet = user_wallet+form.instance.load_amount
User.objects.filter(id=pk).update(wallet=user_wallet)
return HttpResponseRedirect(reverse('user-details', args=[str(pk)]))
and the form in my template file
<form action="{% url 'load-wallet' user.pk %}" method="POST">
{% csrf_token %}
<label for="load_amount">Load amount</label>
<input type="text" class="form-control" id="load_amount" onkeyup="replaceNoneNumeric('load_amount')">
<button type="submit" name="user_id" value="{{ user.id }}" class="btn btn-md btn-success" style="float: right; margin: 10px 5px;">Load</button>
</form>
Right now I tried this but it's returning "name 'LoadForm' is not defined". Should I declare the LoadForm first?
Is there a better way to implement this? Thank you!
You might have an easier time using something like this, than LoadForm:
def LoadWallet(request, pk):
user = get_object_or_404(User, id=request.POST.get('user_id'))
user_wallet = user.wallet
if request.method == "POST":
user_id = request.POST["user_id"]
# Other logic here
return ...
And in template
<form class="load-wallet" action="" method="POST">
{% csrf_token %}
<input type="text" name="user_id" placeholder="What is the user id?">
<button type="submit" class="submit-btn"> Submit </button>
</form>

passing form arguments in django

I am trying to implement a simple search function in django but somehow I can't pass the argument from my template to my view function. I've got a key error: KeyError at /artdb/search/ because kwargs is empty:
url.py:
path('search/',views.Search.as_view(),name='search'),
base,.html:
<form class="form-inline my-2 my-lg-0" name="search" action="{% url 'artdb:search' %}" {{ form.as_p }} method="get">{% csrf_token %}
<input class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search" value="{{seastr}}">
<button class="btn btn-outline-success my-2 my-sm-0" type="submit" value="{{seastr}}">Search</button>
</form>
views.py:
class Search(ListView):
print("class Search")
model=Person
template_name='artdb/search.html'
context_object_name='ans'
def get_queryset(self):
Pdb().set_trace()
self.seastr=get_object_or_404(Person,name=self.kwargs['seastr'])
return Person.objects.filter(seastr=self.seastr)
You did not attach the name seastr to your <input> field:
<form class="form-inline my-2 my-lg-0" name="search" action="{% url 'artdb:search' %}" {{ form.as_p }} method="get">{% csrf_token %}
<input name="seastr" class="form-control mr-sm-2" type="text" placeholder="Search" aria-label="Search" value="{{seastr}}">
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
</form>
Notice the name="seastr" in the <input> tag.
GET parameters are not stored in self.kwargs, but in self.request.GET, so we can obtain the parameter with self.request.GET['seastr'].
Typically the page with the search bar, is the same as the one with the request, therefore the search request if frequently optional. So it might be useful to make filtering optional here:
class Search(ListView):
model=Person
template_name='artdb/search.html'
context_object_name='ans'
def get_queryset(self):
q = self.request.GET.get('seastr')
if q is not None:
return Person.objects.filter(seastr=q)
else:
return Person.objects.all()
Finally note that the seastr parameter is not part of the context data. You can make this part of the context data, by patching it:
class Search(ListView):
model=Person
template_name='artdb/search.html'
context_object_name='ans'
def get_queryset(self):
q = self.request.GET.get('seastr')
if q is not None:
return Person.objects.filter(seastr=q)
else:
return Person.objects.all()
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['seastr'] = self.request.GET.get('seastr')
return context