How to handle url collisions in django/wagtail - django

how to handle two different views witch match for the same url? (Both views need a database call to determine if the called element is available. Changing the url structure is not an option.)
url(r'^', include(wagtail_urls)),
This wagtail url is matching all url's and is raising an 404 if the according page/slug is not in the database.
But, I also have my own view witch behaves similar. How can I tell django to continue with the next url instead of raising a 404?
(I could place my own view before the wagtail view and modify it, but I don't know how to return to the next url?)
This is my solution at the end:
from wagtail.wagtailcore.views import serve
# ... in my view where I normally return a 404 => I set this:
return serve(self.request, self.request.path)

First of all, Sharing same url pattern in diffrent views is bad idea.
The bigger your project, the harder it will be to maintain it.
Nevertheless, there is a way if you want that way.
You can place your own view first in urls.py like your saying,
process some your own logic first and catch 404 exception when there is nothing to show in your view than simply call the "Wagtail" view with request original parameters(page, slug, etc..) with return statement.
Below is example.
This example is based on Django functional based view, but there is the way in class based view something like this.
def your_own_view(request, slugs):
try:
article = get_object_or_404(Article, slugs=slugs)
except Http404:
return some_wagtail_view(request, slugs)
...
return render(request, "article/view.html", context)

Related

Django URL and making a portion of it optional, but using the same class API View

So I have this API URL on the back-end and I am wondering how to make a portion of it optional.
url(r'^api/documents/(?P<id>[0-9]+)$', GetDocumentsAPIView.as_view(), name='documents'),
So two things can happen coming from the front-end.
1) When the user logs in, it brings them to the /home which lists all of their projects. Clicking on the project brings them /documents/85 where the number is the number of the project and it lists all the documents for that project. This is sent to the API URL /api/documents/85. This much is working fine.
2) The other option is the user will just click on a Documents link in the navbar, which will just bring them to /documents. This should just go to the API URL /api/documents/ and eventually onto the serializer.py where their most recent project is determined and the documents for that are returned and rendered in the front-end
This I can't get working. Not sure if I can do it with just one url(), or if I need two. Was hoping the one I posted would look at the (?P<id>[0-9]+)$ as optional and if nothing was there would return the same GetDocumentsAPIView, but this is not the case.
EDIT: Including the view I am using for testing at this point. Just print() to see if anything is being routed to the view.
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
class GetDocumentsAPIView(APIView):
permission_classes = [IsAuthenticated]
def get(self, request, *args, **kwargs):
print(kwargs.get('id'))
return Response('Test')
No you need to add a URL pattern for r'^api/documents/$', which can launch the same view by the way. Only inside the view you'll have to assume id is optional:
if kwargs.get('id'):
# return specific document
else:
# return list of documents
I would rename your first URL pattern to 'view_document' so you can use the name 'documents' on the other, more generic view.
Note: I think your URL structure is wrong. Reading your URL, according to REST, I would expect to see the document with id 85 when fetching documents/85. If you actually are listing the docs of a project, the URL should be projects/85/documents/ or if unspecified projects/documents.

Passing a list of URLS from one page to another

On the index page of my Django site I generate a list of urls that allow the user to navigate to a detail page. Once the detail page appears the navigation is no longer visible.
What I am trying to achieve is that the navigation list appears on the detail page (and every page that is added to my site).
What I have tried is the following: (the first line in each view is duplicated)
def index(request):
**collection_urls = Collection.objects.order_by('the_year')**
return render(request, 'index.html', {'collection_url': collection_urls})
def originalexample(request, collection_id):
**collection_urls = CarCollection.objects.order_by('the_year')**
car = get_object_or_404(CarCollection, pk=collection_id)
return render(request, 'detail.html', {'originalexample': car, 'collection_url': collection_urls})
Whilst this works, I know it is not right as I running the query twice. My next thought would be to perform the query once and then pass it to the pages as they are rendered. If so how would I do that? or is there a more pythonic method?
In case of need I'm using Django 1.6.2 and the list of urls does not change frequently (They can only be changed via the Django admin screens)
Thanks in advance.
You don't want to pass them from one to another, you simply want them to appear everywhere. That is usually done via context processors or custom tags.

Is there a way to have the django admin model list link to the last page of resutls?

We have these moderately large and constantly growing tables and the most interesting stuff is always the most recent. Currently we have them ordered by creation time, so the interesting stuff is at the end. This requires 2 clicks when navigating, one to select the model and another select the last page.
I could of course change the order so the most recent stuff is at the front, but then the content of the pages would be continually changing as new stuff is pushed on the front, making exploration of the history harder.
So I was wondering if there was a way to have it go straight to the last page?
You can alter the change_list template (the pagination block) to show {{page.last}}
https://github.com/django/django/blob/master/django/contrib/admin/templates/admin/change_list.html
This is a pretty peculiar request, but you could redirect the admin view if there is no page parameter in the URL (i.e. you are on the frontpage).
from django.shortcuts import redirect
from django.core.urlresolvers import reverse
class MyAdmin(admin.ModelAdmin):
...
def changelist_view(self, request, extra_context=None):
if not request.GET.get("p", False):
return redirect("%s?p=%s" % (
reverse("admin:my_app__model__changeview"),
self.paginator.page_range[-1])
super(MyAdmin, self).changelist_view(request, extra_context=extra_context)
an alternative is to inject a p URL paremeter into the request before passing control over to the parent changelist_view method (but this requires copying the request). Edit: Wouter's solution is actually nice and simple

Django view: good programming practice question

suppose that you have a webpage that uses the post and get method, and you wrote the following view to generate it:
def homepage(request):
if 'login' in request.POST:
# ......... code goes here, and you return an appropriate response
if 'register' in request.POST:
# ......... code goes here, and you return an appropriate response
# When no Post request, just render the page
return render_to_response('homepage.html')
Question:
Is it considered good programming practice to split the above view into three views: one for login, one for register and one that would render the page? Or is it OK to keep it as it is.
EDIT
in the case listed above, I am not checking if the server received a "GET". But the idea is still the same :)
I think a better idea would be to have each of the two forms submit to a different URL. Then you can define views for, e.g., /login, /register, and / (the default homepage handler). Your views for /login and /register can use if request.method == 'POST', and then redirect to the homepage if they are called with a GET request.

Get user from URL segment with Django

I have a web application which will return a user id based on the first segment of the url, much like Twitter:
http://www.myapplication.com/user-name-goes-here/
It can go deeper too, like so:
http://www.myapplication.com/user-name-goes-here/news/article_1/
In order to break the site down, I am using the following URL routing technique:
(r'^(?P<slug>\w+)/', include('myapp.sites.urls')),
This will then further route the user to the correct page, but as it stands I am having to query the database in every view in order to obtain the user_id based on the first url segment. I was hoping to somehow automate this so I don't have to bloat my views with the same code each time... my solution was to create some middleware which checks the url segment and returns a 404 if its not found:
from django.http import Http404
class DomainMiddleware(object):
def process_request(self, request):
from myapp.sites.models import Sites
dname = request.path.split('/')[1]
if not dname:
return
try:
d = Sites.objects.get(domain__exact=dname)
except Sites.DoesNotExist:
raise Http404
return
This works, but it's trying to parse EVERY request, even those to images, favicons etc.
My question is thus; Is there a way to run this query on every page load without clogging up my views with extra code? If middleware is the solution, how can I modify my code so that it doesn't include EVERY request, only those to successfully routed URLs?
Hope someone can help!
The Django server shouldn't be processing requests for static content URLs - certainly not in production anyway, where you'd have a different web server running to handle that, so this shouldn't be an issue there.
But if you say you'd like this to run for only sucessfully routed URLs, maybe you'd be better of using process_view rather than process_request in your middleware? http://docs.djangoproject.com/en/dev/topics/http/middleware/#process-view
process_view works at view level rather than request level, and provides a view_func argument which you can check so that your code doesn't run when it's the django.views.static.serve view used for serving static media during development.
Whatever happens you should defs be caching that database call if it's going to be used on every view.