Creating a "catch all" for URLs with Python's Flask - python

I want to create custom URLs for each user on my site.
My application uses certain custom URLs for its internal pages:
/login
/gallery
/about
etc ...
How can I make a url that would come after the above urls, and supply a function urlLookup() with the string it contains? And would I have to declare this at the end of my views file?
For example:
/First-Last
And how could I extend this to multiple variables?
/First-Last/contact
/First-Last/album/photo-title

Use url variables:
#app.route("/<full_name>")
def profile(full_name):
# Lookup user by full name
#app.route("/<full_name>/<action>", defaults={"action": "contact"})
def act_on_user(full_name, action):
# Lookup user and act on them

Related

Fetching a mobile or desktop template using django middleware [duplicate]

I want to write custom template loader for my Django app which looks for a specific folder based on a key that is part of the request.
Let me get into more details to be clear. Assume that I will be getting a key on every request(which I populate using a middleware).
Example: request.key could be 'india' or 'usa' or 'uk'.
I want my template loader to look for the template "templates/<key>/<template.html>". So when I say {% include "home.html" %}, I want the template loader to load "templates/india/home.html" or "templates/usa/home.html" or "templates/uk/home.html" based on the request.
Is there a way to pass the request object to a custom template loader?
I've been searching for the same solution and, after a couple days of searching, decided to use threading.local(). Simply make the request object global for the duration of the HTTP request processing! Commence rotten tomato throwing from the gallery.
Let me explain:
As of Django 1.8 (according to the development version docs) the "dirs" argument for all template finding functions will be deprecated. (ref)
This means that there are no arguments passed into a custom template loader other than the template name being requested and the list of template directories. If you want to access paramters in the request URL (or even the session information) you'll have to "reach out" into some other storage mechanism.
import threading
_local = threading.local()
class CustomMiddleware:
def process_request(self, request):
_local.request = request
def load_template_source(template_name, template_dirs=None):
if _local.request:
# Get the request URL and work your magic here!
pass
In my case it wasn't the request object (directly) I was after but rather what site (I'm developing a SaaS solution) the template should be rendered for.
To find the template to render Django uses the get_template method which only gets the template_name and optional dirs argument. So you cannot really pass the request there.
However, if you customize your render_to_response function to pass along a dirs argument you should be able to do it.
For example (assuming you are using a RequestContext as most people would):
from django import shortcuts
from django.conf import settings
def render_to_response(template_name, dictionary=None, context_instance=None, content_type=None, dirs):
assert context_instance, 'This method requires a `RequestContext` instance to function'
if not dirs:
dirs = []
dirs.append(os.path.join(settings.BASE_TEMPLATE_DIR, context_instance['request'].key)
return shortcuts.render_to_response(template_name, dictionary, context_instance, content_type, dirs)

Django: Getting the page an object is on

Let's say I have a class Foo. I want to know what page a particular instance of Foo will be on: eg: api.myapp.com/foos/?page=25.
Given an object:
Foo.objects.get(id=500), how can I determine what page my instance will be on?
My approach is a little bit different so you can do this,
model_ids = (list(Model.objects.values_list('id', flat=True)))
This will give you the list of the ids. After that,
get_page_number = model_ids.index(obj_id) // per_page_objects + 1
If the obj_id is 500 so the index will be 499
now if per_page_objects are 10 then it will give you page number by calculating (499 // 10 +1 = 50).
This means your object having an id 500 is on the 50th page.
I hope this will work for you.
Django by itself does not predefine which url your model will be accessed through.
The documentation says - "Django lets you design URLs however you want, with no framework limitations".
So the process is rather opposite:
you define the url (look inside urls.py) and associate it with the view to be called for processing:
from django.urls import path
from . import views
urlpatterns = [
path('foos/', views.foo_list),
path('foos/<int:id>/', views.foo_detail),
you should define the views (usually in views.py)
and inside the view you can call any models to fetch data from DB
You can implement your API with additional packages like Django Rest Framework.
It has Routers that allow you to define a set of urls at once. The following will generate URL patterns like '^foos/$' and '^foos/{pk}/$':
you register your url within the router
from rest_framework import routers
router = routers.SimpleRouter()
router.register(r'foos', FooViewSet)
you should implement FooViewSet and make sure your model is used there.

Check if string matches dynamic regexp and find variables

In django web app, user may define urls with dynamic parameters, for example:
/users/:id
or
/posts/:postid/:commentid
now, I have given strings, for example:
/users/mysername <- it matches /users/:id - how can I exstract "myusername" from it?
/users/mysuername/something <- doesn't match
/posts/10/382 - match, extract two variables - postid and commentid
my models.py:
class Server(BaseModel):
url = models.CharField(verbose_name=_('URL'), max_length=64)
in my view, I want to compare request's PATH_INFO:
endpoint_url = request.META.get('PATH_INFO').lower().strip().lstrip('/')
lets say I have a Server model instance with url: /users/:someid
now, when request path is: /users/somestring0
I want to match it and extract variable someid to be "somestring0".
Parmeters may contain anything - except slash (/) probably.
How can I achieve something like that?
If these endpoints are registered in Django routes, maybe just use resolver ?
from django.urls import resolve
match = resolve(my_url)
print(match.args)
print(match.kwargs)

Pass variable from jinja2 template to python

Sorry if this is a noob question I am still learning. I have passed a variable from python code to a jinja2 HTML template to set up a URL, like this:
Delete
When this link is pressed it should run a query that deletes the entity with that ID. But when the link is pressed it goes to /delete/1827424298 for example, which results in a 404 error as the request handler doesn't exist.
I need to pass that ID back into my python code so it can run a method to delete the entity with that same ID. How do I go about doing this? Using webapp2 if that is important.
class DeleteRequestHandler(webapp2.RequestHandler):
def get():
template = template_env.get_template('myrequests.html')
context = {
'results': results.key.id()
}
self.response.out.write(template.render(context))
EDIT: I've added my delete handler - it is incomplete as I have yet to add the query to delete the entity. My thinking behind it so far is I can grab the results.key.id() from the jinja2 template and put it into results but I am not sure if this would work.
So I think what you're confused about is how to set up a route handler with a dynamic part to the URL. It's a shame that this is completely skipped over in the webapp2 tutorial, as it's a fundamental part of writing any web application. However, it is covered well in the guide to routing, which you should read.
At its simplest, it's just a matter of putting a regex in the route:
app = webapp2.WSGIApplication([
...
(r'/delete/(\d+)', MyDeleteHandler),
])
which will now route any URL of the form /delete/<number>/ to your deletion handler.
The ID that you pass in the URL will be the first positional argument to the handler method:
class MyDeleteHandler:
def get(self, item_id):
key = ndb.Key(MyModel, item_id) # or whatever

Shared/Global Dictionary in Django Between URLs and Context Processor

At runtime I'm trying to generate a tree of parent-child relationships between views using the urls.py of different apps. I'm trying to accomplish breadcrumbs by allowing this tree to be defined by an extension of the url function that accepts extra arguments for view_name (name to display on page when used on page, like "Home") and parent_view (specifies the immediate parent so you can generate your breadcrumb).
This class is defined in a separate file in its own module utils.breadcrumbs. The class is called BreadCrumbs and I try to define an instance of BreadCrumbs in the same file for import into various files. This is where it breaks I think.
utils/breadcrumbs.py
class BreadCrumbs:
breadcrumbs = {} # This is our tree
def url(self, pattern, view, arguments={}, name=None, view_name=None, parent_view=None):
... Adds node to self.breadcrumbs ...
return url(pattern, view, arguments, name)
bc = BreadCrumbs()
app/urls.py
from utils.breadcrumbs import bc
urlpatterns = patterns('',
bc.url(r'^home/$', 'app.views.home', name='home', view_name='Home'),
bc.url(r'^subpage/$', 'app.views.subpage', view_name='Sub Page', parent_view="app.views.home"),
)
Then I try to access the tree defined in breadcrumbs.bc in a context processor using the view name given through a middleware. When I had all of my url patterns in the core urls.py file instead of in separate apps, it worked fine. Now that I've moved the url patterns to separate files, the tree is empty when I go to call it in my context processor using a from utils.breadcrumbs import bc. Am I using global variables incorrectly here? Is there a more correct method to share a variable between my urls.py and my context processor? I've looked at sessions, but I don't have access to the request in urls.py, correct?
Your help is appreciated in advance.

Categories