Skip to content
This repository

Dry url issue69 #71

Closed
wants to merge 4 commits into from

2 participants

darbula Daniele Procida
darbula

This pull request replaces pull/issue #69 as that issue seems to have some work ahead and by my mistake it did not have a dedicated named branch. Now I have made a dedicated branch issue69 to be used to fix everything concerning following problem:

Description:

Urls for contacts, news and vacancies were defined in multiple places:

  • urls.py,
  • models.py - in url_path and
  • menus.py - in url_attribute.

This situation prevents changing/translating the default urls (i.e. contacts/ news/ etc). In this commit url patterns in urls.py are given names and then reverse is used to resolve urls where needed i.e. in Entity.get_related_info_page_url or in URLModelMixin.get_absolute_url.

Url patterns are named so that their name can be deduced from url_path and url_attribute when needed.

darbula

Urls for contacts, news and vacancies are defined in multiple places:

  • urls.py,
  • models.py - in url_path and
  • menus.py - in url_attribute.

This situation prevents changing/translating the default urls. In this commit url patterns in urls.py are given names and then reverse is used to resolve urls where needed i.e. in Entity.get_related_info_page_url or in URLModelMixin.get_absolute_url.

Url patterns are named so that their name can be deduced from url_path and url_attribute when needed.

Owner

This is probably a good idea, but I am not sure what some of the implications might be. I'll look into it more closely, but if you also want to discuss it on #arkestra on irc.freenode.net or the email list, please do.

Daniele Procida
Owner

I'd like to do something with some of these ideas, but I will need to discuss it first. One issue is that it is important that it should be easy to provide Entities with connections to other kinds of information through other applications.

For example, our Publications application makes it possible to see an Entity's academic research publications, and I am not sure how that will be affected by these changes.

darbula

There should not be any consequences to external applications but if you can provide some more details about certain parts that could become problematic we can discuss it.

Daniele Procida
Owner

I'm taking a good look at this now. There are some changes in the develop branch since you made this pull request, so I will reconcile those first, and make some a reminder to myself below about things that need tests and/or comments to explain their behaviour.

tests/comments required

  • Person.get_absolute_url() - test for self.active
  • basic tests for news and events, vacancies and studentships views
  • tests for get_absolute_url() methods where not present
Daniele Procida evildmp commented on the diff June 18, 2013
contacts_and_people/urls.py
((5 lines not shown))
4 4
 
5 5
     # person
6  
-    (r"^person/(?P<slug>[-\w]+)/(?P<active_tab>[-\w]*)/?$", "contacts_and_people.views.person"),
3
Daniele Procida Owner
evildmp added a note June 18, 2013

What is the advantage of splitting up a pattern that could catch URLs with or without a tab into two different ones?

darbula
darbula added a note June 18, 2013

If there were only one pattern i.e.

(r"^person/(?P<slug>[-\w]+)/(?P<active_tab>[-\w]*)/?$", "person", {}, "contact_person_tab")

then calling

reverse("contact_person_tab", kwargs={"slug":"foo","active_tab":"bar"})

would return '/person/foo/bar', but calling

reverse("contact_person_tab", kwargs={"slug":"foo"})

would return NoReverseMatch

OTH calling

reverse("contacts_and_people.views.person", kwargs={"slug":"foo"})

would return '/person/foo', so if the view name is used instead of the pattern name optional arguments are resolved correctly but at this moment reverse is called by name and in some cases it resolves the pattern name dynamically.

Daniele Procida Owner
evildmp added a note June 18, 2013

OK, good, I think I understand this now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Daniele Procida evildmp commented on the diff June 18, 2013
news_and_events/urls.py
((13 lines not shown))
10 9
     
11 10
     # named entities' news and events
12  
-    url(r'^news-archive/(?:(?P<slug>[-\w]+)/)?$', views.news_archive, name="news_archive"),
1
Daniele Procida Owner
evildmp added a note June 18, 2013

Is there an advantage here in replacing a single pattern with two - one that can catch slugs and one that doesn't?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Daniele Procida

Should be:

url = reverse(kind,kwargs={"slug":self.slug})

Of course :(

Daniele Procida evildmp commented on the diff June 18, 2013
contacts_and_people/models.py
((5 lines not shown))
415 416
         if self.external_url:
416 417
             return ""
417 418
         elif self == Entity.objects.base_entity():
418  
-            return "/%s/" % kind
  419
+            if kind in kinds:
3
Daniele Procida Owner
evildmp added a note June 18, 2013

I don't think I understand the purpose of this. Since, if kind in kinds is False we will use "/%s/" % kind anyway, and since that will work just the same even if kind in kinds is True, why do we need it?

darbula
darbula added a note June 18, 2013

If kind is not in the list then it probably wont get proper reverse so it has to have fallback "/%s/" % kind. I didn't know if and when you'll pull this code into origin repo and if you define some other kind I still want that part to work without debugging. Looking to it now it would be better to write:

try:
    url = reverse(kind+"_base") 
except NoReverseMatch:
    url = "/%s/" % kind 

If and when choose to use reverse everywhere then it is not needed anymore.

Daniele Procida Owner
evildmp added a note June 18, 2013

I think it will be better to move towards using reverse everywhere.

If I understand correctly, reverse will match all url patterns in the system, so as long as - for example - the Publications application we use has named url patterns that conform to the same scheme it will work with them too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Daniele Procida evildmp commented on the diff July 11, 2013
vacancies_and_studentships/urls.py
... ...
@@ -1,26 +1,25 @@
1 1
 from django.conf.urls.defaults import patterns
2 2
 
3  
-urlpatterns = patterns('',
  3
+urlpatterns = patterns('vacancies_and_studentships.views',
4 4
     
5 5
     # vacancies and studentships 
1
Daniele Procida Owner
evildmp added a note July 11, 2013

These need some more names on the patterns - for example, name="archived-vacancies_base" and so on.

I will also rationalise hyphens and underscores - "archived-vacancies_base" looks messy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Daniele Procida
Owner

Have a look at https://github.com/evildmp/Arkestra/tree/merge-darbula-issue69. This:

  • incorporates your changes
  • rationalises the naming of reverse patterns
  • rationalises and reformats URL patterns
  • includes tests for reverse patterns

I will do some more testing, and if this looks OK it's ready to be merged.

Daniele Procida evildmp referenced this pull request July 24, 2013
Merged

Merge darbula issue69 #106

Daniele Procida
Owner

Merged in #106 - thanks.

Daniele Procida evildmp closed this July 24, 2013
darbula

Great, glad that this has worked its way into upstream :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 4 unique commits by 1 author.

Mar 11, 2013
darbula dry url, reverse 0159fec
Mar 12, 2013
darbula dry url a9376b0
Mar 15, 2013
darbula dry url fix 9a57050
Jun 19, 2013
darbula dry url 1cfa5c7
This page is out of date. Refresh to see the latest.
4  arkestra_utilities/mixins.py
... ...
@@ -1,5 +1,5 @@
1 1
 from django.db import models
2  
-
  2
+from django.core.urlresolvers import reverse
3 3
 from links.models import ExternalLink     
4 4
         
5 5
 
@@ -21,6 +21,8 @@ def __unicode__(self):
21 21
     def get_absolute_url(self):
22 22
         if self.external_url:
23 23
             return self.external_url.url
  24
+        elif self.url_path in ["news","event","vacancy","studentship"]:
  25
+            return reverse(self.url_path,kwargs={"slug":self.slug})
24 26
         else:
25 27
             return "/%s/%s/" % (self.url_path, self.slug)
26 28
 
22  contacts_and_people/models.py
@@ -8,7 +8,7 @@
8 8
 from django.contrib.auth.models import User
9 9
 from django.template.defaultfilters import slugify
10 10
 from django.conf import settings
11  
-
  11
+from django.core.urlresolvers import reverse
12 12
 from cms.models import Page, CMSPlugin
13 13
 from cms.models.fields import PlaceholderField
14 14
 
@@ -98,7 +98,7 @@ def __unicode__(self):
98 98
         return building_identifier
99 99
     
100 100
     def get_absolute_url(self):
101  
-        return "/place/%s/" % self.slug
  101
+        return reverse("contact_place", kwargs={"slug":self.slug}) 
102 102
     
103 103
     def save(self):
104 104
         if not self.slug or self.slug == '':
@@ -317,9 +317,9 @@ def get_absolute_url(self):
317 317
         if self.external_url:
318 318
             return self.external_url.url
319 319
         elif self.get_website:
320  
-            return "/contact/%s/" % self.slug
  320
+            return reverse("contact", kwargs={"slug":self.slug}) 
321 321
         else:
322  
-            return "/contact/"
  322
+            return reverse("contact_base") 
323 323
 
324 324
     @property
325 325
     def _get_real_ancestor(self):
@@ -412,12 +412,20 @@ def get_related_info_page_url(self, kind):
412 412
         
413 413
         If the entity is the base entity, doesn't add the entity slug to the URL
414 414
         """
  415
+        kinds = ["contact","news-and-events","vacancies-and-studentships","forthcoming-events","news-archive","previous-events"] # "publications"
415 416
         if self.external_url:
416 417
             return ""
417 418
         elif self == Entity.objects.base_entity():
418  
-            return "/%s/" % kind
  419
+            if kind in kinds:
  420
+                url = reverse(kind+"_base")
  421
+            else:
  422
+                url = "/%s/" % kind
419 423
         else:
420  
-            return "/%s/%s/" % (kind, self.slug)
  424
+            if kind in kinds:
  425
+                reverse(kind,kwargs={"slug":self.slug})
  426
+            else:
  427
+                url = "/%s/%s/" % (kind, self.slug)
  428
+        return url
421 429
 
422 430
     def get_template(self):
423 431
         """
@@ -595,7 +603,7 @@ def get_absolute_url(self):
595 603
         if self.external_url:
596 604
             return self.external_url.url
597 605
         else:
598  
-            return "/person/%s/" % self.slug
  606
+            return reverse("contact_person", kwargs={"slug":self.slug}) 
599 607
 
600 608
     @property
601 609
     def get_role(self):
2  contacts_and_people/templates/contacts_and_people/entity_contacts_and_people.html
@@ -47,7 +47,7 @@
47 47
     				<h{{ IN_BODY_HEADING_LEVEL }}>All people A-Z by surname</h{{ IN_BODY_HEADING_LEVEL }}>
48 48
     				<ul class= "index">
49 49
     					{% for initial in initials_list %}
50  
-    						<li><a href="/people/{{ entity.slug }}/{{initial|lower|urlencode}}/">{{ initial }}</a></li>
  50
+    						<li><a href="{% url contact_people_letter entity.slug,initial|lower %}">{{ initial }}</a></li>
51 51
     					{% endfor %}
52 52
     				</ul>	
53 53
         		{% endif %}
8  contacts_and_people/templates/includes/people_list_with_index.html
@@ -5,18 +5,18 @@
5 5
 Lists members of an entity - either all people by surname, or surnames beginning {{ letter }}.
6 6
 
7 7
 {% endcomment %}
8  
-{% load entity_tags %}
  8
+{% load i18n entity_tags %}
9 9
 <div class="row columns2">
10 10
    	<div class="column firstcolumn">
11  
-		<h{{ IN_BODY_HEADING_LEVEL }} style="clear:both">{% if letter %}People: surnames beginning {{letter|upper}}{% else %}All people by surname{% endif %}</h{{ IN_BODY_HEADING_LEVEL }}>
  11
+		<h{{ IN_BODY_HEADING_LEVEL }} style="clear:both">{% if letter %}{% trans "People: surnames beginning" %} {{letter|upper}}{% else %}{% trans "All people by surname" %}{% endif %}</h{{ IN_BODY_HEADING_LEVEL }}>
12 12
 		{% people_with_roles letter %}
13 13
 	</div>
14 14
 	<div class="column lastcolumn"> 
15 15
 	{% if initials_list %}
16  
-		<h{{ IN_BODY_HEADING_LEVEL }}>Index of people by surname</h{{ IN_BODY_HEADING_LEVEL }}>
  16
+		<h{{ IN_BODY_HEADING_LEVEL }}>{% trans "Index of people by surname" %}</h{{ IN_BODY_HEADING_LEVEL }}>
17 17
 		<ul class="index">
18 18
 			{% for initial in initials_list %}
19  
-				<li><a href="/people/{{ entity.slug }}/{{initial|lower}}/">{{ initial }}</a></li>
  19
+				<li><a href="{% url contact_people_letter entity.slug initial|lower %}">{{ initial }}</a></li>
20 20
 			{% endfor %}
21 21
 		</ul>
22 22
 	{% endif %}
16  contacts_and_people/urls.py
... ...
@@ -1,20 +1,22 @@
1 1
 from django.conf.urls.defaults import patterns, include, url
2 2
 
3  
-urlpatterns = patterns('',
  3
+urlpatterns = patterns('contacts_and_people.views',
4 4
 
5 5
     # person
6  
-    (r"^person/(?P<slug>[-\w]+)/(?P<active_tab>[-\w]*)/?$", "contacts_and_people.views.person"),
  6
+    (r"^person/(?P<slug>[-\w]+)/?$", "person", {}, "contact_person"),
  7
+    (r"^person/(?P<slug>[-\w]+)/(?P<active_tab>[-\w]*)/?$", "person", {}, "contact_person_tab"),
7 8
     
8 9
     # place
9  
-    (r"^place/(?P<slug>[-\w]+)/(?P<active_tab>[-\w]*)/?$", "contacts_and_people.views.place"),    
  10
+    (r"^place/(?P<slug>[-\w]+)/?$", "place", {}, "contact_place"),    
  11
+    (r"^place/(?P<slug>[-\w]+)/(?P<active_tab>[-\w]*)/?$", "place", {}, "contact_place_tab"),    
10 12
 
11 13
     # lists of people in an entity
12  
-    (r"^people/(?P<slug>[-\w]+)/(?P<letter>\w)/$", "contacts_and_people.views.people"),
13  
-    (r"^people/(?P<slug>[-\w]+)/$", "contacts_and_people.views.people"), 
  14
+    (r"^people/(?P<slug>[-\w]+)/$", "people", {}, "contact_people"), 
  15
+    (r"^people/(?P<slug>[-\w]+)/(?P<letter>\w)/$", "people", {}, "contact_people_letter"),
14 16
     
15 17
     # main contacts & people page
16  
-    (r'^contact/(?P<slug>[-\w]+)/$', "contacts_and_people.views.contacts_and_people"), # non-base entities
17  
-    (r'^contact/$', "contacts_and_people.views.contacts_and_people"), # base entity only
  18
+    (r'^contact/(?P<slug>[-\w]+)/$', "contacts_and_people", {}, "contact"), # non-base entities
  19
+    (r'^contact/$', "contacts_and_people", {}, "contact_base"), # base entity only
18 20
 
19 21
     # news, events, vacancies, studentships
20 22
     (r'^', include('news_and_events.urls')),
19  news_and_events/urls.py
... ...
@@ -1,18 +1,21 @@
1 1
 from django.conf.urls.defaults import *
2  
-from news_and_events import views
3 2
 # from  news_and_events.views import NewsAndEventsViews
4 3
 
5  
-urlpatterns = patterns('',
  4
+urlpatterns = patterns('news_and_events.views',
6 5
     
7 6
     # news and events items
8  
-    url(r"^news/(?P<slug>[-\w]+)/$", views.newsarticle, name="newsarticle"),
9  
-    url(r"^event/(?P<slug>[-\w]+)/$", views.event, name="event"),
  7
+    url(r"^news/(?P<slug>[-\w]+)/$", "newsarticle", {}, "news" ),
  8
+    url(r"^event/(?P<slug>[-\w]+)/$", "event", {}, "event"),
10 9
     
11 10
     # named entities' news and events
12  
-    url(r'^news-archive/(?:(?P<slug>[-\w]+)/)?$', views.news_archive, name="news_archive"),
13  
-    url(r'^previous-events/(?:(?P<slug>[-\w]+)/)?$', views.previous_events, name="previous_events"),
14  
-    url(r'^forthcoming-events/(?:(?P<slug>[-\w]+)/)?$', views.all_forthcoming_events, name="forthcoming_event"),
15  
-    url(r"^news-and-events/(?:(?P<slug>[-\w]+)/)?$", views.news_and_events, name="news_and_events"),
  11
+    url(r'^news-archive/?$', "news_archive", {}, "news-archive_base"),
  12
+    url(r'^news-archive/(?:(?P<slug>[-\w]+)/)?$', "news_archive", {}, "news-archive"),
  13
+    url(r'^previous-events/?$', "previous_events", {}, "previous-events_base"),
  14
+    url(r'^previous-events/(?:(?P<slug>[-\w]+)/)?$', "previous_events", {}, "previous-events"),
  15
+    url(r'^forthcoming-events/?$', "all_forthcoming_events", {}, "forthcoming-events_base"),
  16
+    url(r'^forthcoming-events/(?:(?P<slug>[-\w]+)/)?$', "all_forthcoming_events", {}, "forthcoming-events"),
  17
+    url(r"^news-and-events/?$", "news_and_events", {}, "news-and-events_base"),
  18
+    url(r"^news-and-events/(?:(?P<slug>[-\w]+)/)?$", "news_and_events", {}, "news-and-events"),
16 19
     )
17 20
     #(r"^entity/(?P<slug>[-\w]+)/news/$", "news_and_events.views.news"), # in development
18 21
 
10  news_and_events/views.py
... ...
@@ -1,5 +1,5 @@
1 1
 import datetime
2  
-
  2
+from django.utils.translation import ugettext as _
3 3
 from django.shortcuts import render_to_response, get_object_or_404
4 4
 from django.template import RequestContext
5 5
 from django.http import Http404
@@ -39,17 +39,17 @@ def common_settings(request, slug):
39 39
     return instance, context, entity
40 40
 
41 41
 
42  
-def news_and_events(request, slug):
  42
+def news_and_events(request, slug=None):
43 43
     instance, context, entity = common_settings(request, slug)    
44 44
 
45 45
     instance.type = "main_page"
46 46
 
47 47
     meta = {"description": "Recent news and forthcoming events",}
48  
-    title = unicode(entity) + u" news & events"
  48
+    title = unicode(entity) + _(u" news & events")
49 49
     if MULTIPLE_ENTITY_MODE:
50  
-        pagetitle = unicode(entity) + u" news & events"
  50
+        pagetitle = unicode(entity) + _(u" news & events")
51 51
     else:
52  
-        pagetitle = "News & events"
  52
+        pagetitle = _("News & events")
53 53
     CMSNewsAndEventsPlugin().render(context, instance, None)
54 54
     
55 55
     context.update({
31  vacancies_and_studentships/urls.py
... ...
@@ -1,26 +1,25 @@
1 1
 from django.conf.urls.defaults import patterns
2 2
 
3  
-urlpatterns = patterns('',
  3
+urlpatterns = patterns('vacancies_and_studentships.views',
4 4
     
5 5
     # vacancies and studentships 
6  
-    (r"^vacancy/(?P<slug>[-\w]+)/$", "vacancies_and_studentships.views.vacancy"),
7  
-    (r"^studentship/(?P<slug>[-\w]+)/$", "vacancies_and_studentships.views.studentship"),
  6
+    (r"^vacancy/(?P<slug>[-\w]+)/$", "vacancy", {}, "vacancy"),
  7
+    (r"^studentship/(?P<slug>[-\w]+)/$", "studentship", {}, "studentship"),
8 8
     
9 9
     # named entities' vacancies and studentships
10  
-    (r"^vacancies-and-studentships/(?P<slug>[-\w]+)/$", "vacancies_and_studentships.views.vacancies_and_studentships"),
11  
-
12  
-    (r'^archived-vacancies/(?P<slug>[-\w]+)/$', "vacancies_and_studentships.views.archived_vacancies"),
13  
-    (r'^all-open-vacancies/(?P<slug>[-\w]+)/$', "vacancies_and_studentships.views.all_current_vacancies"),
14  
-
15  
-    (r'^archived-studentships/(?P<slug>[-\w]+)/$', "vacancies_and_studentships.views.archived_studentships"),
16  
-    (r'^all-open-studentships/(?P<slug>[-\w]+)/$', "vacancies_and_studentships.views.all_current_studentships"),
17  
-
  10
+    (r"^vacancies-and-studentships/(?P<slug>[-\w]+)/$", "vacancies_and_studentships", {}, "vacancies-and-studentships"),
18 11
     # base entity's vacancies and studentships
19  
-    (r'^vacancies-and-studentships/$', "vacancies_and_studentships.views.vacancies_and_studentships"),
  12
+    (r'^vacancies-and-studentships/$', "vacancies_and_studentships", {}, "vacancies-and-studentships_base"),
  13
+
  14
+    (r'^archived-vacancies/(?P<slug>[-\w]+)/$', "archived_vacancies"),
  15
+    (r'^all-open-vacancies/(?P<slug>[-\w]+)/$', "all_current_vacancies"),
20 16
     
21  
-    (r'^archived-vacancies/$', "vacancies_and_studentships.views.archived_vacancies"),
22  
-    (r'^all-open-vacancies/$', "vacancies_and_studentships.views.all_current_vacancies"),
  17
+    (r'^archived-vacancies/$', "archived_vacancies"),
  18
+    (r'^all-open-vacancies/$', "all_current_vacancies"),
  19
+
  20
+    (r'^archived-studentships/(?P<slug>[-\w]+)/$', "archived_studentships"),
  21
+    (r'^all-open-studentships/(?P<slug>[-\w]+)/$', "all_current_studentships"),
23 22
 
24  
-    (r'^archived-studentships/$', "vacancies_and_studentships.views.archived_studentships"),
25  
-    (r'^all-open-studentships/$', "vacancies_and_studentships.views.all_current_studentships"),
  23
+    (r'^archived-studentships/$', "archived_studentships"),
  24
+    (r'^all-open-studentships/$', "all_current_studentships"),
26 25
 )
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.