URL Generation

34 views
Skip to first unread message

James Schneider

unread,
Jul 26, 2015, 8:07:06 PM7/26/15
to django...@googlegroups.com
Hello all,

I have an issue that I've been trying to work around in a generic fashion (so that I'm not repeating myself in views/templates). Let's say I have three models:

# models
class Organization(models.Model):
    name = models.CharField(max_length=250, null=False, blank=False, unique=True)


class Team(models.Model):
    organization = models.ForeignKey(Organization, null=False)
    name = models.CharField(max_length=250)


class Competition(models.Model):
    organization = models.ForeignKey(Organization, null=False)
    name = models.CharField(max_length=250)
    teams = models.ManyToManyField(Team, related_name='competitions')


And this basic URL structure:

# urls

# organization URL's
url(
    regex=r'organization/',
    view=include(organization_urlpatterns, namespace='organization'),
),

# team URL's
url(
    regex=r'organization/(?P<organization_pk>\d+)/team/',
    view=include('project.teams.urls', namespace='team'),
),

# competition URL's
url(
    regex=r'organization/(?P<organization_pk>\d+)/competition/',
    view=include('project.competitions.urls', namespace='competition'),
),


# competition team listing - project.competitions.urls
url(
    regex=r'^(?P<competition_pk>\d+)/team/',
    view=include('project.teams.urls', namespace='team'),
),


In this (simplified version of my) application, a Team is a member of an Organization. Competitions are created within the Organization, and will have one or more Teams associated with them. Teams can be associated with multiple Competitions, but not with multiple Organizations.

Focusing on Teams specifically, there are two URL's/views that can be used to view a Team. One from the perspective of an Organizatoin (where you can see all of the teams associated with an Organization), and one within the context of a Competition, where you can see a list of Teams filtered specifically for that Competition.

Here's my dilemma. I need to generate various links to get to other parts of the application, but if the user is working within the 'context' of a competition (adding/removing teams, etc.), then I need the links for objects to be relative to the Competition that they are working on. For example, a link to 'list all teams' in the Organization context should list all of the teams within an Organization, but should be limited to the associated teams in a Competition context (using the term context generally, not referring to a template context). 

Normally I would use something like get_absolute_url() on the model, but the model object has no concept of the 'context' of where/how it is being modified, so get_absolute_url() would unconditionally return the URL as if it were being viewed at an Organizational level, meaning that all of the links would take the user out of the context where they were expecting, and force them to navigate back into it.

I have several other models that need to follow a similar URL scheme, so something generic would be appreciated.

I have a sneaking suspicion that utilizing app_name within the URL's could be beneficial, but I can't seem to grasp the concept of how to properly use an app_name with URL's, and have it apply to my situation (I'm already using instance namepaces, which have been working out peachy so far). It'd be nice to just have 'team:create' as the namespace and have Django automagically determine whether or not it should stay within the Comeptition context. The other wrinkle in this is that any operations performed in the Competition context currently require an extra kwarg (competition_pk) to specify what Competition is in use, whereas both URL's are already aware of the Organization (organization_pk). I'm open to reworking the URL structure if someone can point me in the right direction and that is the only hurdle.

What URL resolution strategies would be appropriate in this situation? 

Thank you in advance,

-James

Tim Graham

unread,
Jul 27, 2015, 10:02:05 AM7/27/15
to Django users, jrschn...@gmail.com
I think what you want is something like:


# team URL's
url(
    regex=r'organization/(?P<organization_pk>\d+)/team/',
    view=include('project.teams.urls', namespace='organization-team', app_name='team'),
),

# competition team listing - project.competitions.urls
url(
    regex=r'^(?P<competition_pk>\d+)/team/',
    view=include('project.teams.urls', namespace='competition-team', app_name='team'),
),

Did you follow the example at https://docs.djangoproject.com/en/1.8/topics/http/urls/#id4?

James Schneider

unread,
Jul 27, 2015, 2:28:15 PM7/27/15
to Tim Graham, Django users
> I think what you want is something like:
>
> # team URL's
> url(
>     regex=r'organization/(?P<organization_pk>\d+)/team/',
>     view=include('project.teams.urls', namespace='organization-team',
> app_name='team'),
> ),
>
> # competition team listing - project.competitions.urls
> url(
>     regex=r'^(?P<competition_pk>\d+)/team/',
>     view=include('project.teams.urls', namespace='competition-team',
> app_name='team'),
> ),


I also believe this is correct.
I had circled back around to that page several times in the past and couldn't grasp the concept of how the internals made the determination of which instance namespace to use. Then, given your answer above, I re-read it again and saw this:

"""
Using this setup, the following lookups are possible:

If one of the instances is current - say, if we were rendering the detail page in the instance 'author-polls' - 'polls:index' will resolve to the index page of the 'author-polls' instance; i.e. both of the following will result in "/author-polls/".
"""

*facepalm*

That's exactly the behavior I need. I think this is one of those cases where I zoomed in on an issue a little too far (been working on this for several months on/off for a personal project).

However, I still think I'll need to change my URL structure up a bit. Assuming I implement as stated above, I'll then have two different signatures for the same namespace ({% url 'team:detail' org_pk %} and {% url 'team:detail' org_pk comp_pk %}), which I think was part of the problem as to why I couldn't grasp the application namespace. It also means I would need to determine the signature I need to use ahead of time , which makes this question moot since I can add other logic to generate the correct URL. I have a custom row-level permission system and heavy view/model inheritance in play as well (a majority of my CBV's are literally a single line to specify the permission needed), and I was using that to pull in information needed for permission checks from the URL kwargs before wasting time rendering, but I believe I can pull in the necessary bits from a simplified URL structure with a little bit of extra effort spent inspecting the primary object in question.

Thank you for the enlightenment. I think this is my first question post, but watching threads to/from others has definitely helped immensely on other topics. 

-James
Reply all
Reply to author
Forward
0 new messages