0

I am new to Django, and working on a URL shortener project like bitly. I am running into issues at the moment when trying to click the link created in the success.html template, it does not redirect, and appends the path + short_url + url:

DEBUG-URLRedirectView::get(): obj.url: www.google.com
[05/Feb/2017 19:02:27] "GET /gesw1m/ HTTP/1.1" 302 0
Not Found: /gesw1m/www.google.com
[05/Feb/2017 19:02:27] "GET /gesw1m/www.google.com HTTP/1.1" 404 2216

enter image description here

Here is the project tree:

-src_shrtnr
   manage.py
   -shrtnr
      hosts.py
      settings.py
      urls.py
      -hostconf
         urls.py
         views.py
   -shortener
      models.py
      views.py
      -templates
         -shortener
            already-exist.html
            home.html
            success.html
   -analytics
      ...

Here is the success.html template and image:

<div style='align-text: center; width: 800px; margin: 0 auto;'>
    <h1>Created!</h1>
    <p>{{ object.url }}</p>
    <p>Count: {{ object.clickevent.count }}</p>
    <p><a href='{{ object.get_short_url }}'>{{ object.get_short_url }}</a></p>
    <a href='/'>+New</a>
</div>

enter image description here

Here is the shortener models.py file:

class ShrtnrURL(models.Model):
    url = models.CharField(max_length=220, validators=[validate_url, validate_dot_com])
    shortcode = models.CharField(max_length=SHORTCODE_MAX, unique=True, blank=True)

    ...

    def get_short_url(self):
        url_path = reverse('scode', kwargs={'shortcode': self.shortcode}, host='www', scheme='http')
        print('DEBUG-ShrtnrURL::get_short_url(), url_path: ', url_path)
        return url_path

Here is the shortener views.py relevant view:

class URLRedirectView(View):
        qs = ShrtnrURL.objects.filter(shortcode__iexact=shortcode)
        if qs.count() != 1 and not qs.exists():
            raise Http404
        obj = qs.first()
        print('DEBUG-URLRedirectView::get(): obj.url: ',ClickEvent.objects.create_event(obj), obj.url)
        return HttpResponseRedirect(obj.url)

Here is hostconf urls.py:

from .views import wildcard_redirect

urlpatterns = [
    url(r'^(?P<path>.*)', wildcard_redirect),
]

Here is hostconf views.py:

DEFAULT_REDIRECT_URL = getattr(settings, 'DEFAULT_REDIRECT_URL', 'http://www.shrtnr.co')

def wildcard_redirect(request, path=None):
    new_url = DEFAULT_REDIRECT_URL
    if path is not None:
        new_url = DEFAULT_REDIRECT_URL + '/' + path
    print('DEBUG-wildcard_redirect(), new_url: ', new_url)
    return HttpResponseRedirect(new_url)

Here is hosts.py:

from shrtnr.hostsconf import urls as redirect_urls
host_patterns = [
    host(r'www', settings.ROOT_URLCONF, name='www'),
    host(r'(?!www).*', redirect_urls, name='wildcard'),
]

Here is shrtnr urls.py:

from shortener.views import HomeView, URLRedirectView
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^$', HomeView.as_view()),
    url(r'^(?P<shortcode>[\w-]+)/$', URLRedirectView.as_view(), name='scode'),
]

Selected sections from settings.py:

ALLOWED_HOSTS = ['www.shrtnr.co', 'shrtnr.co', 'blog.shrtnr.co']
INSTALLED_APPS = [
    ...
    # Third party
    'django_hosts',
    # Custom app
    'analytics',
    'shortener',
]
MIDDLEWARE = [
    'django_hosts.middleware.HostsRequestMiddleware',
    ...
    'django_hosts.middleware.HostsResponseMiddleware',
]
ROOT_URLCONF = 'shrtnr.urls'
ROOT_HOSTCONF = 'shrtnr.hosts'
DEFAULT_HOST = 'www'
DEFAULT_REDIRECT_URL = 'http://www.shrtnr.co:8000'
PARENT_HOST = 'shrtnr.co:8000'

Just to point out I added in /etc/hosts:

127.0.0.1 www.shrtnr.co
127.0.0.1 shrtnr.co
127.0.0.1 blog.shrtnr.co

I am still in "debug" mode, not hosting yet (will use Heroku), but I added :8000 port as needed in settings.py. I think I added all the necessary information, please let me know if I forgot to mention something. It might be resolved once I host it, but I am not sure.

  • Python 3.5
  • Django 1.10
  • installed django_hosts 2.0 successfully via anaconda
camelBack
  • 748
  • 2
  • 11
  • 30

1 Answers1

1

The problem is that your URL is just "www.google.com", without a protocol. When a browser is told to redirect, if there is no protocol it just treats it as a path - and since there is no initial slash either, it will treat it as a relative path and append it to the current location.

You probably need to add validation to ensure that the field contains a full URL including protocol, ie "https://www.google.com". Alternatively your view might inspect the value and prepend "http://" or "https://" if necessary.

Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895