Pass QuerySet in Django url - python

I'm looking to pass a list as the queryset parameter to a Django ListView. I know you can do this by overwriting the get_queryset method but ideally I would like to avoid this. The reason is, I am referring from another view and already have the queryset I need so I don't want to run the same query twice.
Currently I am linking to my view as follows:
{{active|length}
active is the prepopulated list I want to use as the queryset.
My view looks as follows:
class ProjectListOngoing(ListView):
template_name = "<name of my template>"
model = Project
context_object_name = "projects"
paginate_by = 10
def dispatch(self, request, *args, **kwargs):
self.projects = request.GET.get('projects', [])
return super().dispatch(request, *args, **kwargs)
def get_queryset(self):
return self.projects
This does seem to populate the correct queryset however the primary keys are blank for some reason.
I have the following in my template:
{% for project in projects %}
<li></li>
{% endfor %}
And I get the following error:
Reverse for 'project_detail' with keyword arguments '{'pk': ''}' not found. 1 pattern(s) tried: ['project/(?P<pk>\\d+)/$']

Related

Passing a model's string parameter to URL with TemplateView

I am listing data from a search result matching the name parameter of my Model. For each result I have a link to the detail page with the key parameter (which is a string) passed in the url, Like this
<ul>
{% for x in results %}
<li><a href = 'login/index/{{x.key}}'>{{x.name}}</a></li>
{% endfor %}
</ul>
My url.py looks like this
app_name = 'kpi'
urlpatterns = [
path('login/index/search', views.SearchView.as_view(), name="search"),
path('login/index/<slug:key>', views.EpicDetailView.as_view(), name="detail")
]
And my views.py look like this:
class SearchView(LoginRequiredMixin, TemplateView):
template_name = 'KPI/search.html'
def get(self, request, *args, **kwargs):
self.q = request.GET.get('q','')
self.results = Epic.objects.filter(name__icontains= self.q)
return super().get(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = super(SearchView, self).get_context_data(**kwargs)
context['results'] = self.results
return context
class EpicDetailView(LoginRequiredMixin, TemplateView):
template_name = 'KPI/epic_detail.html'
def get_context_data(self, **kwargs):
context = super(EpicDetailView, self).get_context_data(**kwargs)
context['lone_epic2'] = Epic.objects.get(key=self.kwargs['key'])
I know I am missing a step here, probably how i created the url path, or needing logic in my views. With the code above i get a page not found error because the template view link doesn't recoginze/match the EpicDetailView url
What I'm Trying to Accomplish
The purpose is to be able to click on the search result, push the key to the url, and store that key value as a variable to use in the EpicDetailView page
NOTE: Although I'm not showing it in the code above, my detail view will be displaying data from multiple model querysets so that is why i'm using TemplateView instead of DetailView for my EpicDetailView
You should pass the slug into your URL like so in your template:
<li>{{x.name}}</li>
Make sure that kpi is properly registered as the namespace for your KPI app. More info on the URL dispatcher here: https://docs.djangoproject.com/en/2.1/ref/templates/builtins/#url

Count number of posts from a ListView

I would like to count the number of "todo" in my ListView
views.py
class DashboardListView(LoginRequiredMixin,ListView):
model = Links
template_name = 'dashboard/home.html'
context_object_name ='links_list'
paginate_by = 15
def get_queryset(self):
return self.model.objects.filter(author=self.request.user)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['dashboard_list']= Dashboard.objects.filter(author=self.request.user)[:15]
context['todo_list']= Todo.objects.filter(author=self.request.user).order_by('-pk')[:15]
context['PasswordUsername_list']= PasswordUsername.objects.filter(author=self.request.user)
return context
And render it with {{c_count}} in my template but was unable to do so.
Thanks
Since you probably will render the list as well, using the length template filter [Django-doc] is probably the fastest way to do this, since it will fetch the objects, and calculate the length, so we can render this like:
{{ todo_list|length }}
If you are only interested in the length itself, and not in the objects of a todo_list, we can call .count() on the QuerySet, but this also has an extra disadvantage that it will only work for QuerySets (or classes that have a .count() method):
<!-- only interested in the count, not in the objects -->
{{ todo_list.count }}

How to retrieve the output of for-loop (dictionary) from models to views?

I have this model:
class ModelName(models.Model):
def my_dict(self):
for i in range(n):
…#some code
context_a = {‘a’: a}
return context_a
I need to take context into view like this:
from .models import ModelName
class ViewName
model = ModelName
template_name = ’template_name.html’
def context_b(request):
context_b = ModelName.objects.get(context_a=context_a) #here I want to get context_a as a dictionary and pass it to context_b for further operations. I know that my syntax here is not correct.
return render(request, self.template_name, context_b)
If I do it, I get
Method Not Allowed: /
[18/Nov/2018 12:40:34] "GET / HTTP/1.1" 405 0
I would like to know how to do it correctly, and also which specific resource (documentation and/or article) should I read/learn to understand my problem.
I would appreciate any help.
I think you are not subclassing proper class based view here.
The error you are getting is that, you are calling get method, but the View you have provided does not support that. For simplistic purpose, lets use DetailsView which supports get request, so you can try like this:
class YourView(DetailsView):
template_name = 'template_name.html'
model = MyModel
def get_context_data(self, **kwargs):
context = super(YourView, self).get_context_data(**kwargs)
context_a = self.object.my_dict() # here you will get the dictionary from model in view
# by the way, you can also access the your model object from context via context['object'] and in template via {{ object }}
return context
And access dictionary of the template like this:
{% for k, v in object.my_dict.items %}
{{ k }} - {{ v }}
{% endfor %}
Also the Url
#urls
path('/someview/<int:pk>/', YourView.as_view(), name="your_view"),

Django - Multiple <pk> in urls.py with DetailViews

I'm trying to build a script using Django Generic display views.
My urls.py
url(r'^page/(?P<pk>[0-9]+)/$', PageDetails.as_view(), name='page-details'),
My views.py
class PageDetails(DetailView):
model = Pages
def get_context_data(self, **kwargs):
context = super(PageDetails, self).get_context_data(**kwargs)
return context
The problem
How can I set multi <pk> in my urls like this?
url(r'^page/(?P<pk>[0-9]+)/subpage/(?P<pk>[0-9]+)$', PageDetails.as_view(), name='page-details'),
In my views I need to take data from first and second <pk>.
Change the second pk argument in your url to something else, for example pk_alt:
^page/(?P<pk>[0-9]+)/subpage/(?P<pk_alt>[0-9]+)$
The url parameter pk_alt will then be available in your views function as part of the self.kwargs dictionary, so you can access it using:
self.kwargs.get('pk_alt', '')
You could then update your views to something like the following:
class PageDetails(DetailView):
model = Pages
def get_context_data(self, **kwargs):
context = super(PageDetails, self).get_context_data(**kwargs)
page_alt = Pages.objects.get(id=self.kwargs.get('pk_alt', ''))
context['page_alt'] = page_alt
return context
You will then be able to access the alternative model in your template using {{ page_alt }}
If you need two arguments in the url try this:
url(r'^page/(?P<pk_1>[0-9]+)/subpage/(?P<pk_2>[0-9]+)$', PageDetails.as_view(), name='page-details'),
Then you have pk_1 and pk_2 available as kwargs

Accessing get method data in Django Template

I have read docs and other things, tried many tuts but still no luck. What I am trying to achieve is to show a custom error message.
I have this: /?message=success
And want to access this data in my Django template
class mysite(TemplateView):
template_name = 'index.html'
def get_context_data(self, **kwargs):
context = super(mysite, self).get_context_data(**kwargs)
return context
def get(self, request, *args, **kwargs):
return super(mysite, self).get(request, *args, **kwargs)
How I am accessing it in my template file:
{{ message }}
This gives no output. What I need is success to be read. Then I will do a conditional block on its base.
You can add message to the template context by changing your get_context_data method to
def get_context_data(self, **kwargs):
context = super(mysite, self).get_context_data(**kwargs)
context['message'] = self.request.GET.get('message', '') # default to empty string if not in GET data
return context
Then access message in your template with:
{{ message }}
Alternatively, make sure you are using the request template context processor, to make the request object available in your templates.
Then in your template, you can access the GET data with:
{{ request.GET }}
and the message parameter with:
{{ request.GET.message }}

Categories