Dynamically alter urls.py to support dynamically created URLs? - django

I'd like to create a web service using Django that dynamically adds URLs to my urls.py file. Can this be done in Django? In other words, I'd like to have users be able to sign up for an end point that gets dynamically created using Django, e.g. my domain "dynamicurl.com" could add /johnp/ via a registration of user johnp. How would I do this?

Just create a pattern that matches the required characters for your username. Here is an example:
url(r'(?P<username>[\w.#+-]+)/$',
'yourapp.views.user_home', name='user-home'),
Then, when someone goes to yourdomain.com/johnp/ in your view you can do something like:
def user_home(request, username=None):
return render(request, 'user_home.html', {'username': username})
In user_home.html:
<strong>Welcome {{ username }}</strong>
Which will result in:
Welcome johnp

Consider this situation.
Suppose at some point in time you have a million users, your urls.py file will have a million records for user pages only. And I hope you do not wish to have separate views to handle all these separate urls.
Therefore, it is better define url patterns that can dynamically alter the content inside the templates depending on the value received within the url.
Using class based views, this can be done as follows:
In your urls.py file, write
url(r'^(?P<user_name>(.*))/$',ProfileView.as_view(),name='profile-view'),
class ProfileView(TemplateView):
template_name = "abc.html"
def get_context_data(self,**kwargs):
context = super(ProfileView,self).get_context_data(**kwargs)
context['user_name'] = kwargs['user_name']
return context
Then, in your template you can use it as {{user_name}}.

Related

How to Django reverse to pages created in Wagtail?

I have a Wagtail model for an object.
class ObjectPage(Page):
# fields, not really important
I want to make the object editable by front-end users, so I have also created a generic update view to accomplish this. My question is how I can use Django's reverse() function to point to the edited object in my get_success_url() method:
class EditObjectPage(LoginRequiredMixin, UpdateView):
# model, template_name, and fields defined; not really important
def get_success_url(self):
return("ObjectPage", kwargs={"slug" : self.object.slug}) # doesn't work
return("object_page_slug", kwargs={"slug" : self.object.slug}) # also doesn't work
I know how to do this when I'm explicitly defining the URL name in my urls.py file, but in this case, the URL is created as a Wagtail page and is handled by this line of my urls.py:
url(r"", include(wagtail_urls)),
I've been searching the documentation for whether Wagtail pages are assigned names that can be reversed to, but I'm finding nothing in the official documentation or here on StackOverflow.
The page object provides a get_url method - get_success_url should be able to accept this directly, so there's no need to use reverse.
def get_success_url(self):
return self.object.get_url()
Internally the URL route used by get_url is wagtail_serve, so if you absolutely need to go through reverse, you could replicate the logic there.

Can different Django apps serve the same URL for different MIME types?

I want a URL, say /users/fred, to serve different content based on the Accept header. If the requested MIME type is application/activity+json, I want to serve an ActivityPub representation of Fred's account; otherwise, I want to serve an HTML page.
The twist is that I want to implement the ActivityPub view and the HTML view in different Django apps. If they were at different URLs, this would be easily done with urls.py, but that doesn't seem to allow filtering by Accept.
Is there a standard way to do this? Do I need to implement something new in middleware?
If you mean that you want that calculation done in the urls.py path itself, no you can't. A url path is linked to a single view function (or View.as_view()). These only apply pattern matching on the url itself.
However, you can certainly link it to a first view function which reads your header and dispatches it to the right app view based on its content.
e.g.
In a urls.py
url_pattern = [
...
path('/users/<str:username>', views.user_dispatch_view(), name='user-detail'),
]
In app1.views.py
from app2.views import json_view
def html_view(request, **kwargs):
'''
Do your stuff, or even use a generic view instead,
calling it with YourGenericView.as_view(request, **kwargs)
'''
def user_dispatch_view(request, **kwargs):
if request.Meta.get('Accept') == application/activity+json:
return json_view(request, **kwargs)
return http_view(request, **kwargs)

How to extend django admin view?

i want to display additional sidebar in my django admin index. I have created templates/admin/index.html and it show up. Now i need some data from model. To do this I have created index function in the file admin/views.py
def index(request):
var = 'var'
return render_to_response('admin/index.html', {'var': var})
Without this function I have error ViewDoesNotExist.
However template not react for this sample variable 'var'. Moreover my app doesn't display in the index. I have only auth app.
I think that I'm overwriting index function form admin view. How to properly overwrite this function?
Instead of overwriting the view entirely, you can add logic to the views in your ModelAdmin (admin.py) class:
https://docs.djangoproject.com/en/dev/ref/contrib/admin/#other-methods
so for example:
class MyAdmin(admin.ModelAdmin)
...
def add_view(self, request, form_url='', extra_context=None):
# Do some extra queries that will get passed to the template
c = {'x':SomeModel.objects.all()}
super(MyAdmin, self).add_view(request, extra_context=c)
Consider using django admin tools https://bitbucket.org/izi/django-admin-tools/wiki/Home
then you get commands like manage.py customdashboard, manage.py custommenu etc.
It even has a nice bookmark-functionality to quickliy jump to certain objects or list pages.

Resolving urls to different views for different types of user profiles in Django

I'm adding a new type of user profile to site and this new type of user(say new_type) should not be able to reach the same views like the existings users.
My question is: how can i use different types of views according to user type using the same request paths without altering the existing view codes like adding
if user.profile_type == 'blah':
do_this
else:
do_that
to each view?
In detail:
i'd like to use "http://mysite.com/path/" for both types of users, running different logics and returning different displays without making differences in existing views (since there are lots of views to modify).
I'm thinking of adding different groups of views for new type, then override urls logic to resolve the request paths to relevant views, such as :
if user is of new_type
resolve path to related_view_for_new_type
else
resolve as usual
As a straight forward example: logging in admin and normal user from the same login url, and if user is admin, run the relevant views for admin and return django admin display to her, if normal user, then run the normal view and return normal website view to her, without rewriting or changing the url they are requesting. (/index/ for example)
Is it possible to extend urls in Django in such way and if so how, or should i give up overloading the same request paths and add '/new_type/' to urls (http://mysite.com/new_type/path/)for new_type users?
Thanks
To start with, what does it mean to have different types of users? A very simple way to do this would be to store an attribute on a user. That way, given a user object, you could look at this extra attribute to determine whether the user is of a special type. Django has a standard mechanism for storing additional attributes like this, which you can read about here.
Once you have a way of determining user types, you can create a single decorator and apply it to any view that needs to behave in the way you've described. Decorators are a great way of applying extra conditions or behaviour to existing functions. The logic in the decorator gets to work before and/or after the existing function, so it can very easily accomplish something like displaying a different template based on a the user's type.
Decorator functions look very odd when you first encounter them, but read it carefully and you'll soon get it. The decorator is a function itself, and you give it the function you want to decorate. It gives you back a new function, which is your old function wrapped with the extra logic.
I've written some untested example code below.
def template_based_on_user_type(special_template, ordinary_template):
def decorator(your_view_function):
def inner_decorator(request, *args, **kwargs):
# this is the logic that checks the user type before
# every invocation of this view:
if request.user.type == 'special_type':
template = special_template
else:
template = ordinary_template
# this is the invocation of the view function, with
# a custom template selected:
return your_view_function(request, template)
return inner_decorator
return decorator
#template_based_on_user_type('my-special-template.html', 'ordinary-template.html')
def my_view_function(request, template='default.html'):
# Do what you need to do here
render_to_response(template, data, RequestContext(request)
The syntax for applying a decorator is the "#" symbole, followed by the decorator function. The decorator is customized with the template names specified.
I solved this problem using decorator in urls.py:
def dispatch_by_user(staff_view, external_user_view):
def get_view(request, **kwargs):
if (is_staff_user(request.user)):
return staff_view(request, **kwargs)
else:
return external_user_view(request, **kwargs)
return login_required(get_view)
def is_staff_user(user):
return user.groups.filter(name="privileged-group").exists()
So patterns set as following:
urlpatterns = [
url(r'^$',
dispatch_by_user(
views.StaffHomeView.as_view(),
views.ExternalUserClientView.as_view()),
name='index'),
# ...
]
RTFM as usual :)
Here's the link to a possible solution :
method_splitter # http://www.djangobook.com/en/2.0/chapter08/
new_type related views' names will be derived from the originals by adding new_type_ to beginning of the name, such as index-> new_type_index
then i'll determine the view to return by simply checking the request.user.is_new_type attribute. ugly, but better than modifying gazillions of views.

Django URL configuration

I have a purchase page, it can take an optional argument as a gift, if it is a gift, the view passes a gift form to the template and if not, a regular purchase form.
my old regular url, which redirects to two seperate views:
(r'^(?P<item>[-\w]+)/purchase/$', 'purchase_view'),
(r'^(?P<item>[-\w]+)/purchase/gift$', 'gift_view'),
and the views was like this:
def purchase_view(request,item):
....use purchase form
def gift_view(request,item):
....use giftform
It is a bad design indeed, as both views having are almost everything same but the forms used.
I have also thougt about using GET and giving gift as a GET param however it wasnt a good idea as I am using POST method for these pages, especially would cause issue after validation.
How can I make this a single url and a single view?
Thanks
urls.py
url(r'^(?P<item>[-\w]+)/purchase/$', 'purchase_view', name='purchase_view'),
url(r'^(?P<item>[-\w]+)/purchase/(?P<gift>gift)/$', 'purchase_view', name='gift_view'),
views.py
def purchase_view(request, item, gift=False):
if gift:
form = GiftForm
else:
form = PurchaseForm
...