URL dispatcher API

538 views
Skip to first unread message

Marten Kenbeek

unread,
May 4, 2015, 3:45:48 PM5/4/15
to django-d...@googlegroups.com
Hi all,

I'd like to discuss the API I'm proposing for the new url dispatcher I'm working on. I'll try to explain the API and some of the rationale behind it.

There is a working proof-of-concept at https://github.com/knbk/django/tree/url_dispatcher. Currently, all the names are chosen as not to conflict with the old implementation. A short description can be found at https://gist.github.com/knbk/96999abaab4ad4e5f8f9, which also contains a link to an example url configuration. 

My main goal was to create a simple, extensible API. In the old API, about 90% of the work was done in the `resolve()`, `_reverse_with_prefix()` and `populate()` of the RegexURLResolver. This made for a tightly coupled design that was almost impossible to extend.

My starting point was the RegexURLResolver and RegexURLPattern. Both have a regex constraint that can match the current path and extract arguments. The former can then pass the remainder of the path to its list of resolvers and patterns; the latter can return a ResolverMatch containing the callback specified by that pattern. I've kept this distinction, with the `Resolver` and `View` classes. The change of name from `Pattern`  to `View` is because the `View` object has a bit more logic that determines how the view is called. It is a thin, callable wrapper that can optionally decorate the actual view function with a set of decorators passed down from parent resolvers, and when overwritten, can do some more processing before or after the view function is called. 

The hard-coded dependence on a regex pattern has been abstracted to a Constraint object. Each Resolver and View has a (set of) Constraint object(s), that can match the current url and extract arguments. A RegexPattern that simply mimics the old behaviour will be available, but other implementations, such as a Constraint that matches the request's host or method, are easily provided. A Constraint can also reverse a set of arguments to a partial url. That means that the full set of constraints used to match an url to a view, together with a suitable set of arguments, can be reversed to the url itself.

The main strength of a Constraint is that it can contain very specific logic about its arguments. For example, a Constraint may know that it resolves to a Model's primary key. If it then receives a Model instance of that particular type, it will know how to reverse that model instance to a valid string-based partial url, so that it can later be resolved to match the same object. It could also e.g. infer the regex pattern from the field's type. 

There's one final piece to the puzzle: the URL object. This is the state of the url in the process of resolving or reversing an url. It's a two-way street: when resolving, it starts out as a full path, and the Constraints chip away at the path, while the set of constraints and extracted argument grows. When reversing, it starts out as a set of constraints and arguments, and reconstructs the partial urls from those constraints and arguments until a full url path is reconstructed. It shifts some of the logic from the Resolver to the URL, so that it is easier to extend the Resolver. It is also a simple container that allows any Constraint access to the full request. Last but not least, it allows to dynamically build an url against the current request. This is useful if e.g. a constraint matches a different subdomain than the current request, so that a link automatically points to the right domain. 

I'm looking forwards to your feedback.

Thanks,
Marten

Carl Meyer

unread,
May 4, 2015, 5:05:02 PM5/4/15
to django-d...@googlegroups.com
Hi Marten,

On 05/04/2015 01:45 PM, Marten Kenbeek wrote:
> I'd like to discuss the API I'm proposing for the new url dispatcher I'm
> working on. I'll try to explain the API and some of the rationale behind it.

Thanks for seeking comment early, and providing working PoC code, prose
description, and API example!

> There is a working proof-of-concept
> at https://github.com/knbk/django/tree/url_dispatcher. Currently, all
> the names are chosen as not to conflict with the old implementation. A
> short description can be found
> at https://gist.github.com/knbk/96999abaab4ad4e5f8f9, which also
> contains a link to an example url configuration.
>
> My main goal was to create a simple, extensible API. In the old API,
> about 90% of the work was done in the `resolve()`,
> `_reverse_with_prefix()` and `populate()` of the RegexURLResolver. This
> made for a tightly coupled design that was almost impossible to extend.
>
> My starting point was the RegexURLResolver and RegexURLPattern. Both
> have a regex constraint that can match the current path and extract
> arguments. The former can then pass the remainder of the path to its
> list of resolvers and patterns; the latter can return a ResolverMatch
> containing the callback specified by that pattern. I've kept this
> distinction, with the `Resolver` and `View` classes. The change of name
> from `Pattern` to `View` is because the `View` object has a bit more
> logic that determines how the view is called. It is a thin, callable
> wrapper that can optionally decorate the actual view function with a set
> of decorators passed down from parent resolvers, and when overwritten,
> can do some more processing before or after the view function is called.

This is a minor point, but I don't believe that the name `View` works
for this class; it's too ambiguous when we already have a `View` class
at the root of the class-based-views hierarchy. This class is not a
view: it wraps one or calls one, but it is not itself the view.

I'm also curious to learn more about this "set of decorators" that can
be applied to a view by the url resolver - that feature doesn't seem to
be documented in the linked gist or in the API example.

> The hard-coded dependence on a regex pattern has been abstracted to a
> Constraint object. Each Resolver and View has a (set of) Constraint
> object(s), that can match the current url and extract arguments. A
> RegexPattern that simply mimics the old behaviour will be available, but
> other implementations, such as a Constraint that matches the request's
> host or method, are easily provided. A Constraint can also reverse a set
> of arguments to a partial url. That means that the full set of
> constraints used to match an url to a view, together with a suitable set
> of arguments, can be reversed to the url itself.

I like the general idea of the Constraint object! It reminds me of
Pyramid's view predicates system, which I think are a good model that it
may be worth spending some time reviewing for inspiration:
http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/viewconfig.html

> The main strength of a Constraint is that it can contain very specific
> logic about its arguments. For example, a Constraint may know that it
> resolves to a Model's primary key. If it then receives a Model instance
> of that particular type, it will know how to reverse that model instance
> to a valid string-based partial url, so that it can later be resolved to
> match the same object. It could also e.g. infer the regex pattern from
> the field's type.

I am not at all sure that it is a good idea to mix layers in this
suggested way, or what specific use case it improves. If the argument
that a constraint matches is an integer, why is it (in practice) useful
for the constraint to know that this integer is supposed to be the ID of
some particular model class? Why is it good for that constraint, when
reversing, to be able to take a model instance instead of an ID? To me
this sounds like the sort of implicit type coercion that makes APIs
harder to use and understand, not easier.

> There's one final piece to the puzzle: the URL object. This is the state
> of the url in the process of resolving or reversing an url. It's a
> two-way street: when resolving, it starts out as a full path, and the
> Constraints chip away at the path, while the set of constraints and
> extracted argument grows. When reversing, it starts out as a set of
> constraints and arguments, and reconstructs the partial urls from those
> constraints and arguments until a full url path is reconstructed. It
> shifts some of the logic from the Resolver to the URL, so that it is
> easier to extend the Resolver. It is also a simple container that allows
> any Constraint access to the full request. Last but not least, it allows
> to dynamically build an url against the current request. This is useful
> if e.g. a constraint matches a different subdomain than the current
> request, so that a link automatically points to the right domain.

In reviewing the code samples in the linked gist, the part that I found
most difficult to understand was the URL object.

In part I think this is because it is mis-named (it is not really just a
url, it's a full request).

It's also because of the mutable nature of the URL object; especially
the fact that it's not the URL object itself, but the Constraint
objects, which are responsible for mutating the URL as it passes through
them. It also seems that the concept of "stripping down" and "building
up" a mutable URL object is highly tied to the URL path specifically.
It's not at all clear how it would apply to other possible types of
Constraints, such as those based on hostname or method: is a
method-based Constraint supposed to somehow "strip" the method from the
URL object?

I suspect that there are better design options here. In general,
immutable objects are easier to reason about and work with than mutable
ones, and my intuition says that a URL resolving system with the
properties you've described should be possible to implement in terms of
immutable objects.

The mutability seems to mostly serve the specific use case of nested
path-based constraints, where the inner ones don't have to repeat the
initial part of the path from the outer ones. But I think this pattern
should be equally possible to implement by having the path prefix
information passed down to nested constraints at the time when the graph
is constructed, so that the fully-constructed Constraint knows about the
full path it is supposed to match, and actual matching doesn't require
passing a mutable URL through the graph.

> I'm looking forwards to your feedback.

Thanks again for seeking out feedback! I hope this feedback was useful;
I'd be happy to elaborate on anything that was unclear.

Carl

signature.asc

Aymeric Augustin

unread,
May 17, 2015, 8:13:27 AM5/17/15
to django-d...@googlegroups.com
Hi Marten,

I had a look at your proposal today. You've done good work there.

My comments revolve around making the API obvious, simplifying it until
someone who discovers it understands immediately what the moving pieces are,
what they do, and how they relate to one another.

Here are my two main reactions.


1) The interplay between URL and Constraint is unclear.

In particular I'm not sure which one is designed to be customized, perhaps by
subclassing. To what extent are constraints expected to poke into the URL's
internals?

The documentation shows that URL has methods that accept Constraint in
argument and Constraint has methods that accept URL in argument. Often such
dependency loops indicate that responsibilities should be split differently
between the two classes.

I also share Carl's concerns with regards to URL being mutable.

I don't have a ready-made solution to offer but two suggestions:

a. Try to organize classes in a tree where parent classes use their children's
API but children don't known anything about their parents.

b. Try to clarify further the responsibilities of each class and make sure
they don't know more than they need to achieve this purpose.

For example, having Constraint.match() accept a string in argument -- the
current URL path -- instead of an URL object would prevent Constraint from
depending on URL's API.


2) The Resolver / View API can be simplified.

Is there a fundamental reason to have two different classes here? If so, is
the split in responsibilities optimal?

As far as I can tell, there's some overlap between the two classes, especially
in `resolve()`, but:

- Resolver has additional code for resolving further
- View has additional code for calling a view

My gut feeling is that View should be subsumed into Resolver.


Finally, if you haven't already, you should read about Simon Willison's theory
of "Turtles all the way down":

https://web.archive.org/web/20121013085920/http://simonwillison.net/2009/May/19/djng/

The general idea is that at any point in the Django stack (down to the view
callable) you have stuff that sees an incoming request and will eventually
return a response. I don't think it's directly relevant to your work but it
can provide some guiding priciples.


I hope this helps!

--
Aymeric.
> --
> You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
> To post to this group, send email to django-d...@googlegroups.com.
> Visit this group at http://groups.google.com/group/django-developers.
> To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/5547DEEE.5010000%40oddbird.net.
> For more options, visit https://groups.google.com/d/optout.

Anssi Kääriäinen

unread,
May 17, 2015, 8:35:33 AM5/17/15
to django-d...@googlegroups.com
One important thing to keep in mind is reverse() performance.

While it isn't important that the prototype is fast, making sure the API doesn't limit performance for the most important operations must be checked.

At least my experience is that URL resolving performance isn't that important, but having fast reverse() is really important. The reason is that single request typically has just one resolve operation, and thus the amount of time used for resolving tends to end up in the noise. But large list/table views can have up to thousands of reverse() operations, when there are multiple urls per row.

I believe we can have clean, fast and extensible URL resolving system, so I'm not too worried about this. Still, lets make sure performance won't be a problem.

 - Anssi
--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.
Visit this group at http://groups.google.com/group/django-developers.

Tino de Bruijn

unread,
May 17, 2015, 10:27:32 AM5/17/15
to django-d...@googlegroups.com
Hi Marten,

I am a little less acquainted with the internals of resolving and reversing than the people above, and I must say that I have a hard time understanding your new syntax when looking at the example gist. That might also have to do with the indentation style. Would the (blog_detail, blog_index) -> blog_resolver -> patterns be the replacement of the urlpatterns below? Because I think the latter is a lot more readable. 

Do you have an example of something that is easy to do with this API that is hard or impossible with the current API?

Thanks,


Tino

Marten Kenbeek

unread,
May 23, 2015, 8:13:31 PM5/23/15
to django-d...@googlegroups.com
Hi all,

Thanks for the feedback. It's good to know I'm on the right track.

I've pushed another commit that addresses most of the concerns raised here. I've updated the example gist as well. 

I'm also curious to learn more about this "set of decorators" that can 
be applied to a view by the url resolver - that feature doesn't seem to 
be documented in the linked gist or in the API example. 

The idea is that sometimes, sets of views require a certain decorator - i.e. the whole admin uses the staff_member_required decorator (and some more stuff). This feature allows you to specify a list of decorators to apply to a whole section of your site, and prevents a lot of code duplication and the risk of missing a decorator somewhere (for example, if you add additional views to the admin, you'll have to decorate them yourself). 

I am not at all sure that it is a good idea to mix layers in this 
suggested way, or what specific use case it improves. If the argument 
that a constraint matches is an integer, why is it (in practice) useful 
for the constraint to know that this integer is supposed to be the ID of 
some particular model class? Why is it good for that constraint, when 
reversing, to be able to take a model instance instead of an ID? To me 
this sounds like the sort of implicit type coercion that makes APIs 
harder to use and understand, not easier. 

The constraints should be very explicit about what they accept. The model_or_pk pattern is used all over Django, so I don't think it's that much of a problem. I see two main advantages: you can easily change the field in the url (e.g. from id to slug/uuid), and the regex pattern can be inferred from the field. The latter certainly is more friendly to beginners. But well, maybe it isn't my best idea ever. It doesn't have to be in core, it's easy enough to create in a third-party app if people want it.

1) The interplay between URL and Constraint is unclear. 

I moved the constraints out of the URL class, so that the Constraint knows about the URL. The URL is not strictly immutable, but I think that's difficult to avoid. Now, `Resolver.match()` is a more-or-less atomic operation that clones the old url, manipulates the clone through `Constraint.match()` and returns it. After that, the URL shouldn't change. When reversing, the URL is created from a set of constraints in one go. 

The URL class is something I'm still working on. I particularly like the option to build an url relative to the current request. That should gracefully handle subdomains, and it can easily be extended to handle schemes etc. It might not be needed in resolve(), though. I would like the request object available, but that could be passed as a separate argument. I don't think the pattern of cutting of the matching part should really be extended to the host, so it would only need the path and request parameters. 

2) The Resolver / View API can be simplified. 

I was afraid that Resolver.resolve() would become too complicated, but I've managed to keep it simple. I've brought back the ResolverMatch class (which I would need for backwards compatibility anyway), and the decorator functionality has been moved over there. The resolving functionality has been moved to the Resolver class. This does feel quite a bit cleaner :)

One important thing to keep in mind is reverse() performance.

My (very limited) tests leave me optimistic. With some optimized constraints, reversing could be a lot faster than the current implementation, I believe.

I am a little less acquainted with the internals of resolving and reversing than the people above, and I must say that I have a hard time understanding your new syntax when looking at the example gist. That might also have to do with the indentation style. Would the (blog_detail, blog_index) -> blog_resolver -> patterns be the replacement of the urlpatterns below? Because I think the latter is a lot more readable. 

The example configuration is just to have a working example at hand. The final patch will have url() and include() functions, just like the current implementation. In reality you would use the urlpatterns at the bottom, not the patterns at the top. You do have a point, I've tried to clean up the example to be a bit more readable, and to work with the updated branch.

Do you have an example of something that is easy to do with this API that is hard or impossible with the current API?

Domain-based resolving, for one. Another, non-obvious advantage is that a Resolver subclass can dynamically resolve or reverse patterns. A lot of apps (think flatpages, a CMS, or the sitemaps app) have a semi-static set of urls. The current approaches are limited to a catch-all pattern that further resolves in the view, or a static url for each option. The first approach has the obvious disadvantage that it can only ever be used once in a single urlconf, and the view has to solve problems that the url dispatcher should handle. With the second approach the old url dispatcher makes it virtually impossible to make runtime changes. I'm sure that's not all ;)

I will probably create a separate thread to discuss the mess that is url namespaces. 

Marten

Op zondag 17 mei 2015 16:27:32 UTC+2 schreef Tino de Bruijn:
 - Anssi
To unsubscribe from this group and stop receiving emails from it, send an email to django-developers+unsubscribe@googlegroups.com.
To post to this group, send email to django-developers@googlegroups.com.

Marten Kenbeek

unread,
Jun 28, 2015, 8:35:43 AM6/28/15
to django-d...@googlegroups.com
Hey,

I've been working on (re)building the new dispatcher API from the ground up at https://github.com/knbk/django/tree/dispatcher_api
As of this week it is passing the complete test suite, and I've replaced all occurrences of the old dispatcher with the new one. It's 
not 100% ready but it's getting closer. 

The API hasn't changed too much since my last post. After several iterations of the URL class, I went back to simply passing the remaining 
path, with the request as a second parameter. The URL class is now solely used in reverse() to reconstruct urls. After the View class has been 
merged in Resolver, I've now split Resolver into Resolver and ResolverEndpoint, with common functionality in BaseResolver. App names are 
now resolved to namespaces before calling resolver.search(), as the former method of resolving them on the fly posed some problems. 

The biggest issue still at hand is that `RegexPattern.construct()` can't always reliably determine which `normalized_pattern` to use if  there is 
more than one option. Using `reversed(self.normalized_patterns)` and trying all options from most specific to least specific might be enough 
in practice, but it can also be a cause for hard-to-debug problems. I haven't given it much attention yet, but I'm looking for an efficient way to 
solve this while maintaining a simple API for `construct()`. 

As always, feedback is welcome.

Marten

Op zondag 24 mei 2015 02:13:31 UTC+2 schreef Marten Kenbeek:

James Addison

unread,
Jul 9, 2015, 7:19:11 AM7/9/15
to django-d...@googlegroups.com
Marten,

Using your dispatcher_api branch, I found a few issues - I believe this is an acceptable place to post them. My apologies if this is not the case.

My use case is this: Using a single Django codebase, I plan to have www.example.com and my.example.com. 'my' will be https, while 'www' will be http. 'my' will be for logged in actions (including signup/logging in), and 'www' will be largely anonymous usage and cached using various mechanisms. I've figured out how to do scheme and host based constraints easily enough, thanks to a code sample you provided to me.  This is what I've developed it into, and it works pretty well (once I got around the Major issue listed below):

from django.conf.urls import url, include
from django.core.urls import Constraint, Resolver404


class ConstraintBase(Constraint):
    """
    This exists purely as a way to ensure MRO mixin inheritance will work
    """
    def match(self, path, request=None):
        return path, (), {}

    def construct(self, url, *args, **kwargs):
        return url, args, kwargs


class SchemeConstraintMixin(object):
    scheme = ''

    def match(self, path, request=None):
        if request and request.scheme == self.scheme:
            return super(SchemeConstraintMixin, self).match(path, request)
        raise Resolver404()

    def construct(self, url, *args, **kwargs):
        url.scheme = self.scheme
        return super(SchemeConstraintMixin, self).construct(url, *args, **kwargs)


class HostConstraintMixin(object):
    host = ''

    def match(self, path, request=None):
        if request and request.get_host() == self.host:
            return super(HostConstraintMixin, self).match(path, request)
        raise Resolver404()

    def construct(self, url, *args, **kwargs):
        url.host = self.host
        return super(HostConstraintMixin, self).construct(url, *args, **kwargs)


class SchemeHostConstraint(SchemeConstraintMixin, HostConstraintMixin, ConstraintBase):
    def __init__(self, scheme, host):
        self.scheme = scheme
        self.host = host


www_constraint = SchemeHostConstraint('http', 'localhost:8000')
my_constraint = SchemeHostConstraint('https', 'my.example.com')

urlpatterns = [
    url(www_constraint, include([
        url(r'^$', 'testviews.views.testview', {'template': 'testview1.html'}, 'testview1'),
        url(r'^test2/$', 'testviews.views.testview', {'template': 'testview2.html'}, 'testview2')
    ])),
    url(my_constraint, include([
        url(r'^test3/$', 'testviews.views.testview', {'template': 'testview3.html'}, 'testview3'),
        url(r'^test4/$', 'testviews.views.testview', {'template': 'testview3.html'}, 'testview4')
    ]))
]

The view simply renders a template. The templates simply display the `{% url %}` output of the available url patterns mentioned above. With that preamble done, I'll mention my findings below:

Major bug: the `request` object needs to be passed into `resolve()` here: https://github.com/knbk/django/blob/4a9d2a05bb76c9ad996921b9efadd8dad877540e/django/core/handlers/base.py#L134 - otherwise host and scheme constraints cannot work. I believe there are other instances of `resolve()` not getting `request`, but mostly in tests. Is there a way for `request` to be a required parameter instead of defaulting to `None`?

Minor bug: Given two subdomains, my.example.com and localhost:8000, going to a url using the 'localhost:8000' subdomain that only exists on the 'my' subdomain (ie. http://my.example.com/test3/ exists, but you try to go to http://localhost:8000/test3/), the debug mode 'patterns tried list' is a series of blank lines. See image below:



​Nice to have: When attempting to use multiple constraints (ie. list or tuple of constraints), using `RegexPattern` seems to be required when doing pattern matching - otherwise it messes up while calling `construct`. First glance says this is by design? I think it would be nice to still be able to use the old r'<regex here>' (without wrapping in `RegexPattern`) syntax as well. Not critical, as the multi-constraints is NOT breaking behaviour, just new.

Nice to have: I realise this isn't likely to happen at all, but it would be nice if when `reverse()` and `{% url %}` are called, it would be good to be able to automatically drop the scheme and host when reconstituting an absolute URL if the scheme and host of the current request match.  However, I'm pretty sure that this is not possible, given the various scenarios in which these methods can be called. Obviously, this is not required, as the resulting URL (with scheme/host or without when matching) will still work regardless!

I hope this was clear. If there is a way I can be of more assistance, please let me know!  Nice work, by the way. I'm stoked to have this in 1.9.

James

Tim Graham

unread,
Jul 10, 2015, 9:21:36 AM7/10/15
to django-d...@googlegroups.com
Marten, did you consider putting the new API in `django.urls` instead of `django.core.urls`? I don't need there's a need to namespace it under "core", but others might be able to confirm the philosophy behind this.

Marten Kenbeek

unread,
Jul 10, 2015, 4:55:22 PM7/10/15
to django-d...@googlegroups.com
Hi James,

Thanks for taking a look at this, I really appreciate it. 

Major bug: the `request` object needs to be passed into `resolve()` here: https://github.com/knbk/django/blob/4a9d2a05bb76c9ad996921b9efadd8dad877540e/django/core/handlers/base.py#L134 - otherwise host and scheme constraints cannot work. I believe there are other instances of `resolve()` not getting `request`, but mostly in tests. Is there a way for `request` to be a required parameter instead of defaulting to `None`?

Damn... I'll fix this asap. I haven't implemented any request-based constraints yet, which allowed this to slip through without any test failures. I'm afraid I can't just make `request` a required parameter, as it needs to maintain backwards compatibility. With that said, the current function signature of `resolve()` is just... awkward. One option is to change it to `resolve(request_or_path, urlconf=None)`, and get the path_info from the request if a request is supplied. `resolve()` might still be called in a context where there is not request available, so I think we need to maintain the ability to resolve just the path. 
 
Minor bug: Given two subdomains, my.example.com and localhost:8000, going to a url using the 'localhost:8000' subdomain that only exists on the 'my' subdomain (ie. http://my.example.com/test3/ exists, but you try to go to http://localhost:8000/test3/), the debug mode 'patterns tried list' is a series of blank lines. See image below:

I would've expected at least the regexes here. I'll look into this. 

​Nice to have: When attempting to use multiple constraints (ie. list or tuple of constraints), using `RegexPattern` seems to be required when doing pattern matching - otherwise it messes up while calling `construct`. First glance says this is by design? I think it would be nice to still be able to use the old r'<regex here>' (without wrapping in `RegexPattern`) syntax as well. Not critical, as the multi-constraints is NOT breaking behaviour, just new.

Yes, this is more or less by design. While in the case of a single constraint it's nice and concise. Once you use a list of constraints you'll have to start counting brackets to see if that string is a RegexPattern or a parameter to another constraint, or you'll put each constraint on a new line and it doesn't matter as much imo. It isn't set in stone, so if you have any compelling arguments to change this, let me know. 
 
Nice to have: I realise this isn't likely to happen at all, but it would be nice if when `reverse()` and `{% url %}` are called, it would be good to be able to automatically drop the scheme and host when reconstituting an absolute URL if the scheme and host of the current request match.  However, I'm pretty sure that this is not possible, given the various scenarios in which these methods can be called. Obviously, this is not required, as the resulting URL (with scheme/host or without when matching) will still work regardless!

I'll probably implement something like this before it is merged. I've been struggling to implement the `URL` class in a way that provided such methods in a way that fully conformed RFC 3986, but it was taking up too much of my time and I dropped it for now. I'm not sure I'll get it to conform to RFC 3986, but I'll surely write some basic implementation to output urls relative to the current host and scheme. Of course it won't cover 100% of the cases as the "current" host and scheme are not always available, but in the basic cases it should be doable. 

Op vrijdag 10 juli 2015 15:21:36 UTC+2 schreef Tim Graham:
Marten, did you consider putting the new API in `django.urls` instead of `django.core.urls`? I don't need there's a need to namespace it under "core", but others might be able to confirm the philosophy behind this.

That's certainly worth considering, in fact, I quite like the idea. If there are no objections (philosophical or otherwise) I'll move it to `django.urls`. 

Marten

Marc Tamlyn

unread,
Jul 10, 2015, 5:35:24 PM7/10/15
to django-d...@googlegroups.com

+100 for django.urls. resolving and reversing functions should be located in the same namespace.

M

--
You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-develop...@googlegroups.com.
To post to this group, send email to django-d...@googlegroups.com.
Visit this group at http://groups.google.com/group/django-developers.

James Addison

unread,
Aug 24, 2015, 10:02:38 AM8/24/15
to Django developers (Contributions to Django itself)
Hi Marten,

I'm just curious if this is still on track for inclusion within the Sept 21 Apha feature deadline? I've been using your Django `dispatcher_api` branch for a new project since I learned of your proposed changes and am excited to see them in stable Django. There hasn't been any changes in about a month on your branch, so I'm (hopefully understandably) curious as to its future?

Cheers,
James

Tim Graham

unread,
Aug 24, 2015, 10:36:53 AM8/24/15
to Django developers (Contributions to Django itself)
I don't think so. Marten has been MIA unfortunately. Someone else could try to pick it up, but it seems a bit ambitious to complete in the time remaining before alpha.

James Addison

unread,
Aug 24, 2015, 11:52:49 AM8/24/15
to Django developers (Contributions to Django itself)
Assuming https://www.google-melange.com/gsoc/project/details/google/gsoc2015/knbk/5668600916475904 is the canonical source for the project details, what is the status of each of its goals? From a high level, the project seems well described on that page, but everything after (ie. status) seems opaque - unless there is another resource?

It would be a shame for something so powerful to fall by the wayside. I'm sure I'm not the only one to see such value in this addition.

Tim Graham

unread,
Aug 24, 2015, 12:05:16 PM8/24/15
to Django developers (Contributions to Django itself)
You would have to take a look at the pull request and figure out the status. As far as I know, there aren't any status updates elsewhere.
Reply all
Reply to author
Forward
0 new messages