0

my app (deployed to Heroku fwiw) had two model objects, Org and Event with corresponding object views and no issues/errs. when I introduced a third object Theme and modified some url routes to use its slug, I'm now getting the following err requesting the view for Org (url path whose view takes org.slug as a param):

AttributeError: 'NoneType' object has no attribute 'org' and a 404

orgs.models.py

class Org(models.Model):
     name = models.CharField(max_length=100, unique=True)
     slug = AutoSlugField(populate_from='name')
     themes = models.ManyToManyField('common.Theme', related_name='orgs', blank=True)
     ...

     def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('org-detail', args=[self.slug])

class Event(models.Model):
      org = models.ForeignKey('Org', on_delete=models.CASCADE, related_name='events')
      name = models.CharField(max_length=120)
      slug = AutoSlugField(populate_from='name', unique_with='org', sep='-')
      ...

      def __str__(self):
        return self.name

      def get_absolute_url(self):
        return reverse('event-detail', args=[self.org.slug, self.slug])

common.models.py

class Theme(models.Model):
    name = models.CharField(max_length=50)
    slug = AutoSlugField(populate_from='name')

    class Meta:
        ordering = ['name']

    def __str__(self):
        return self.name

    def get_absolute_url(self):
        return reverse('themes', args=[self.slug])

orgs.urls.py

urlpatterns = [
    url(r'^org/(?P<org_slug>[-\w]+)/?$', views.org, name='org-detail'),
    url(r'^org/(?P<org_slug>[-\w]+)/event/(?P<slug>[-\w]+)/', include([
        url(r'^$', views.event, name='event-detail'),
        ...
    ])),
    ...
]

common.urls.py

urlpatterns = [
     url(r'^(?P<slug>[-\w]+)/?$', views.theme, name='theme'),
     ...
]

orgs.views.py

def event(request, org_slug, slug):

     event = Event.objects.filter(slug=slug).order_by('id').first()

     if event.org.slug != org_slug:
         raise Http404

     event_url = '{}{}{}'.format(settings.DEFAULT_PROTOCOL, settings.APP_DOMAIN, event.get_absolute_url())

     context = {
         'event': event,
         'event_url': event_url,
         'event_url_encode': urlquote_plus(event_url),
     }

     return render(request, 'orgs/event.html', context)


def org(request, slug, role=None):
    try:
        org = Org.objects.get(slug=slug)
    except Org.DoesNotExist:
        return HttpResponseBadRequest()

    context = {
        'org': org,
    }

    return render(request, 'orgs/org.html', context)

views.event returns valid response as expected. views.org used to, but now returns 404. the log err actually shows the err being generated by views.event, but I don't understand why:

    Traceback (most recent call last): 
    File "/app/.heroku/python/lib/python3.6/site-packages/django/core/handlers/exception.py", line 41, in inner 
    response = get_response(request) 
    File "/app/.heroku/python/lib/python3.6/site-packages/django/core/handlers/base.py", line 249, in _legacy_get_response 
    response = self._get_response(request) 
    File "/app/.heroku/python/lib/python3.6/site-packages/django/core/handlers/base.py", line 187, in _get_response 
    response = self.process_exception_by_middleware(e, request) 
File "/app/.heroku/python/lib/python3.6/site-packages/channels/handler.py", line 237, in process_exception_by_middleware 
return super(AsgiHandler, self).process_exception_by_middleware(exception, request) 
File "/app/.heroku/python/lib/python3.6/site-packages/django/core/handlers/base.py", line 185, in _get_response 
    response = wrapped_callback(request, *callback_args, **callback_kwargs) 
    File "/app/.heroku/python/lib/python3.6/contextlib.py", line 52, in inner 
    return func(*args, **kwds) 
    File "/app/project/utils/helpers.py", line 28, in _decorated 
    return view(request, *args, **kwargs) 
    File "/app/.heroku/python/lib/python3.6/site-packages/htmlmin/decorators.py", line 13, in minify 
    response = f(*args, **kwargs) 
    File "/app/orgs/views.py", line 243, in event 
    if event.org.slug != org_slug: 
    AttributeError: 'NoneType' object has no attribute 'org' 

in debug mode Django says: No Theme matches the given query. raised by project.utils.helpers._decorated for GET app.com/org/valid-org-slug. why is Theme being called in that query (or Theme's slug being used as an arg instead of org?) - it's not used or requested by views.event or views.org? and how can Event be NoneType for views.org if view.event returns the correct object? thanks

Chris B.
  • 1,505
  • 5
  • 26
  • 48
  • Please refer to this https://stackoverflow.com/questions/8949252/python-attribute-error-nonetype-object-has-no-attribute-something – Jamshy Jan 07 '19 at 06:45
  • `event = Event.objects.filter(slug=slug).order_by('id').first() ` event is empty here please check what you are sending in the url, code is correct and you can try it in shell. – NVS Jan 07 '19 at 11:56

2 Answers2

0

Actually the problem here in the code is with first(). first returns None if there is no matching object in the queryset. You should change the line like this:

events = Event.objects.filter(slug=slug).order_by('id')
if events.exists():
    event = events.first()
ruddra
  • 50,746
  • 7
  • 78
  • 101
  • appreciate you pointing that out but its not the source of this issue (doesn't change the err). the issue is related to `'No Theme matches the given query.'` because I'm not querying for Theme but I've done something in the code that's causing the view to get the wrong argument – Chris B. Jan 07 '19 at 06:55
  • as per your stacktrace, it is the underlying cause. But in debug mode, I am not sure why you are getting this error. Because as per regex, it should not go to theme view at `org/...` url path. So um, can you change the url arrangment in root `urls.py` where org app's urls are included before common urls. Like `url(r'^$`, include('org.urls')` on top of `url(r'^$`, include('common.urls')`, and please see if the error persists? – ruddra Jan 07 '19 at 08:14
  • I did resolve the issue by changing the url path. I too am unclear why it was going to theme view at `org/...` – Chris B. Jan 07 '19 at 17:25
  • To be honest, its not a solution, even though the problem is resolved. I will try to look into this tomorrow. – ruddra Jan 07 '19 at 19:03
0

I elimated the err by changing the url path in common.urls from

url(r'^(?P<slug>[-\w]+)/?$', views.theme, name='theme'),

to:

url(r'^foo/(?P<slug>[-\w]+)/?$', views.theme, name='theme'),

after that views.event and views.org work as expected. the url config I was using was causing a regex issue that created the underlying NoneType err. I still don't fully understand the cause/source of the regex issue.

Chris B.
  • 1,505
  • 5
  • 26
  • 48