spaceman.spiff
spaceman.spiff

Reputation: 13

Django 1.6 reverse() fails, kwarg value missing from Exception value

I have an affiliate program app with redirects and link statistics tracking. A read-only field in the Django Admin should display the full URL of the affiliate link, (so the user can copy+paste this into their editor) but the reverse() call in the model instance's get_absolute_url() method is failing when called from a callable in the admin class. For example:

from project urls.py

urlpatterns = patterns(
    '',
    url(r'^a/', include('shop.affiliates.urls', namespace='affiliates')),
    ...

from shop.affiliates.urls.py

urlpatterns = patterns(
    '',
    url(r'^(?P<slug>[\w]+)/$', redirect_to_affiliate_link, name='affiliate_redirect'),

)

from shop.affiliates.models.py

class AffiliateLink(models.Model):
    ...
    slug = models.SlugField(
        max_length=4,
        help_text='The slug for this link, used to generate url.',
    )
    ...
    def get_absolute_url(self):
        return reverse(
            'affiliates:affiliate_redirect',
            kwargs={'slug': self.slug},
        )

Note: for the sake of debugging simplicity, it's safe to assume that the slug field has already been populated in the database previously. So I'm not trying to create a new object where slug has not yet been set.

from shop.affiliates.admin.py

class AffiliateLinkInline(admin.StackedInline):

    model = AffiliateLink
    extra = 0
    fields = (
        ..., 'hyperlink', ...
    )
    readonly_fields = (
        'hyperlink', ...
    )

    def hyperlink(self, obj):
        url = 'http://example.com{}'.format(obj.get_absolute_url())
        return '<a href="{0}">{0}</a>'.format(url)
    hyperlink.allow_tags = True

When loading the appropriate admin page, I get a NoReverseMatch exception. Exception value: Reverse for 'affiliate_redirect' with arguments '()' and keyword arguments '{u'slug': u''}' not found. 1 pattern(s) tried: [u'a/(?P<slug>[\\w]+)/$']

so the proper regex is found, but the slug parameter is empty. I verified that obj.slug within the admin callable exists, and it is the correct AffiliateLink slug. To make matters more strange, if I switch the kwargs in get_absolute_url() like so:

def get_absolute_url(self):
        return reverse(
            'affiliates:affiliate_redirect',
            kwargs={'bug': self.slug},
        )

Then the exception value changes to:

Reverse for 'affiliate_redirect' with arguments '()' and keyword arguments '{u'bug': u'7aeB'}' not found. 1 pattern(s) tried: [u'a/(?P<slug>[\\w]+)/$']

So the kwarg value for key 'slug' disappears from the exception value, but the value for 'bug' stays.

What am I doing wrong here? Any help is greatly appreciated.

Upvotes: 1

Views: 235

Answers (1)

hellsgate
hellsgate

Reputation: 6005

URL patterns are sometime evaluated before URLconf has been loaded. Try reverse_lazy instead of reverse

https://docs.djangoproject.com/en/dev/ref/urlresolvers/#reverse-lazy

Upvotes: 1

Related Questions