Customize Django ListView Pagination - django

im implementing a Django ListView for a Search View. The search is done using Elasticsearch and django-elasticsearch-dsl. Im actually getting a pagination of just 10 items because thats the amount of contents that Elasticsearh answers by default. I could ask elasticsearch to get all the contents but it would be really unnefficient since im only showing like 50 of them.
Is there any way that Django reads the pagination information from other than the queryset?
This is what my view looks like:
from .elastic import search
class SearchView(ListView):
template_name = "search/index.html"
paginate_by = 50
def get_queryset(self):
keyword = self.kwargs['keyword']
lang = get_language()
return search(keyword, lang)
Edit:
When using a normal queryset from database, django manages the pagination, i assume that using a query for count the total amount of objects and by using the paginate_by parameter. In my case, the queryset that i return on the get_queryset method, is only one page lenght because i get those contents from elasticsearch. Im looking for a way to tell django how much contents the query has in total to let django build the pagination ok.
My search method is a query to elasticsearch that returns a page of contents in a queryset. But it doesnt return all the contents. I have the total amount of search results but i dont know where to put that variable to allow django build the pagination.

Related

Django: how to redirect to page with list of newly created objects after form post bulk_create

I have a simple form that allows user to paste csv data with the goal to create multiple model objects at one go.
The form method is 'post'. Action url is a method that calls the django `bulk_create` to create the model objects returning the pks.
Goal: After submission, I want to redirect to page showing a list of the objects corresponding to the pks.
Is that possible?
I have tried:
return render(request, "list_template.html", context={'object_list': objects_with_pks}), passing the model objects as context data to another template (but there would be danger of duplicate submission upon refresh)
Redirect user to a model DetailView which contains the pk in the url (but I have more than one pks created)
return HttpResponseRedirect to a new page with a success message (but I won't be able to pass the pks to the new page)
Pass num = len(pks) to a new view function that accepts a num kwargs in its url and returns the last num model objects (but is there a proper way?)
Other ways that I've thought but could not find an answer
Can I pass multiple pks in a url? so ListView could set the queryset
If not, can querysets in a model ListView instance be passed as parameters?
Is there a way to transform a POST request to a GET?
I am fairly new to web development and posting questions on stackoverflow. Please comment if its unclear and I'll update. Thank you so much.
#jjxxll- Why would you want to pass multiple pk's to a URL? If you want to view all the inserted objects after the bulk_insert is completed then a simple ListView will do. E.g
class ModelListView(ListView):
model = Model
template_name = 'some_form.html"
paginate_by = 10
In your some_form.html you will have to loop through the object_list and display the fields e.g
{% for obj in object_list%}
{{obj.name}}
{% endfor %}
That's it
If you want to view DetailView per object using pk
class ModelDetailView(DetailView):
model = Model
template_name = 'some_detail_form.html'
In your detail_form.html you will have to display the data e.g
{{object.name}}
{{object.description}}

returning record count in django restful api

I have a very complex API that accepts different filter fields via POST request. the result is a list of items from the database. The total result set can be thousands of items if the user does not filter good.
The API will be returning only 30 items but I want to add the total amount of items that satisfied the search conditions. I know that I can add a custom field in the Serializer class to return the count but I don't know how to access the queryset to query for the count().
I am sure there is a simple solution for this which I am missing
Thanks
Eyal
I got this to work but the solution is ugly and I can't believe there is no native support for this in the framework. I must be missing something
#querysey has several filters set till now
#save the querysey
queryset_orig = queryset
#add limits
queryset = queryset.filter()[:30]
serializer = ItemsSerializer(queryset, many=True)
#add total count to the first items only
serializer.data[0]. update ({'count':queryset_orig.count()})

Modelchoicefield Queryset Confusion

All,
I'm new to Django and have been doing pretty good so far but this one has me stumped. I'm trying to utilize ModelChoiceField for a number of records that have the same name. I'm using Postgresql so I was able to determine that I need to use the distinct command and that is working perfectly. The records in my dropdown are all stripped down to just one version of each of the records. However, when I try to get all of the versions of a particular record, that's where I'm getting lost. I am able to get the detail of each record if I don't use distinct via a DetailView, but I am really trying to get all versions of each record on the screen after the modelchoicefield.
Here is my form:
class History(forms.Form):
dropdown = forms.ModelChoiceField(queryset=History.objects.all())
def __init__(self, user, *args, **kwargs):
super(History, self).__init__(*args, **kwargs)
self.fields['dropdown'].widget.attrs['class'] = 'choices1'
self.fields['dropdown'].empty_label = ''
qs = History.objects.all().distinct('record_name')
self.fields['dropdown'].queryset = qs
I am ultimately trying to get a view the queryset on the screen via my template. I have tried several different versions of code in the template but nothing seems to work. If I use the CBV DetailView without distinct I can get all of the records with their detail view fine. However, that's not what I'm trying to do. I have played with several versions of the queryset command in the template as I found several questions similar to mine but can't seem to get it to work. I found a couple of references to something similar to:
{% for record in form.history.field.queryset %}
etc.
{% endfor %}
But can't seem to get it to work in my Django template. Any and all help is appreciated! Thank you in advance!
In this case I'd either suggest
a) to put the value of your dropdown field into your url matching. See the django docs for named groups in URL. Additionally, you could add an onchange event to your dropdown-field which redirects to <current url>/<value of dropdown> or simply change the value of (if existing) buttons which links to the following page. Caution: With this solution you must ensure that the values of your dropdown field matches url-format (django's slugify might be useful for this).
or
b) to add your dropdown field to your input form or as input field. Then you can extract the value of your dropdown with:
try:
dropdown_value = request.POST['dropdown-field-name'] # dict-error if field is not in request.POST
except:
# some error actions
then you can add this value as filter to your queryset:
def get_queryset(self, dropdown_value=None):
# ...
qs = qs.filter('field-name' = dropdown_value) # possibly no/wrong results if dropdown_value is corrupted or manipulated

Django rest framework: automatically create a url for each field of a model

I have large table of data (~30 Mb) that I converted into into a model in Django. Now I want to have access to that data through a REST API.
I've successfully installed the Django REST framework, but I'm looking for a way to automatically create a URL for each field in my model. My model has about 100 fields, and each field has about 100,000 entries.
If my model is named Sample,
models.py
class Sample(models.Model):
index = models.IntegerField(primary_key=True)
year = models.IntegerField(blank=True, null=True)
name = models.TextField(blank=True, null=True)
...97 more fields...
then I can access the whole model using Django REST framework like this:
urls.py
class SampleSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Sample
fields = ( **100 fields**)
class SampleViewSet(viewsets.ModelViewSet):
queryset = Sample.objects.all()
serializer_class = SampleSerializer
router = routers.DefaultRouter()
router.register(r'sample', SampleViewSet)
But of course my browser can't load all of that data in a reasonable amount of time. I could manually make a different class and URL for each field, but there must be a better way... I want to be able to go to my_site.com/sample/year (for example) and have it list all of the years in JSON format, or my_site.com/sample/name and list all the names, etc.
Please help me figure out how to do this, thanks!
You might be able to do that using a custom viewset route.
You have this:
class ModelViewSet(ModelViewSet):
#list_route()
def sample_field(self, request):
desired_field = request.data.get('field', None)
if not desired_field:
return response # pseudocode
values = Model.objects.all().values_list(desired_field, flat=True)
# serialize this for returning the response
return Response(json.dumps(values)) # this is an example, you might want to do something mode involved
You will be able to get this from the url:
/api/model/sample_field/?field=foo
This extra method on the viewset will create a new endpoint under the samples endpoint. Since it's a list_route, you can reach it using /sample_field.
So following your code, it would be:
mysite.com/sample/sample_field/?field='year'
for example.
There are many interesting details in your question, but with this sample I think you might able to achieve what you want.
Try to use pagination. You can do it in almost the same way as in you question. Pagination in django lets you divide the results into pages. You don't have to display all the entries in the same page. I think this is the best option for you.
Refer django documentation on pagination:
Pagination in django

Integrating Haystack in Django-CMS omitting Pages with View-Restrictions

I want to integrate haystack with django-cms making a search view. My CMS has pages with view restrictions (only a few authenticated users have access to some pages).
The problem is: when making a search, haystack gives me list with results from all pages, including pages to which the current user has not view permissions.
How can I integrate Haystack in a way that filters results, showing only the ones to which the current user has permissions for? If that's not possible, how to configure haystack letting it index only pages without view-restrictions? Any help is appreciated.
In my solution to this problem I use aldryn_search to do the integration of Haystack and django-cms. aldryn_search returns a listwith results from all pages, including the ones the current user hast not view-permissions for. To resolve this issue I'm inheriting from AldrynSearchView and override the get_queryset method like this:
def get_queryset(self):
queryset = super(IntranetSearchView, self).get_queryset()
for result in queryset.load_all():
page = result.object.page
# Begin: modified copy (queryset.exclude added) of cms.utils.decorators.cms_perms
if page:
if page.login_required and not self.request.user.is_authenticated():
queryset = queryset.exclude(id=result.id)
if not page.has_view_permission(self.request, user=self.request.user):
queryset = queryset.exclude(id=result.id)
# End: Copy
return queryset
using queryset.exclude() to exclude results the current user has not permissions for. After that I inherit from AldrynSearchApphook overriding the urls with my new View and than doing a apphoook_pool.register of the modified Apphook.