-
-
Notifications
You must be signed in to change notification settings - Fork 6.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature/url versions #1143
Feature/url versions #1143
Conversation
Versioning is something we need to provide. (No one disagrees with that right?) Every time it comes up on the mailing list there's talk of doing it via Accept headers. This sounds great but (perhaps I'm slow) I can't see how doing it that way is (currently) feasible without rewriting — essentially cut and pasting — whole sections of the GCBVs. Here we have the basis of a working solution to the versioning problem. Unless similar can be demonstrated using the correct Accept approach we should throw our weight behind this and get it in. What needs to be done? I'd be inclined to break it into sub-tickets if possible so we can collaborate. I, for one, will put some cycles into this. |
Just posting here for ease of reference (whilst planning a "Topics > Versioning your API" page) This was the example from the mailing list thread:
So if we did that multiple times we'd do:
|
Looks good, how else could I help out? What are the edge cases where it could break? |
Ideas:
I think it wold be cool if we could show an absolutely minimal versioned api — or outline in the style of the Quickstart. i.e. one URLConf using the method above pointing to two hello world views in different modules. (And we say, "From here you can include different versions of ... as needed for your application." and so on.) |
The content of the pull-request strikes me as totally harmless — it's just adding namespace support to rest_framework.reverse — which arguably it should have anyway. Perhaps we should merge this and open a new ticket for "Documenting how to Version your API"? @tomchristie It would be good to have your thoughts. Given the tight mapping (in Django) between URLs and views it's hard to see other ways around versioning. — Old code I wrote that went if request.method == "GET": (... and so on) keeps flashing into my mind :) — branching by URL seems cleaner. |
url = django_reverse(viewname, args=args, kwargs=kwargs, **extra) | ||
|
||
try: | ||
namespace=resolve(request.path).namespace |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At least in newer versions of Django I think this information is already stored on the request object?
Little cautious about introducing this as it currently stands as a single view might output a lot of URLs, all of which will now cause URL resolving.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since Django 1.5 we have the ResolverMatch which gives us the namespace.
So we can do:
try:
namespace = request.resolver_match.namespace
except AttributeError: # this is right yes?
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we always get a request?
I'm just trying to profile this change (and the request.resolver_match.namespace
version) against the original and hit an AttributeError here.
'NoneType' object has no attribute 'path'
— Given that the current tests pass but None is a valid value, we need a new test (I think)
URL Versioning, accept header versioning, versioning in the request/response content, And not versioning at all are all valid options in different circumstances. It probably would be good to suppport at least URL based versioning out of the box and for sure we need to document the options. This PR seems to be along sensible lines though will need to mull it over. Also note the inline comment. I might be fine with only supporting on certain versions of Django if there's a limitation there. |
I've been quiet on this. As ever I got busy. :-) Before that, I began looking in to it but realised I don't know enough about how app/instance/url namespaces work in Django to be 100% confident about the solution. I started on the docs but ate whatever time I had not getting very far. (It was basically clear as mud — probably simple enough but not laid out very well in the Django documentation.) I also started to profile the change — and the suggested alteration using the Finally, as I've let it stew, I've come to wonder if we need the namespace at all. Doesn't this work equally?
(This just adapts the example from the previous discussion.) Counterpoint: Even if it does, arguably |
I'm pretty sure that not including the namespace but using the same named paths won't work (thinking of a router giving the same names). Either way, it isn't difficult to include namespace support, and this is definitely a use case that fits larger applications. |
On 24 Oct 2013, at 15:31, Kevin Brown [email protected] wrote:
Ah, yes, of course. My comment was hoping to restart this one.
— Cool. The bit I ran out of time on was "app" vs "instance" and such. I didn't have time to get my head round it to make sure the patch was right. |
Ok I've been seriously thinking about this and just got around to testing it. My worry was 1) what happens when So this new commit should cover both. And I switched to |
As it currently stands, all tests are now failing. New tests should probably be added to make sure the namespaces work correctly? |
Ah I didn't run tests. Huburis... |
And what should we test now? Using the DRF reverse with a "namspace:app"? and without request objects? and perhaps without a namespace in the urls.py |
Hey @carltongibson I'm not quite sure I follow. As it currently stands, this pull attempts to use |
i'm pretty sure this will fail if the passed url has a different namespace than the view/request namespace. |
@kevin-brown could you give an example? |
@readevalprint I think the idea was simply not to support namespaces if |
@carltongibson That works for me. Let me update the pull. |
bump. Hey guys thanks for working on this aspect. What is the current status? |
This is on my list to get finished. (We should be supporting namespaced URLs.) My guess is the pull as-is would work for the usual cases but we need to draw up a list of test cases where it may break and ensure all of those are good. (Given that it's new behaviour we could just make sure non-namespaced URLs are okay and put a big "try this, if you have issues let us know" sign on it — but I'd rather cover as much as we can before thinking about that.) Any thoughts on this thread as to cases that would be worth testing would be welcome. On 6 Dec 2013, at 09:44, rosscdh [email protected] wrote:
|
url = django_reverse(viewname, args=args, kwargs=kwargs, **extra) | ||
|
||
if request: | ||
if hasattr(request, 'resolver_match'): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could drop this logic into the Request
class, to transparently support a .resolver_match
attribute.
@carltongibson Sounds good ✨ I guess we have the following cases:
I don't think case (0) needs any work - that ought to already be fine. I think the right approach might be to use the existing |
OK. I somehow managed to clear the list. Am looking at this now. |
oo wow, forgot about this. I'm looking now too |
Hey Tim — Ok, cool. The bit I'm thinking about is the minimum needed to bootstrap a unit for Beyond that there's @tomchristie's comments and we should be about done. |
Right… Okay… As per usual I've been totally snowballed by work. However, this ticket seems a good candidate for the sprint in Cardiff this weekend. (There is one right?) I made this note that might aid that:
If this doesn't get knocked off in Cardiff I'll make the session in the next few weeks to get it done. C. |
any news on this? |
It's still on the list. I need to sit down and write the tests for it. Unless someone jumps in that will be "next free moment". The patch should more-or-less work. If you want to cherry-pick it and have a play you can do that. Any failing test cases you come up with would also help. |
Bump. Will test the patch, but wondering if this will be in the next DRF release? Any reason it wasn't in the 2.3.13 release from a few weeks ago? |
Hey @pikeas — this wasn't in the last release because it's not ready yet. At the least it needs tests and docs — but the code probably needs adjusting too. (Having said that it'll probably work, and any real-world feedback would no doubt be handy.) The main stumbling block is the tests — they're not hard but it's a bit of boilerplate which means a little bit of time setting it up. I've put my hand up to do that but frankly have been snowed under and have had essentially zero time for any OSS — or even much Django for that matter. I am doing some API work this week so I'll see if I can squeeze it in. |
Closing in favour of #1495 |
* carltongibson/encode#1143: Reverse order to checks in reverse. Some tests for the patch in encode#1143. Finally!
This gives the ability to use namespaces in the urls.py and have reverse pick up on them automatically so that all links generated in the api use the current namespace pattern, if any.
From this discussion: https://groups.google.com/forum/?fromgroups=#!topic/django-rest-framework/JBb-k7FTnvA
In this example the default urlpatterns is also aliased to /v1/
url(r'', include(urlpatterns)), # urls are like http://example.com/user/tim
url(r'v1/', include(urlpatterns, namespace='v1')), # urls are like http://example.com/v1/user/tim
It passes currents tests.
Let me know what it would take to get this accepted :)