So I just received a requirement to have an internal profile site URL that links to an external page. Think of it like I have an internal URL such as `www.adamwester.me/internal-url-goes-external/` which would link to something external, such as a blog post somewhere else

Ok let's take a look at this and build it out cleanly. My general strategy is to create a model with just two fields - we list the internal slug URL and the external URL that it should redirect to.


class ExternalURL(models.Model):
    """
    used to redirect to an external url from an internal url
    """
    internal_slug = models.SlugField(max_length=100)
    external_url = models.URLField(max_length=250)

    def __str__(self):
        return self.external_url

Then when we get into the view layer, I utilize django's built-in DetailView to access the model instance, although we have to override some stuff since after we get the object we aren't going to display a template. In order to do that, I override the get method and instead of rendering a template I'm going to redirect to the model object's external URL.


# views.py
class ExternalURLRedirectView(DetailView):
    """
    when a user goes to a specific internal url, they'll be redirected to an
    external URL. This is used to link to an external url such as a blog post,
    but share a url to the profile site.
    """
    model = ExternalURL
    slug_field = "internal_slug"

    def get_redirect_url(self, *args, **kwargs):
        object = self.get_object()
        return object.external_url

    def get(self, request, *args, **kwargs):
        """
        handle redirect view and redirect to the `external_url` listed on object
        """
        return HttpResponseRedirect(self.get_redirect_url())

That's it! Pretty clean, right? After adding the model to your admin.py, the user will then be able to add in a slug such as `internal-url-link` and it will redirect to what they put in the external_url field.

We're hooking into built-in functionality of detail view to pick up the slug url argument and connect the request to the appropriate model instance of ExternalURL. When defining the url pattern in your urls.py, make sure that you put the url in the right place so that it doesn't interfere with your other urls. In my case, I needed to put it at the end since I have it on my root URL.


# urls.py

... 

urlpatterns = [
    url(r'^$', HomeView.as_view(), name="home"),
    url(r'^about/$', AboutView.as_view(), name="about"),

    # this url needs to be last
    url(r'^(?P[-\w]+)/$', ExternalURLRedirectView.as_view(), name="external-url"),
]