Queryset not displayed in django admin interface - python

I am creating a Django application and trying to include more search boxes in Django web admin interface for a specific model, so that users can simultaniously search more fields. For example, users can enter in one search box the name of the city, and in another search box the name of the street, and all model instances which have corresponding city and street are shown in browser after 'Search' button is hit. Default admin web interface has only one search box. I've added three search boxes in change_list.html file, and when I enter some data in those search boxes in browser and hit 'Search', a proper URL is formed (with query string containing those three input parameters by which the search shoould be done). Then I capture those input parameters in queryset method which I have overriden in my class that extends models.AdminModel calss, perform query set filtering and finally return the filtered queryset. Now, the problem is that the filtered query set is simply not shown on the web page (web interface of my model) after the search process is done, it says that no matches were found. But I am definately sure that my filtered query set contains data beacues I print it in command line just before the return command of queryset method is executed, and it prints correct data.
Here is my queryset method:
def queryset(self, request):
qs = super(UkopcanjeAdmin, self).queryset(request)
if "mjesto" in request.GET:
lokacija = request.GET.get('mjesto',None)
if lokacija:
qs = qs.filter(mjesto__icontains=lokacija)
if "ulica" in request.GET:
ulica = request.GET.get('ulica',None)
if ulica:
qs = qs.filter(ulica__icontains=ulica)
if "naziv" in request.GET:
naziv = request.GET.get('naziv',None)
if naziv:
qs = qs.filter(naziv__icontains=naziv)
print qs #this prints correct filtered data
return qs
Why isn't filtered query set shown in web interface?
EDIT : Thanks to my friend, I've finally managed to solve the problem. And solution is quite simple, all I had to do is move the whole code of queryset method to get_search_results method, and along filtered queryset return false boolean parameter (because get_search_results method returns two parameters). So if anybody wants to customize the search process in Django, the get_search_results method should be used. There you can access query string argumnets and retreive some data the way you want.

I think it should be get_queryset but not queryset method.
def get_queryset(request):
#your code here
queryset = super(UkopcanjeAdmin, self).get_queryset(request)
if 'miesto' in request.GET:
print 'Yes'
return queryset
else:
print 'No'
Here is some short explanation from Django docs.

Related

How to get value of django form within that same form before submission?

I'm creating a django form with 3 choice fields. I want the 3rd choice field (object field) to populate based on the first 2 choice fields. Boiling it down, I guess my question would be how do I get the values of the first 2 choice fields so I can use those values within the same form.py before submitting?
Here is what my forms.py looks like, which is currently giving me the error "maximum recursion depth exceeded":
class MyForm(forms.Form):
season = forms.ChoiceField(
widget=forms.Select(attrs={"class": "form-control test"}),
label="season",
choices=SEASON_CHOICES,
)
episode = forms.ChoiceField(
widget=forms.Select(attrs={"class": "form-control"}), label="episode"
)
object = forms.ChoiceField(
widget=forms.Select(attrs={"class": "form-control"}),
label="object",
)
def __init__(self, *args, **kwargs):
super(forms.Form, self).__init__(*args, **kwargs)
form = MyForm()
season = form.cleaned_data.get["season"]
episode = form.cleaned_data.get["episode"]
try:
snow = Snowflake()
snow_data = snow.query(
f"""select * from modern_family"""
)
object_data = snow.query(
f"""select * from {season}.{episode}"""
)
snow.close()
self.fields["episode"].choices = [(sd[0], sd[0]) for sd in snow_data]
self.fields["object"].choices = [(sd[0], sd[0]) for sd in object_data]
except Exception as e:
print(e)
What you are looking to do is create a 'conditional' form, where early elements dictate the format or presence of later elements.
Django doesn't handle this use case out of the box, as views containing forms are created server-side and delivered to the client browser. Django has no default visibility over what happens on the client page, unfortunately. cleaned_data is what is produced by a submitted form, not one currently being filled out, so your approach won't work as is.
Usually dynamic elements such as conditional forms are handled client side by javascript, as the elements on the page can be read before submission using onchange() or listener functions attached to the form elements.
There are a few approaches to try
Split the form into two, and deliver a constructed third drop down in a separate view and form - for this you only need django
Use HTMX or Ajax to make a call via javascript back to the server, then alter the third dropdown element appropriately based on the response. HTMX may be a good choice for this as you can deliver the new dropdown HTML directly from a django template. This is a good approach if you need to do server side calculations on what options should be available in the third dropdown.
Use javascript alone to read the values of the first two dropdowns and amend the third dropdown. A good approach if all the info you need to edit the third dropdown is contained in the page.

ListView with different outputs depending on POST or GET

My app is a db of entries that can be filtered and grouped in lists. Index page should show all entries properly paginated, with no filters, and a search form to filter by entry name and types. Is there a way to do this with one ListView and one template, changing behaviors depending if the page was accessed from index (with GET) or from a search (with POST)? If so, how can I change template page title to "Index" or "Search results" accordingly?
Have you tried using get() and post() methods inside your view? It is exatcly what you need.
class YourView(ListView):
...
def get(self, request):
# unique behaviour for GET
def post(self, request, *args, **kwargs):
# unique behaviour for POST
Check out Django docs.

Django how to iterate through a list of objects in a view?

So I have a view that asks the user for input and I cannot figure out what to do to somehow iterate through the list and get the user input on all the objects...
def get(self, request, language, word):
'''Get reqeust to edit taken in steps'''
context = cache.get(word)
form_class = DefinitionInfoForm
context['form_class'] = form_class
return render(request,
'study/add_info.html',
context_instance=RequestContext(request, context))
Here is my get that is inside a CBV. I have loaded a cache of objects and I would like to somehow iterate through them one at a time making a new get for every one if possible
OR
do a bulk ad and render them all with forms and modify all the objects in the post method
I am using this form to add the info and I can not figure out how to do it with a bulk or one at a time...
class DefinitionInfoForm(forms.Form):
part_of_speech = forms.CharField(required=True, label=_(u'Part of Speech'))
pronunciation = forms.CharField(required=True, label=_(u'Pronunciation'))
In this case the answer for me was to use https://docs.djangoproject.com/en/1.9/topics/forms/modelforms/#model-formsets and add a queryset as an argument.
I could then pass it to the template as context and iterate through the formset there

Using objects.get or objects.filter to obtain specific groups to use in form filter

I have created a form that due to segregation requirements needs me to prevent certain users from seeing certain results.
The form works perfectly, but I want to apply a filter that looks at the group of a user and filters the form contents based on the group the user belongs to.
views.py that renders the form with the filter.
def Overtime_Results(request):
employeeGroup = request.user.groups.get(name='Client1' or 'Client2' or 'Client3' or 'Client4')
overtime_data = Overtime.objects.filter(client=employeeGroup)
location = None
if request.method == 'POST':
form = OvertimeForm(data=request.POST)
if form.is_valid():
location = form.data['location']
overtimeid = Location.objects.all()
overtime_data = Overtime.objects.filter(location=location, client=employeeGroup)
else:
form = OvertimeForm()
template_name = "overtime/Overtime_Results.html"
context = {
'form': form,
'location': location,
'overtime_data': overtime_data,
}
return render(request, template_name, context)
This is the filter that checks whether the user belongs to a certain group.
employeeGroup = request.user.groups.get(name='Client1' or 'Client2' or 'Client3' or 'Client4')
I essentially want this to return whichever group the user belongs to, which will subsequently apply this to the forms filter later.
I've tried both filter, get with multiple methods. The above works, but only for Client1. Client2 and subsequentl clients don't work.
Edit: I think I need to use the equivalent to an 'in' statement in SQL. But, I can't seem to figure out how to do this.
The error I'm receiving right now is:
Group matching query does not exist.
When accessing the page with a user that has a valid group assigned that matches the query results.
How about this QuerySet API Field Lookups using "in".
request.user.groups.get(name__in=['Client1' ,'Client2' , 'Client3' , 'Client4'])
Your query boils down to:
request.user.groups.get(name='Client1')
This is because the result of:
'Client1' or 'Client2' or 'Client3' or 'Client4'
Will always be 'Client1'.
If you just want to get all the groups the current user belongs to:
user_groups = request.user.group_set.all()
If your user can only belong to one group, then use:
user_group = request.user.group

Django: How do I access post data and match with a criteria

I need some guidance on best practice implementation of the following.
I have a scenario where I am building an app, but if it matches a certain "category" or "locale" and want to redirect it to a page in between else just go the normal route.
Here is my simple views.py
if form.is_valid():
...
kwargs = {'project_id':project_id, 'categories':request.POST['categories'], 'locale':request.POST['locale']}
process_se(request, **kwargs)
return HttpResponseRedirect(obj.next_url)
Here is what I have in my models.py file but it seems to be very inconsistent.
Is there a better way to handle this request?
def process_se(self, request, **kwargs):
if "All" or "Sweden" in kwargs['locale']:
if "Technology" or "Internet" in kwargs['categories']:
next_url = request.build_absolute_uri(reverse('project_new_se', kwargs={'project_id': self.id}))
else:
next_url = request.build_absolute_uri(reverse('project_new_step2', kwargs={'project_id': self.id}))
self.next_url = next_url
UPDATES:
I am using forms.ModelForm, categories and locales are ManyToManyField's
I have simulated a for in the shell and still seem to get no result
Here is the cleaned_data output
f.cleaned_data
{'locale': [<Locale: Sweden>, <Locale: All>], 'categories': [<Category: Technology>, <Category: Internet>]}
Although running this for fields in the form seem to render perfectly fine based on your solution
I originally proposed putting this code in the form class, but ApPeL revised the question to point out that locale and categories are many-to-many fields on the model. So now I suggest putting a method like this in your model:
def requires_swedish_setup(self):
"""
Return True if this project requires extra Swedish setup.
"""
return (self.locale.filter(name__in = ('All', 'Sweden')).exists())
and self.categories.filter(name__in = ('Technology', 'Internet')).exists())
and then implementing your view like this:
if form.is_valid():
project = form.save()
next = 'project_new_step2'
if project.requires_swedish_setup():
next = 'project_new_se'
next_url = reverse(next, kwargs={'project_id': project.id})
return HttpResponseRedirect(next_url)
Some notes:
I'm assuming that Locale and Category objects have name fields (if not, use whatever field contains the name you are testing).
It's not a good idea to read form data out of request.POST (widgets haven't had a chance to run, and it hasn't been validated): it's better to use form.cleaned_data.
You don't need to call request.build_absolute_uri in this case: it's fine to feed the result of reverse directly to HttpResponseRedirect.
"All" or "Sweden" in kwargs['locale'] is probably not what you mean: it parses like "All" or ("Sweden" in kwargs['locale']) and so is always true.

Categories