Django : Several paths, one ListView, different templates? - python

Please help me. I want to have multiple path in urls.py (lets say a, and b). But I want to ONLY have one ListView, and this ListView need to channel me to different html file when I access the url (a.html when access 'a/', b.html when access 'b/').
Currently I use different ListView for each path (aListView and bListView), even though the model is the same. But it seems that it violate the Don't Repeat Yourself rule. And the code looks bad.
So the question is how can I define several different templates in one ListView?
Below is my current mind map. Thank you
My mind route

Here is an example of how you can define multiple paths that points to one ListView within multiple templates:
Let's suppose my app name is example and my project name is test_project; my setup is like this:
test_project/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
..., # my project urls
path('', include('example.urls'))
]
example/urls.py
from django.urls import path
from example import views
app_name = 'example'
urlpatterns = [
path('a/', views.GenericListView.as_view(), name='a-url'),
path('b/', views.GenericListView.as_view(), name='b-url')
]
templates/a.html
This is A file
templates/b.html
This is B file
example/views.py
from django.views.generic.list import ListView
from django.urls import reverse
class GenericListView(ListView):
a_template = 'a.html'
b_template = 'b.html'
def get_template_names(self, *args, **kwargs):
# Check if the request path is the path for a-url in example app
if self.request.path == reverse('example:a-url'):
return [self.a_template] # Return a list that contains "a.html" template name
return [self.b_template] # else return "b.html" template name
def get_queryset(self, **kwargs):
# For this example i'm returning [] as queryset for both a/ and b/ routes
if self.request.path == reverse('example:a-url'):
return [] # Return whatever queryset for a/ route
return [] # Return whatever queryset for b/ route
For more informations you can visit ListView: get_template_names() Documentation

It seems to me that having 2 separate ListViews is the right approach in your situation. You have 2 different URLs and 2 different templates, so you have 2 different views. I don't think that it violates DRY principles because the common logic is abstracted by the reusable ListView class.

Related

Not understanding how Python Class works

I am in need of some help understanding how Python and Django work based on some code I'm looking at.
Say my urls.py file has the following
router.register(r'testing', SomeClass)
and then in my views.py file, it is set up like this:
class SomeClass():
database = DatabaseValues.objects.all()
def first_def(self):
# do some filtering and such on db results
return database
def second_def(self):
a = 20
b = 40
return b - a
def third_def(self):
z = 200
y = 400
return y - z
When the SomeClass is called in UI by hitting the http://localhost/testing url, what is returned??
I would recommend making some changes to urls.py I think this method below is easier to understand.
when you run python3 manage.py runserver
you can open 127.0.0.1/example.
the reason you are not understanding is because Django has a lot of boilerplate code. I would recommend reading more into how views work.
every class in views.py should inherit a django class in this example I use TemplateView. your app name is the folder that is created when a new django "app" is added to the project.
from django.urls import path
from .views import exampleView
app_name = "example"
urlpatterns = [
path('/example', exampleView.as_view(), name='example'),
]
in views.py you cannot create arbitrary function names. when a website loads
www.baseurl/example you are making a get request. therefore you must have a get method inside of your class.
template_name refers to an html page that will be rendered...
this template name must point at an html file which is located inside project_root/templates/html_file.html
views.py
from django.views.generic import TemplateView, ListView
class exampleView(TemplateView):
template_name = 'test.html'
def get(self, request):
print("hello")
return render(request, self.template_name, {})
if you wish to have arbitrary functions inside your class cool. Add them below the get function and call them when a user makes a get request.

django-contact-form how to use the form inside any template, without a new url?

I have installed django-contact-form, and the default url to the form is 'contact/'. But, I already have my own contact page, let's call it 'contact_us/', I wish to include the form inside 'contact_us/', using the url and view I already have for 'contact_us/'.
The usual way to do that is by using {% extends 'contact_us' %}, but if I do this, and remove my original 'contact_us/' url, it gives me an ReverseError.
The way I think that would be possible is if sent the ContactFormView (from django-contact-form) as context to 'contact_us/', but I think that's not possible because each view has it's own url.
I want to know a way to be able to put the form easily inside of any template. There's probably a simple way to do that and I don't know.
You can call the ContactFormView from the contact_us by:
1. By overriding the url
urls.py
from contact_form.views import ContactFormView
from django.views.generic import TemplateView
urlpatterns = [
# ... other URL patterns for your site ...
url(r'^contact_us/$',
ContactFormView.as_view(),
name='contact_form'),
url(r'^contact_us/sent/$',
TemplateView.as_view(template_name='contact_form/contact_form_sent.html'),
name='contact_form_sent'),
]
2. If you want to customize this view
In views.py
from contact_form.views import ContactFormView
class CustomContactFormView(ContactFormView):
# Customize any function that you want to
template_name = 'custom_template.html'
urls.py
from views import CustomContactFormView
urlpatterns = [
# ... other URL patterns for your site ...
url(r'^contact_us/$',
CustomContactFormView.as_view(),
name='contact_form'),
]

Django Admin Custom Pages and Features

I'm (new to) working in Django and would like to create two features that do not rely upon models/database tables. The basis of this app is as a web-based wrapper to a Python application.
The features are:
I would like to be able to load a ConfigObj text file into a page and edit it's configuration prior to saving again.
I would like to be able to call command line python/bash scripts and display their output on a page - like exec in PHP.
At the moment I'm working on simple custom admin pages without model as described here:
Django admin, section without "model"?
Would this be the right direction to go in? I'm not sure proxy tables apply as the features I desire have nothing to do with any data.
So far I have looked at is it possible to create a custom admin view without a model behind it and a few other links. At the moment I have:
main/urls.py
url(r'^admin/weectrl', include('weectrl.urls')),
which links with weectrl/urls.py
from weectrl import views
urlpatterns = patterns('',
(r'^admin/weectrl/manage/$', weectrl_manage_view),
(r'^admin/weectrl/config/$', weectrl_config_view),
)
which points to weectrl/views.py
def weectrl_manage_view(request):
r = render_to_response('admin/weectrl/manage.html', context, RequestContext(request))
return HttpResponse(r)
def weectrl_config_view(request):
r = render_to_response('admin/weectrl/config.html', context, RequestContext(request))
return HttpResponse(r)
The current error message is name 'weectrl_manage_view' is not defined
Ok, found something that works.
In the main url.py
url(r'^admin/weectrl/', include('weectrl.urls')),
In app/urls.py
urlpatterns = patterns('',
url(r'^config/$', views.config, name='config'),
url(r'^manage/$', views.manage, name='manage'),
)
and in app/views.py
def config(request):
context = ""
return render(request, 'weectrl/config.html', context)
def manage(request):
context = ""
return render(request, 'weectrl/manage.html', context)
html files are in app/templates/app/...

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.

How to use one app to satisfy multiple URLs in Django

I'm trying to use one app to satisfy multiple url paths. That is to say, I want the url /blog/ and /job/ to use the same app, but different views. There are a number of ways to do this I'm sure, but none of them seem very clean. Here's what I'm doing right now
# /urls.py
urlpatterns = patterns("",
(r"^(blog|job)/", include("myproject.myapp.urls")),
)
# /myapp/urls.py
urlpatterns = patterns("myproject.myapp.views",
(r"^(?P<id>\d+)/edit/$", "myproject.myapp.views.edit"),
(r"^(?P<id>\d+)/delete/$", "myproject.myapp.views.delete"),
(r"^(?P<id>\d+)/update/$", "myproject.myapp.views.update"),
(r"^insert/$", "myproject.myapp.views.insert"),
)
urlpatterns += patterns("",
(r"^(?P<object_id>\d+)/$", "django.views.generic.list_detail.object_detail", info_dict, "NOIDEA-detail"),
(r"^/$", "django.views.generic.list_detail.object_list", info_dict, "NOIDEA-community"),
)
# /myapp/views.py
def edit(request, type, id):
if (type == "blog"):
editBlog(request, id)
else (type == "job")
editJob(request, id)
def editBlog(request, id):
# some code
def editJob(request, id):
# some code
I've ended up breaking all of this into multiple model and view files to make the code cleaner but the above example doesn't account for things like reverse url lookups which breaks all of my template {% url %} calls.
Originally, I had blogs, jobs, events, contests, etc all living in their own apps, but all of their functionality is so similar, that it didn't make sense to leave it that way, so I attempted to combine them... and this happened. You see those "NOIDEA-detail" and "NOIDEA-community" url names on my generic views? Yeah, I don't know what to use there :-(
You can have more than one modules defining URLs. You can have /blog/ URLs in myapp/urls.py and /job/ URLs in myapp/job_urls.py. Or you can have two modules within a urls subpackage.
Alternatively you can manually prefix your url definitions:
urlpatterns = patterns("myproject.myapp.views",
(r"^jobs/(?P<id>\d+)/edit/$", "myproject.myapp.views.edit"),
(r"^jobs/(?P<id>\d+)/delete/$", "myproject.myapp.views.delete"),
(r"^jobs/(?P<id>\d+)/update/$", "myproject.myapp.views.update"),
(r"^jobs/insert/$", "myproject.myapp.views.insert"),
)
urlpatterns += patterns("",
(r"^blog/(?P<object_id>\d+)/$", "django.views.generic.list_detail.object_detail", info_dict, "NOIDEA-detail"),
(r"^blog/$", "django.views.generic.list_detail.object_list", info_dict, "NOIDEA-community"),
)
And then mount them as:
urlpatterns = patterns("",
(r"", include("myapp.urls")),
)
Personally I would go for more RESTful URL definitions though. Such as blog/(?P<post_id>\d+)/edit/$.
Looks pretty good to me. If you want reverse lookups, just have a different reverse name for each url format, even if they end up pointing to the same view.

Categories