django paginationated first page content different to root page content (with cache) - python

I am paginating content based on a random queryset and I seem to be getting inconsistent results between the paginated first page ?page=1 and the root page itself.
So, I have my ListView like so:
class Some1_ListView(ListView):
model = Some_Model
template_name = "test1.html"
paginate_by = 12
context_object_name = "test1"
queryset = Some_Model.objects.all().order_by('?')[:24]
My urls is like so:
urlpatterns = [
path('test1/', cache_page(500)(Some1_ListView.as_view()), name="test1" ),
]
and the template is paginated according to the django docs, nothing special. Now, when I go to:
localhost/test1
I get the first 12 objects. Now, When I move to the next page, onbiously, my url becomes:
localhost/test1/?page=2
This renders fine aswell. Now, when I go back to
localhost/test1/?page=1
I see that the results are not the same as localhost/test1/
So, localhost/test1/?page=1 != localhost/test1/ Since I was caching the URL, I was expecting these two to be the same.
Can someone enlighten me as to why this is? and how do I get aorund it? Id like both these pages to show the same content (from cache).

Related

Returning a filter result in a different page - Django

I've searched up but nothing seams to do the trick or be on point.
Let's say i have two websites on page A.html I have a filter (djnago_filter) and B.html is empty. If the user submits the search form he is redirected from page A.html to page B.html where the results are displayed with for loop.
How do I to that?
I was thinking about passing the data from query set to another view but there must be better solution to this.
There are several ways to store and display information on the different views(pages):
You could use the Sessions:
#views.py
#set the session key in the view A:
request.session['info'] = {'key', 'value'}
#get the session key in the view B:
info = request.session['info']
del request.session['info']
You could use Models with JSONField:
#app/models.py
#model to store information from page A
from django.contrib.auth.models import User
class MyModel(models.Model):
user = models.ForeignKey(User,
on_delete=models.DELETE,
related_name="info")
info = models.JSONField()
#views.py
#store data in the view A:
from app.models import MyModel
MyModel.objects.create(user=request.user, info={'key', 'value'})
#retrieve data in the view B:
info = MyModel.objects.get(user=request.user)
But actually, all depends on the logic that you intent to achieve. There are actually other methods like using async Ajax, React, WebSockets...
you can pass it as an HTML request parameter inside the url, for example, in your pageA template will be
to page B
and inside pageb view, you can take the filter from the request object
def page_b_view(request):
some_filter = request.GET.get('some_filter')

Site wide navbar search using class based views

I have a search form in the navbar that is obviously available site wide, however, search only works on the home page because thats the view the search code is written. I figured class based views were the answer such that I could easily add the search functionality as a mixin or something of the kind.
Bottomline: I'm having trouble abstracting the search functionality in a class based DRY
The search form returns www.site.com/?q=search. I need to grab q from the GET request and return that info to my search.html page.
This is my code as it stands
views.py
class HomeListView(ListView, Searchmixin):
model = Part
queryset = Part.objects.order_by('-creDate')
template_name = 'parts/index.html'
paginate_by = 20
is_paginated = True
search.py
class SearchMixin(object):
def sindex(self):
query = self.request.GET.get('q')
return httpResponse(query)
def perf(self, query):
if query is not None:
pollist = self.objects.filter(
Q(project__name__icontains=query) |
Q(owner__icontains=query) |
Q(description__icontains=query) |
Q(pnumber__icontains=query)
)
return render(request, 'parts/search.html', pollist)
Nice job creating your first site. On every view that you would like to have a functional search bar, you should include the SearchMixin that you've created.
One important thing that will save you some trouble down the road is to make sure that the generic class-based views go on the right-hand side of any mixins that you've created -- i.e. class HomeListView(Searchmixin, ListView). That's because Python has an order in which it builds up the class based on what it's inheriting from. Sometimes there could be conflicts if the default ones get overwritten before they're supposed to.
Instead of using SearchMixin and inheriting everywhere, I suggest creating a SearchView, assigning it some URL and returning search results from there.
# urls.py
urlpatterns = [
url(r'/search/', SearchView.as_view(), name='search'),
...
]
# views.py
class SearchView(ListView):
paginate_by = 20 # to show 20 search results per page
def get_template_names(self):
return ['parts/search.html']
def get_queryset(self):
query = self.request.GET.get('q')
pollist = YourModel.objects.all()
if query:
pollist = pollist.filter(
Q(project__name__icontains=query) |
Q(owner__icontains=query) |
Q(description__icontains=query) |
Q(pnumber__icontains=query)
)
return pollist
Now in your JavaScript, you can perform asynchronous GET request to http://www.your_site.com/search/?q=some_search_term, and fetch results and append them in DOM. Hope this helps.

Django admin - add custom link to change list view

Firstly thanks for taking the time to read my problem
I tried to add a custom button to my admin changeList view, but it always gives me Page not found (404)
This my modelAdmin code:
class MyModelAdmin(admin.ModelAdmin):
class Media:
js = ('admin/js/additional_js.js',)
model = MyModel
def get_urls(self):
urls = super(MyModelAdmin, self).get_urls()
analyze_url = patterns('',
(r'^(?P<pk>\d+)/analyze/$',
self.admin_site.admin_view(self.analyze_view))
)
return analyze_url + urls
def analyze_view(self, request, pk):
# some code here
HttpResponseRedirect(
reverse('admin:myapp_MyModel_change', args=(pk,))
)
My jQuery code for adding custom link to change list view:
(function($) {
$(document).ready(function($) {
$(".object-tools").append('<li>Analyze</li>');
});
})(django.jQuery);
when I click my custom link it gives me this:
MyModel object with primary key '3/change/analyze' does not exist.
I see that the link does not point to the view
Can someone help me fix this issue.
Thanks
In Django 1.9, the admin change url has changed to /admin/<app>/<model>/<pk>/change/ (release notes).
Therefore, it doesn't make sense to link to href="analyze/" in your html. The relative url is treated as /admin/<app>/<model>/3/change/analyze, not /admin/<app>/<model>/3/analyze as you expect.
You can probably fix the problem by changing the link to:
<a href="../analyze/" ...
Ideally, it would be better to reverse the url rather than having a relative link. I think this would make the code less fragile.
Since you are using Django 1.9, you can update your code to use a list rather than patterns:
from django.conf.urls import url
analyze_url = [
url(r'^(?P<pk>\d+)/analyze/$', self.admin_site.admin_view(self.analyze_view)),
]

How do I use DateDetailView with a slug to render a page with a single article?

I am new to Django, and I am trying to have a separate page where I can view individual articles. Currently I have:
#views.py
class ArticleView(DateDetailView):
template_name = 'blog/article.html'
model = Article
date_field = "pub_date"
#I am not sure which one to use
slug_field = "unique_url_suffix"
slug_url_kwarg = 'unique_url_suffix'
and
#urls.py
urlpatterns = [
url(r'^(index\.html)?$',views.IndexView.as_view(),name='index'),
url(r'^(?P<year>[0-9]{4})/(?P<month>[-\w]+)/(?P<day>[0-9]+)/(?P<slug>[-\w]+)/$',
views.ArticleView.as_view(),
name="article_detail"),
]
and in index.html inside a loop of objects from the Article class:
<h2>{{article.title}}</h2>
I have also tried manually inputting the arguments, like this:
<h2>{{article.title}}</h2>
I keep on getting a "NoReverseMatch at /blog/" error. What am I doing incorrectly?
Edit: On top of the changes recommended for the answer, there was a typo causing problems. It does not affect the answer below, though.
First off, you should not be generating this URL in your template. You should define a get_absolute_url method in your Article model that looks like this:
from django.core.urlresolvers import reverse
def get_absolute_url(self):
# Note - you have to supply each of the date components separately
# because you need to match the URL regex.
return reverse (
'blog:article_detail',
kwargs={'year': self.pub_date.strftime("%Y"), 'month': self.pub_date.strftime("%b"),
'day': self.pub_date.strftime("%d"), 'slug': self.unique_url_suffix}
)
And then in your template:
<h2>{{article.title}}</h2>

Django URL Patterns

I've created a very simple blog, but have been running into a couple URL issues. For my tag & specific post views I run into the following issues.
Specific Post View ExampleThese two sites render the same, and would like the second one to render a 404. website.com/post/1/hello-world website.com/post/1/hello-world/non-sense (should render 404)
Tag View
website.com/tag/python: this will render all posts tagged python, great. However...
website.com/tag/python/party: this will render all posts tagged "python/party" instead of rendering a 404.
Here is my URL patterns setup so you can take a look.
url(r'^post/(?P<pk>\d+)/(?P<post_title>)', DetailView.as_view(
model = post,
template_name = "post.html")),
url(r'^post/$', ListView.as_view(
queryset = post.objects.all().order_by("-date"),
template_name = "archives.html")),
url(r'^archives/$', ListView.as_view(
queryset = post.objects.all().order_by("-date"),
template_name = "archives.html")),
url(r'^tag/(?P<tag>[\w|\W]+)', 'tags'),
Updated
Solution for tag:
url(r'^tag/(?P<tag>[\w]+)\W*/$', 'tags'),
Solution for post:
url(r'^post/(?P<pk>\d+)/(?P<post_url>[\w-]+)/$', DetailView.as_view(
model = post,
template_name = "post.html")),
Thank you Huckleberry Finn and krakax for all the help!
Your post URLconf regex
url(r'^post/(?P<pk>\d+)/(?P<post_title>)', DetailView.as_view(
model = post,
template_name = "post.html")),
Should changed to
url(r'^post/(?P<pk>\d+)/(?P<post_title>[-\w]+)/$', DetailView.as_view(
model = post,
template_name = "post.html")),
means URLconf is ending with end-slash
Anyway, Try to define you DetailView URLconf after post ListView. In my opinion if you change your list view and detailview to posts/ and post/ you problem will be solved. The solution is same for tags URLconf issue.
Your regex
r'^tag/(?P<tag>[\w|\W]+)'
means that group tag will contain all caracters after 'tag/'. [\w|\W] means 'all alphanumerics' or 'all but alphanumerics'. This is equivalent to 'all caracters'.
It should be changed to
r'^tag/(?P<tag>[\w]+)\W*'
This will stop your group at first non alphanumeric
Sure, right now I see 2 ways.
First, change to:
r'^tag/(?P<tag>\w+)(?P<end>\W.*)'
(BTW, [] is not necessary in your case) This way, you get the group called 'end' as a parameter of your tag controller and you can test it and redirect to your 404 custom page or generate a 404 classic error.
Second possibility is:
Add another url hook and controller:
url(r'^tag/(?P<tag>\w+)\W*', 'tags404'),
url(r'^tag/(?P<tag>\w+)$', 'tags'),
This way, you forbid any url that contains others caracters than alphanumerics after the 'tag/'.
If you want to allow just one optional '/' at the end, you can write in place of your new hook:
url(r'^tag/(?P<tag>\w+)/?$', 'tags'),

Categories