Django 1.9 : Passing arguments from urls.py to a class view - python

I am creating a small web application as a mini project of mine to learn the Django framework. I'm on Version 1.9.4, on OS X. I'm trying to pass a string in the URL that will be sent to a class-based view, and it will return a different template based on the URL. To my knowledge, doing (?P) will allow the input of dynamic text. \w is for characters, and writing <name> will pass it as a variable. Is this configured right, or is this is not the correct way to do it?
The reason I'm concerned is that the Django documentation uses method views, while I am using class-based views.
urls.py
from django.conf.urls import url
from . import views
app_name = 'xyz'
urlpatterns = [
url(r'^create/(?P<ty>\w+)$', views.ArticleView.as_view(), name='article-form'), #.as_view() to turn Class into View
]
views.py
class ArticleCreate(View):
l = {
'weapon': WeaponForm,
'map': MapForm,
'operator': OperatorForm,
'gadget': GadgetForm,
'skin': SkinForm
}
ty = ty.lower()
template_name = 'xyz/create_article_form.html'
def get(self, request):
return render(request, self.template_name)
def post(self, request):
pass

The arguments that are being passed to the url should be "catched" within the view inside the relevant function, for example:
def get(self, request, ty):
ty = ty.lower()
return render(request, self.template_name)

Related

Empty `request.user.username` while handling a GET request created

I was trying out logging all URLs accessed by user along with user id and date time when it was accessed using django middleware as explained here.
For some URLs it was not logging user id. I checked and found that the request.user.username was empty string. I checked views corresponding to those URL and found that those views did not have desired decorators. For example, I changed this:
def getXyz_forListView(request):
# view body ...
to this:
#api_view(['GET'])
#authentication_classes([TokenAuthentication,])
def getXyz_forListView(request):
# view body ...
and it started working.
However some views are created from classes:
class XyzView(View):
def get(self, request):
# view body ...
I added same decorators:
class XyzView(View):
#api_view(['GET'])
#authentication_classes([TokenAuthentication,])
def get(self, request):
# view body ...
But it is still not working. What I am missing?
PS:
It is added to urls.py as follows:
urlpatterns = [
# ...
url(r'^xyz/', XyzView.as_view(), name="xyz"),
]
I think you should try to inherit from APIView class:
from rest_framework.views import APIView

Django URL dispatcher - Try next view

Alright, let me give you guys an example;
We have the following url configuration in Django.
Django will try to match the url with the rules down below. Once it finds a match, it will use the appropriate view and lookup the object in the model.
The thing is, once it finds a match in the URL pattern, it will match the view. But once the object
in the view can't be found, it will return a page not found (404) error.
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('articles/<slug:category>/<slug:editor>/', views.ArticleByThemeView.as_view(), name='articles_by_editor'),
path('articles/<slug:category>/<slug:theme>/', views.ArticleDetailView.as_view(), name='articles_by_theme')
]
views.py
class ArticleByThemeView(ListView):
"""
List all articles by a certain theme; "World War 2".
"""
model = Article
def dispatch(self, request, *args, **kwargs):
try:
# Check if the theme_slug matches a theme
theme = ArticleTheme.objects.get(slug=self.kwargs['theme_slug'])
except ArticleTheme.DoesNotExist:
# Theme does not exist, slug must be an article_slug
return redirect(
'article_detail',
category_slug=category_slug
article_slug=theme_slug
)
return super().dispatch(request, *args, **kwargs)
class ArticleDetailView(DetailView):
"""
Detailview for a certain article
"""
model = Article
def get_object(self):
return get_object_or_404(
Article,
category__slug=self.kwargs['category_slug'],
slug=self.kwargs['article_slug']
)
We have the following url patterns, we can sort articles either by the editor or by theme. We do this to create a logical url structure for SEO purposes.
Is their any way we can redirect to another view once the object isn't found?
Can we modify the dispatch method to return to the url patterns and find the following matching rule?
What about redirection like this:
def articles_by_editor(request, category, editor):
try:
article = Article.objects.get(category=category, editor=editor)
# return article
except Article.DoesNotExist:
# redirect to another view
return redirect('articles_by_theme', category=category)
Alright,
Based on the suggestion from Sunderam Dubey, I'wrote a function view, which uses two differn routes to the same view.
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('articles/<slug:category>/<slug:slug>/', views.article_theme_or_detail_view, name='article_by_theme'),
path('articles/<slug:category>/<slug:slug>/', views.article_theme_or_detail_view, name='article_detail')
]
views.py
def article_theme_or_detail_view(
request,
category_slug,
slug=None
):
"""
This view could either be for a theme view or detailview,
depending on the slug.
"""
try:
# Check if the slug represents a theme
theme = ArticleTheme.objects.get(slug=slug)
article_list = Article.object.filter(theme=theme)
# Add context
context = {
'theme': theme,
'article_list': article_list
}
# Render the template with context
return render(
request,
'article_by_theme.html',
context
)
except ArticleTheme.DoesNotExists:
# The theme does not exist so the slug must be for a detail view
context = {
article = Article.objects.get(slug=slug)
}
return render(
request,
'article_detail.html',
context
)
Todo:
Remove one of the url routes

Customize django admin. Problem with no-model views

Im trying to create a extra view in django admin, on the left navbar. This view will be responsible for uploading a file, which will be parsed in some function (in future i would like to render result of this parsing in admin page). This file wont be saved in database, so there wont be a model. Is there any possibility to add a view to django admin (left navbar) which dont have a model? I was reading a lot, and could find a solution. What i have done for now:
Created a class which inherits from AdminSite. I tried to implement get_app_list method, but variable self._build_app_dict(request) was empty array, and this means, method couldn't find a installed aps. I wanted to add new object to app_list variable, to render it on website.
Tried to override a admin templates, but couldnt render it. I tried to override app_index.html which i put on folder: app_name/templates/admin/app_index.html
Here is my code, which ofc doesnt work:
class MyCustomAdmin(AdminSite):
def get_app_list(self, request):
"""
Return a sorted list of all the installed apps that have been
registered in this site.
"""
app_dict = self._build_app_dict(request)
breakpoint()
app_list = sorted(app_dict.values(), key=lambda x: x['name'].lower())
for app in app_list:
app['models'].sort(key=lambda x: x['name'])
return app_list
def get_urls(self):
from django.conf.urls import url
urls = super(MyCustomAdmin, self).get_urls()
urls += [
url(r'^my_custom_view/$', self.admin_view(MyCustomView.as_view()))
]
return urls
class MyCustomView(View):
template_name = 'admin/app_index.html'
def get(self, request):
print('fefef')
return render(request, self.template_name, {})
def post(self, request):
pass
admin_site = MyCustomAdmin()
admin_site.get_app_list(AdminSite.get_app_list)

Django Sitemap Framework. Accepting query parameters

I'm using the Django Sitemap Framework
I've no problem retrieving a list of articles from my DB.
class ArticleSitemap(Sitemap):
def items(self):
return articles.objects.filter(tagid=1399).order_by('-publisheddate')
I now want to accept a query parameter to filter by an inputted tag id ie:
sitemap.xml?tagid=1000
I have yet to find an example in the docs or on stack.
It is not possible to access HttpRequest object from Sitemap class. Probably the easiest way is to create your own view(s) for the sitemap(s), do what you need to do with HttpRequest and call Django internal view to do the final rendering of XML.
Setup your sitemap URLs as Django docs says (https://docs.djangoproject.com/en/dev/ref/contrib/sitemaps/#initialization), but use your own view(s).
urls.py:
from my_app.sitemap_views import custom_sitemap_index, custom_sitemap_section
sitemaps = {
"foo": FooSitemap,
"bar": BarSitemap,
}
urlpatterns = [
url(
r"^sitemap\.xml$",
custom_sitemap_index,
{"sitemaps": sitemaps},
name="sitemap_index",
),
url(
r"^sitemap-(?P<section>.+)\.xml$",
custom_sitemap_section,
{"sitemaps": sitemaps},
name="sitemaps",
),
# ...
]
Your custom sitemap views are standard Django views: you can access HttpRequest, database, cache...
sitemap_views.py:
import copy
from django.contrib.sitemaps import views as django_sitemaps_views
from django.contrib.sitemaps.views import x_robots_tag
#x_robots_tag
def custom_sitemap_index(
request,
sitemaps,
template_name="sitemap_index.xml",
content_type="application/xml",
sitemap_url_name="django.contrib.sitemaps.views.sitemap",
):
print("You can access request here.", request)
return django_sitemaps_views.index(
request, template_name, content_type, sitemaps, sitemap_url_name
)
#x_robots_tag
def custom_sitemap_section(
request,
sitemaps,
section=None,
template_name="sitemap.xml",
content_type="application/xml",
):
tag_id = int(request.GET.get("tagid"))
# We do not want to modify global variable "sitemaps"!
# Otherwise sitemap instances would be shared across requests (tag_id should be dynamic).
sitemaps_copy = copy.deepcopy(sitemaps)
for section, site in sitemaps_copy.items():
if callable(site):
sitemaps_copy[section] = site(tag_id=tag_id)
return django_sitemaps_views.sitemap(
request, sitemaps_copy, section, template_name, content_type
)
sitemap.py:
from django.contrib.sitemaps import Sitemap
class FooSitemap(Sitemap):
def __init__(self, tag_id: int):
self.tag_id = tag_id
super().__init__()
def items(self):
return (
Articles.objects.filter(tagid=1399)
.filter(tag_id=self.tag_id)
.order_by("-publisheddate")
)
class BarSitemap(Sitemap):
pass
# ...
# ...
Its in the request's Get-attribute:
the url '.../names/getNames?pattern=Helm' results in a request-object that has as GET : &LT;QueryDict: {'pattern': ['Helm']}&GT;

django haystack - how to use with current view having some context

I have a view that puts some context and renders the template from this context. I want view display all the things if no search query is there, and show searhed things, if anything searched.
class MyCurrentView(View):
def get(self, request):
data = { 'users': User.objects.all() }
return render_to_response("mytemp.html", ..
urls.py:
url(r'^search/$', MyCurrentView.as_view())
Now, I am integrating this with SEarchView like this:
class MyCurrentView(SearchView): (If u observe, I subclassed SEarchView).
template = 'mytemp.html'
def get(self, request):
data = { 'users': User.objects.all() }
return render_to_response...
def get_context_data(self, ...):
print "....this should print" #But not printing. So, unable to add data
return data
urls.py:
url(r'^search/$', MyCurrentView.as_view())
# as_view() gave me error, so I did MyCurrentView() , may be thats y, get_context_data not calling.
Will provide more information if necessary.
New Django-style class based views were added via PR #1130 to django-haystack:
https://github.com/toastdriven/django-haystack/pull/1130
You can now use search views like you normally would with django (see changes in pull request).
from haystack.generic_views import SearchView
class MySearchView(SearchView):
def get_context_data(self, **kwargs):
# do whatever you want to context

Categories