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.
Related
I am doing a search on the page with the ability to filter. It is necessary to pass the selected fields to form the correct queryset. What is the best way to do this? I am creating str variable in urls. But what if you need to pass 10 or more filter conditions? how to organize dynamically passed variables?
urls
from django.urls import path
from .views import *
urlpatterns = [
path('', OrdersHomeView.as_view(), name='orders_home'),
path('filter/<str:tag>', OrdersFilterView.as_view(), name='orders_filter'),
]
I understand what to do through ?var=&var2=, as in php, but I can't figure out how? it is possible to just process the string str, but maybe there is some django magic?
Make the filter view to work with URL GET params:
page = request.GET.get('page', 0)
page_size = request.GET.get('page_size', 100)
Then construct your URLs to send the filters filter/tag/?page=1&page_size=20
So I have two models in the same app that have pretty much identical url structures:
urlpatterns = patterns('',
#....
url(r'^prizes/', include(patterns('prizes.views',
url(r'^$', 'PrizeStore_Index', name="prizestore"),
url(r'^(?P<slug>[\w-]+)/$', PrizeCompanyDetailView.as_view(), name="prizecompany"),
url(r'^(?P<slug>[\w-]+)/$', 'PrizeType_Index', name="prizetype"),
url(r'^(?P<company>[\w-]+)/(?P<slug>[\w-]+)/$', 'PrizeItem_Index', name="prizepage"),
))),
# Old Redirects
)
The problems here being Reviews and PrizeType. I want my urls structured so that a user looking for prizes under a certain category goes to /prizes/prizetype. But if they want to see prizes under a certain company, then they'd go to /prizes/companyslug/. However, these two urls will naturally conflict. I can always just change the url structure, though I'd rather not. I just want to know if there are any ways around this that don't involve changing the url structure.
I would suggest writing a helper view function, which checks whether the inputted url corresponds to a company or a category, and then redirecting the request to the appropriate page.
url(r'^prizes/', include(patterns('prizes.views',
url(r'^$', 'PrizeStore_Index', name="prizestore"),
url(r'^(?P<slug>[\w-]+)/$', prizehelper, name="prizehelper),
where, you can check within prizehelper, if it is a company or a category and move on accordingly.
Another approach could be, to change your url structure, and reflect which type of url it is
url(r'^prizes/', include(patterns('prizes.views',
url(r'^$', 'PrizeStore_Index', name="prizestore"),
url(r'^company/(?P<slug>[\w-]+)/$', PrizeCompanyDetailView.as_view(), name="prizecompany"),
url(r'^category/(?P<slug>[\w-]+)/$', 'PrizeType_Index', name="prizetype"),
Have a single urlconf entry that goes to a view which figures out which type is being examined and then dispatches to the appropriate view for that type.
i have standard django 1.4 url patterns:
urlpatterns = patterns('',
url('^',include('events.urls')),
url(r'^$', home, {'template_name':'index.html','mod':None}, name='home'),
url(r'^contact$',contact, {'template_name':'index.html',
'mod':'contacto'},name='contact'),
url('^task/(?P<task_id>[\w+-]+)',celery_tasks,name='tasks'),
)
I want to build my sitemap.xml leaving out some urls, for example that /task url should not appear(it makes no sense for the web spiders).
My strategy is passing all the url patterns to my Sitemap class, like this
from sitemaps import EventsSitemap, StaticSitemap
sitemaps = {
'Events': CandidateSiteMap,
'static': StaticSitemap(urlpatterns),
}
As you can see i´m passing the patterns to the class, so i can later filter the urls like this
class StaticSitemap(Sitemap):
def __init__(self, patterns):
self.patterns = patterns
self._items = {}
self._initialize()
def _initialize(self):
do_not_show = ['tasks']
for p in self.patterns:
# no dynamic urls in this class (we handle those separately)
if not p.regex.groups:
if getattr(p,'name',False) and p.name not in do_not_show:
self._items[p.name] = self._get_modification_date(p)
So i keep this list of do_not_show url names and thats how i filter out urls, so far so good, the problem is with included urls such as:
url('^',include('events.urls')),
I can't just iterate on self.patterns and get the included urls, i have to expand them first, thats my question, how can i do that?
How can i get a flat list of urls as if there were no included ones, all were on a single urls module.
Any recommendations to filter out urls in the sitemaps.xml would be most appreciated.
Ok i have to answer my own question because i solved it, what i did was a little function to expand the patterns like this
def expand_patterns(patterns):
new_patterns = []
def recursive_expand(patterns):
for p in patterns:
if getattr(p,'url_patterns',False):
recursive_expand(p.url_patterns)
else:
new_patterns.append(p)
recursive_expand(patterns)
return new_patterns
This will flatten out the urlpatterns into a single list.
So now i can use self.patterns to filter out anything in my Sitemap class :)
I have an app which serves two purposes - displays members and centres of my company. They both work exactly the same, save a different variable when filtering my model. Problem is I can't get the current url onto the template to use in my custom breadcrumbs.
I have this urlpattern in my main urls.py:
# --- urls.py ----
url(r'^find-member/', include('company.directory.urls'), \
{'which_app': 'members'}, name='find_member'),
url(r'^find-centre/', include('company.directory.urls'), \
{'which_app': 'training'}, name='find_centre'),
of which links to my app urls.py:
# ---- company/urls.py ----
from django.conf.urls.defaults import *
urlpatterns = patterns('company.directory.views',
url(r'^$', 'index'),
url(r'^(?P<slug>\w+)/$', 'index'),
)
on my template I wish to create a link to the first urlpatten for use with my custom breadcrumbs
<a href='/find-member/'>members</a>
or
<a href='/find-centre/'>Centre</a>
based upon which url I'm using the app with.
my view looks like this:
# ---- company/view.py ----
def index(request, which_app=None, slug=None):
#r = reverse('' ,kwargs={'which_app'=training )
s = "%s %s" % (which_app, slug)
return render_to_response('directory/index.html', locals())
I would like to find the url based upon the which_app variable passed into the def.
I can't seem to use resolve() or reverse(). I'm probably doing it wrong. I haven't really got a template to show right now.
Does anybody have any suggestions? I'd love some advice.
Thanks in advance.
You don't need to use a function. Your view is passed the request object, which has an attribute path which is the path that was called. See the request docs.
I have a pretty standard django app, and am wondering how to set the url routing so that I don't have to explicitly map each url to a view.
For example, let's say that I have the following views: Project, Links, Profile, Contact. I'd rather not have my urlpatterns look like this:
(r'^Project/$', 'mysite.app.views.project'),
(r'^Links/$', 'mysite.app.views.links'),
(r'^Profile/$', 'mysite.app.views.profile'),
(r'^Contact/$', 'mysite.app.views.contact'),
And so on. In Pylons, it would be as simple as:
map.connect(':controller/:action/:id')
And it would automatically grab the right controller and function. Is there something similar in Django?
mods = ('Project','Links','Profile','Contact')
urlpatterns = patterns('',
*(('^%s/$'%n, 'mysite.app.views.%s'%n.lower()) for n in mods)
)
Unless you have a really huge number of views, writing them down explicitly is not too bad, from a style perspective.
You can shorten your example, though, by using the prefix argument of the patterns function:
urlpatterns = patterns('mysite.app.views',
(r'^Project/$', 'project'),
(r'^Links/$', 'links'),
(r'^Profile/$', 'profile'),
(r'^Contact/$', 'contact'),
)
You might be able to use a special view function along these lines:
def router(request, function, module):
m =__import__(module, globals(), locals(), [function.lower()])
try:
return m.__dict__[function.lower()](request)
except KeyError:
raise Http404()
and then a urlconf like this:
(r'^(?P<function>.+)/$', router, {"module": 'mysite.app.views'}),
This code is untested but the general idea should work, even though you should remember:
Explicit is better than implicit.