How to add pagination in Classed Based View with get_context_data - django

I want to add pagination to my List View. I have used paginated_by=10 but it not working. Please help me to add pagination to my view in my template. What HTML should i put in my template
View.py
class CompanyListView(LoginRequiredMixin, generic.TemplateView):
template_name = 'superadmin/company/company.html'
def get_context_data(self, **kwargs):
context = super(CompanyListView, self).get_context_data(**kwargs)
context['companies'] = Company.objects.exclude(company_name='Apollo').exclude(company_is_deleted = True).annotate(number_of_company_users=Count('userprofile'))
return context

You could use ListView instead of TemplateView.
Here is how.
class CompanyListView(LoginRequiredMixin, generic.ListView):
template_name = 'superadmin/company/company.html'
queryset = Company.objects.all()
context_object_name = 'companies'
paginate_by = 10
def get_queryset(self):
return (
self.queryset.exclude(company_name='Apollo')
.exclude(company_is_deleted =True)
.annotate(number_of_company_users=Count('userprofile'))
)

Related

django CBV doesnt pagginate with editing context

View down below should show the tasks for the logged user but when I paginate the tasks I got
Cannot filter a query once a slice has been taken.
how should I filter the context to avoid the error for pagination?
class TaskList(LoginRequiredMixin, ListView):
model = Task
context_object_name = 'tasks'
template_name = 'TaskList.html'
paginate_by = 2
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['tasks'] = context['tasks'].filter(user=self.request.user)
return context
Use get_queryset() for filtering objects in ListView:
def get_queryset(self): # noqa: D102
queryset = super().get_queryset()
return queryset.filter(user=self.request.user)
The filtering in get_queryset() method should fix the issue - also remove get_context_data() method overload, it's not neccessary.

Combine DetailView and SingleTableView in Django

How can I display a SingleTableView table together with a DetailView in django? What I want is to include or combine both into one. So that when calling DeviceDetailView i receive the device's details and a table of the devices's data (stored also in another model).
I am using django-tables2 for the table.
Someone any idea?
Thank you
class DataListView(SingleTableView):
model = Data
template_name = 'data/list.html'
table_class = DataTable
def post(self, request, *args, **kwargs):
queryset = request.POST
for i in queryset['list'].split(","):
if queryset['action'] == 'delete':
Data.objects.filter(data_id=i).delete()
return HttpResponseRedirect('/data/')
class DeviceDetailView(DetailView):
template_name = 'devices/detail.html'
def get_object(self):
id_ = self.kwargs.get("id")
return get_object_or_404(Device, id=id_)
EDIT
I know it should look something like this:
class DeviceDetailView(SingleTableView, DetailView):
template_name = "devices/device-detail.html"
model = Device
table_class = DeviceTable
def get_context_data(self, **kwargs):
self.object = self.get_object()
context = super(DetailView, self).get_context_data(**kwargs)
id_ = self.kwargs.get("id")
obj = Device.objects.filter(id=id_)
context['object'] = obj
return context
But i think i still don't know how to do this part inside get_context_data so that the elements are merged together...
SOLUTION
Ok it is donde like this:
class DeviceDetailView(SingleTableView, DetailView):
template_name = 'devices/device-detail.html'
model = Data
table_class = DataTable
#crumbs = [('Device detail', 'DeviceDetailView')]
def get_context_data(self, **kwargs):
self.object = self.get_object()
context = super(DetailView, self).get_context_data(**kwargs)
table = self.get_table(**self.get_table_kwargs())
context[self.get_context_table_name(table)] = table
return context
def get_object(self):
id_ = self.kwargs.get("id")
return get_object_or_404(Device, id=id_)
You can serve the table within your DetailsView using custom get_context_data. You can render your table in the template as you usually do with {% render_table table %}.
# import YourModel
# import YourTable
class DeviceDetailView(DetailView):
model = YourModel
template_name = 'devices/detail.html'
def get_context_data(self, **kwargs):
table = YourTable(YourModel.objects.all()) # define your tables data here
context = {"table": table}
return super().get_context_data(**context)

Pagination Not Working for multiple query

I am using pagination but is not woking. I have used with get_queryset() and it works. Why it is not working in get_context_view()
class UserListView(LoginRequiredMixin, generic.TemplateView):
template_name = 'users/users.html'
paginate_by = 1
def get_context_data(self, **kwargs):
context = super(UserListView, self).get_context_data(**kwargs)
context['companies'] = Company.objects.exclude(company_is_deleted=True).exclude(company_name='Apollo')
context['users'] = User.objects.filter(userprofile__user_role__id=2).exclude(
Q(is_superuser=True) |
Q(userprofile__user_is_deleted = True)|
Q(userprofile__user_company__company_is_deleted=True)
)
query = self.request.GET.get('query')
if query:
list_query = context['users']
context['users'] = list_query.filter(userprofile__user_company__company_name__icontains=query)
return context
TemplateView does not provide us with pagination. we can use ListView. It's not recommended to paginate in get_context_data method.
For pagination you should use get_queryset method.
Example:
class UserListView(LoginRequiredMixin, generic.ListView):
paginate_by = 10
def get_queryset(self, **kwargs):
queryset = User.objects.filter(userprofile__user_role__id=2).exclude(
Q(is_superuser=True) |
Q(userprofile__user_is_deleted = True)|
Q(userprofile__user_company__company_is_deleted=True)
)
query = self.request.GET.get('query')
if query:
queryset = list_query.filter(
userprofile__user_company__company_name__icontains=query)
return queryset
If you use ListView then in the template you can access users with name object_list.

objects filter on base of url request

I have two similar classes, query filter is county code DE or NL.
Is possible to make a objects filter on base of url name and keep only one class? For example, if i point my browser to
127.0.0.1:8000/germany
django will call to filter
feed__country__name='DE'
and
127.0.0.1:8000/netherland
will use
feed__country__name='NL'?
My URL:
url(r'^netherland/$', NLFeedList.as_view(), name='nl'),
url(r'^germany/$', DEFeedList.as_view(), name='de'),
VIEWS:
class NLFeedList(PaginationMixin, ListView):
model = FeedItem
template_name = 'nl_feed.html'
context_object_name = 'feed_items'
paginate_by = 20
def get_queryset(self):
items = FeedItem.objects.filter(feed__country__name='NL')
if self.kwargs.get('category', None):
return items.category(self.kwargs.get('category'))
return items
def get_context_data(self, **kwargs):
context = super(NLFeedList, self).get_context_data(**kwargs)
context['categories'] = Category.objects.filter(country__name='NL')
return context
class DEFeedList(PaginationMixin, ListView):
model = FeedItem
template_name = 'de_feed.html'
context_object_name = 'feed_items'
def get_queryset(self):
items = FeedItem.objects.filter(feed__country__name='DE')
if self.kwargs.get('category', None):
return items.category(self.kwargs.get('category'))
return items
def get_context_data(self, **kwargs):
context = super(DEFeedList, self).get_context_data(**kwargs)
context['categories'] = Category.objects.filter(country__name='DE')
return context
You can do something like:
urls.py
url(r'^(?P<country>germany|netherland)/$', FeedList.as_view(), name='feedlist')
and the view:
class FeedList(PaginationMixin, ListView):
model = FeedItem
context_object_name = 'feed_items'
match = {'germany':'DE','netherland':'NL'}
def get_queryset(self):
code = self.match[self.kwargs['country']]
items = FeedItem.objects.filter(feed__country__name=code)
self.template_name = '%s_feed.html' % code.lower()
if self.kwargs.get('category', None):
return items.category(self.kwargs.get('category'))
return items
def get_context_data(self, **kwargs):
context = super(FeedList, self).get_context_data(**kwargs)
context['categories'] = Category.objects.filter(country__name=self.match[self.kwargs['country']])
return context
Also, perhaps you don't need two templates else only one, in this case just remove this line self.template_name = '%s_feed.html' % code.lower() and set the template_name accordingly.
Change your url to
url(r'^(?P<country>netherland|germany)/$', NLFeedList.as_view(), name='nl'),
Then access this new <country> parameter in your view using
country = self.kwargs['country']
Then do the necessary if country = '...': code block in your view.

Filtering a model in a CreateView with get_queryset

I'm trying to filter a model with get_queryset() and it seems to work in the view but not in the template.
My view :
class FolderCreate(CreateView):
fields = ['name', 'parent']
template_name = 'Form/folder_create.html'
def get_queryset(self):
folders = Folder.objects.filter(owner=self.request.user)
print folders # ==> return [<Folder: Folder>, <Folder: Another folder>]
return folders
def form_valid(self, form):
self.object = form.save(commit=False)
self.object.owner = self.request.user
return super(FolderCreate, self).form_valid(form)
def get_initial(self):
if self.request.method == 'GET':
foldersUrl = self.request.META['HTTP_REFERER'].split('/')
foldersUrl.pop()
folder = urllib2.unquote(foldersUrl[-1])
try:
return {'parent' : Folder.objects.get(name=folder, owner=self.request.user)}
except Folder.DoesNotExist:
pass
As you can see, folders return two objects related to the session user in get_queryset() : 'Folder' and 'Another folder
Infortunately, the combobox of my template get all the folders, without any filtering.
Any idea ?
The issue here is that get_queryset is not used in a CreateView, as it's meant for filtering the models returned for display in a list or detail view. You want something completely different: you want to filter the choices available in a form field.
To do that you will need to create a custom ModelForm that accepts a user kwarg and filters the queryset accordingly:
class FolderForm(forms.ModelForm):
class Meta:
model = Folder
fields = ['name', 'parent']
def __init__(self, *args, **kwargs):
user = kwargs.pop('user')
super(FolderForm, self).__init__(*args, **kwargs)
self.fields['parent'].queryset = Folder.objects.filter(user=user)
and then change your view to use that form and pass in the user parameter:
class FolderCreate(CreateView):
template_name = 'Form/folder_create.html'
form_class = FolderForm
def get_form_kwargs(self):
kwargs = super(FolderCreate, self).get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs