title: Django __str__ returned non-string (type NoneType) but from django/contrib/admin
body: <p>Hey sorry if that questions has been asked before but i havent found a fix yet looking at the previous questions.</p>
  
  <p>i am trying to use django-booking (<a href="https://github.com/bitlabstudio/django-booking/tree/master/booking" rel="nofollow noreferrer">https://github.com/bitlabstudio/django-booking/tree/master/booking</a>) on my website/app, now i can do the booking as a client and save it, but in the admin side if i click on bookings, i get and error</p>
  
  <pre><code>&gt; TypeError at /admin/booking/booking/
  &gt; 
  &gt; __str__ returned non-string (type NoneType)
  &gt; 
  &gt; Request Method:   GET Request URL:
  &gt;   http://127.0.0.1:8000/admin/booking/booking/ Django Version:    2.0.8
  &gt; Exception Type:   TypeError Exception Value:  
  &gt; 
  &gt; __str__ returned non-string (type NoneType)
  &gt; 
  &gt; Exception Location:   C:\Program
  &gt; Files\Python37\lib\site-packages\django\contrib\admin\templatetags\admin_list.py
  &gt; in items_for_result, line 235 Python Executable:  C:\Program
  &gt; Files\Python37\python.exe Python Version:     3.7.0 Python Path:  
  &gt; 
  &gt; ['C:\\Users\\Agustin Landivar\\Desktop\\Marie\\drLandivar', 
  &gt; 'C:\\Program Files\\Python37\\python37.zip',  'C:\\Program
  &gt; Files\\Python37\\DLLs',  'C:\\Program Files\\Python37\\lib', 
  &gt; 'C:\\Program Files\\Python37',  'C:\\Program
  &gt; Files\\Python37\\lib\\site-packages']
  &gt; 
  &gt; Server time:  Tue, 21 Aug 2018 15:20:18 +0000 Error during template
  &gt; rendering
  &gt; 
  &gt; In template C:\Program
  &gt; Files\Python37\lib\site-packages\django\contrib\admin\templates\admin\base.html,
  &gt; error at line 70
  </code></pre>
  
  <p>how can i fix that to be able to see all the bookings in the admin without getting this error, i see that normally this error is because of a str, but its also says that the error is in the django/contrib folder which i never touch :/</p>
  
  <p>admin.py</p>
  
  <pre><code>"""Admin classes for the booking app."""
  from django.contrib import admin
  from hvad.admin import TranslatableAdmin
  from . import models
  from booking.models import Booking
  
  
  class BookingAdmin(admin.ModelAdmin):
      list_display = [
          'creation_date', 'booking_status', 'booking_id', 'user', 'email',
          'session', 'date_from', 'date_until',
      ]
  
  
  class BookingItemAdmin(admin.ModelAdmin):
      list_display = ['booking', 'booked_item', 'quantity', 'persons']
  
  
  admin.site.register(models.Booking, BookingAdmin)
  admin.site.register(models.BookingError)
  admin.site.register(models.BookingItem, BookingItemAdmin)
  admin.site.register(models.BookingStatus, TranslatableAdmin)
  admin.site.register(models.ExtraPersonInfo)
  </code></pre>
  
  <p>forms.py</p>
  
  <pre><code>"""Forms for the ``booking`` app."""
  from django import forms
  from django.conf import settings
  from django.contrib.auth import authenticate
  from django.contrib.auth.forms import AuthenticationForm
  from django.utils.translation import ugettext_lazy as _
  
  from .models import Booking, BookingStatus
  
  
  class BookingForm(forms.ModelForm):
      def __init__(self, session=None, user=None, *args, **kwargs):
          self.user = user
          self.session = session
          super(BookingForm, self).__init__(*args, **kwargs)
          # fields that should remain blank / not required
          keep_blank = [
              'phone', 'notes', 'street2', 'title', 'user', 'session',
              'date_from', 'date_until', 'special_request', 'time_period',
              'time_unit', 'email', 'currency', 'total']
          # set all fields except the keep_blank ones to be required, since they
          # need to be blank=True on the model itself to allow creating Booking
          # instances without data
          for name, field in self.fields.items():
              if name not in keep_blank:
                  self.fields[name].required = True
  
      def save(self, *args, **kwargs):
          if not self.instance.pk:
              self.instance.user = self.user
              self.instance.session = self.session
              status_object, created = BookingStatus.objects.get_or_create(
                  slug=getattr(settings, 'BOOKING_STATUS_CREATED', 'pending'))
              self.instance.booking_status = status_object
          return super(BookingForm, self).save(*args, **kwargs)
  
      class Meta:
          model = Booking
          fields = ('gender', 'title', 'forename', 'surname', 'nationality',
                    'street1', 'street2', 'city', 'zip_code', 'country', 'phone',
                    'special_request', 'date_from', 'date_until')
  
  
  class BookingIDAuthenticationForm(AuthenticationForm):
      def __init__(self, *args, **kwargs):
          super(BookingIDAuthenticationForm, self).__init__(*args, **kwargs)
          self.fields['username'] = forms.CharField(
              label=_("Email"), max_length=256)
          self.fields['password'] = forms.CharField(
              label=_("Booking ID"), max_length=100)
  
      def clean_username(self):
          """Prevent case-sensitive erros in email/username."""
          return self.cleaned_data['username'].lower()
  
      def clean(self):
          email = self.cleaned_data.get('username')
          booking_id = self.cleaned_data.get('password')
  
          if email and booking_id:
              self.user_cache = authenticate(username=email,
                                             password=booking_id)
              if self.user_cache is None:
                  raise forms.ValidationError(_(
                      'We cannot find a valid booking ID for this email'
                      ' address.')
                  )
              elif not self.user_cache.is_active:
                  raise forms.ValidationError(self.error_messages['inactive'])
          self.check_for_test_cookie()
          return self.cleaned_data
  </code></pre>
  
  <p>models.py</p>
  
  <pre><code>"""Models for the ``booking`` app."""
  from django.conf import settings
  from django.contrib.contenttypes.fields import GenericForeignKey
  from django.contrib.contenttypes.models import ContentType
  from django.db import models
  from django.utils.encoding import python_2_unicode_compatible
  from django.utils.translation import ugettext_lazy as _
  
  from django_libs.models_mixins import TranslationModelMixin
  from django_countries.fields import CountryField
  from hvad.models import TranslatableModel, TranslatedFields
  from drLandivar import settings
  
  
  class BookingStatus(TranslationModelMixin, TranslatableModel):
      """
      Master data containing all booking status.
      For translatable fields check ``BookingStatusTranslation``.
  
      :slug: A unique slug identifier.
  
      translated:
      :name: The displayable name for the status.
  
      """
      slug = models.SlugField(
          verbose_name=_('Slug'),
      )
  
      translations = TranslatedFields(
          name=models.CharField(
              verbose_name=_('Name'),
              max_length=128,
          )
      )
  
  
  @python_2_unicode_compatible
  class Booking(models.Model):
      user = models.ForeignKey(
          'users.CustomUser',
          verbose_name=_('User'),
          related_name='bookings',
          blank=True, null=True,
          on_delete=models.CASCADE,
      )
  
      session = models.ForeignKey(
          'sessions.Session',
          verbose_name=_('Session'),
          blank=True, null=True,
          on_delete=models.CASCADE,
      )
  
      gender = models.CharField(
          max_length=10,
          verbose_name=_('Gender'),
          choices=(
              ('mrs', _('Mrs')),
              ('mr', _('Mr')),
          ),
          blank=True,
      )
  
      title = models.CharField(
          max_length=10,
          verbose_name=_('Title'),
          choices=(
              ('dr', _('Dr.')),
              ('prof', _('Prof.')),
          ),
          blank=True,
      )
  
      forename = models.CharField(
          verbose_name=_('First name'),
          max_length=20,
          blank=True,
      )
  
      surname = models.CharField(
          verbose_name=_('Last name'),
          max_length=20,
          blank=True,
      )
  
      nationality = CountryField(
          max_length=2,
          verbose_name=_('Nationality'),
          blank=True,
      )
  
      street1 = models.CharField(
          verbose_name=_('Street 1'),
          max_length=256,
          blank=True,
      )
  
      street2 = models.CharField(
          verbose_name=_('Street 2'),
          max_length=256,
          blank=True,
      )
  
      city = models.CharField(
          verbose_name=_('City'),
          max_length=256,
          blank=True,
      )
  
      zip_code = models.CharField(
          verbose_name=_('ZIP/Postal code'),
          max_length=256,
          blank=True,
      )
  
      country = CountryField(
          max_length=2,
          verbose_name=_('Country'),
          blank=True,
      )
  
      email = models.EmailField(
          verbose_name=_('Email'),
          blank=True,
      )
  
      phone = models.CharField(
          verbose_name=_('Phone'),
          max_length=256,
          blank=True,
      )
  
      special_request = models.TextField(
          max_length=1024,
          verbose_name=_('Special request'),
          blank=True,
      )
  
      date_from = models.DateTimeField(
          verbose_name=_('From'),
          blank=True, null=True,
      )
  
      date_until = models.DateTimeField(
          verbose_name=_('Until'),
          blank=True, null=True,
      )
  
      creation_date = models.DateTimeField(
          verbose_name=_('Creation date'),
          auto_now_add=True,
      )
  
      booking_id = models.CharField(
          max_length=100,
          verbose_name=_('Booking ID'),
          blank=True,
      )
  
      booking_status = models.ForeignKey(
          'booking.BookingStatus',
          verbose_name=('Booking status'),
          blank=True, null=True,
          on_delete=models.CASCADE,
      )
  
      notes = models.TextField(
          max_length=1024,
          verbose_name=('Notes'),
          blank=True,
      )
  
      time_period = models.PositiveIntegerField(
          verbose_name=_('Time period'),
          blank=True, null=True,
      )
  
      time_unit = models.CharField(
          verbose_name=_('Time unit'),
          default=getattr(settings, 'BOOKING_TIME_INTERVAL', ''),
          max_length=64,
          blank=True,
      )
  
      total = models.DecimalField(
          max_digits=36,
          decimal_places=2,
          verbose_name=_('Total'),
          blank=True, null=True,
      )
  
      currency = models.CharField(
          verbose_name=_('Currency'),
          max_length=128,
          blank=True,
      )
  
      class Meta:
          ordering = ['-creation_date']
  
      def __str__(self):
          return '#{} ({})'.format(self.booking_id or self.pk,
                                   self.creation_date)
  
  
  @python_2_unicode_compatible
  class BookingError(models.Model):
      booking = models.ForeignKey(
          Booking,
          verbose_name=_('Booking'),
          on_delete=models.CASCADE,
      )
      message = models.CharField(
          verbose_name=_('Message'),
          max_length=1000,
          blank=True,
      )
      details = models.TextField(
          verbose_name=_('Details'),
          max_length=4000,
          blank=True,
      )
  
      date = models.DateTimeField(
          verbose_name=_('Date'),
          auto_now_add=True,
      )
  
      def __str__(self):
          return u'[{0}] {1} - {2}'.format(self.date, self.booking.booking_id,
                                           self.message)
  
  
  @python_2_unicode_compatible
  class BookingItem(models.Model):
      quantity = models.PositiveIntegerField(
          default=1,
          verbose_name=_('Quantity'),
      )
  
      persons = models.PositiveIntegerField(
          verbose_name=_('Persons'),
          blank=True, null=True,
      )
  
      subtotal = models.DecimalField(
          max_digits=36,
          decimal_places=2,
          verbose_name=_('Subtotal'),
          blank=True, null=True,
      )
  
      # GFK 'booked_item'
      content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE,)
      object_id = models.PositiveIntegerField()
      booked_item = GenericForeignKey('content_type', 'object_id')
  
      booking = models.ForeignKey(
          'booking.Booking',
          verbose_name=_('Booking'),
          on_delete=models.CASCADE,
      )
  
      class Meta:
          ordering = ['-booking__creation_date']
  
      def __str__(self):
          return u'{} ({})'.format(self.booking, self.booked_item)
  
      @property
      def price(self):
          return self.quantity * self.subtotal
  
  
  @python_2_unicode_compatible
  class ExtraPersonInfo(models.Model):
      """
      Model to add extra information of persons/guests to a booking.
  
      :forename: First name of the user.
      :surname: Last name of the user.
      :arrival: Arrival date of the guest.
      :booking: Connection to related booking.
      :message: An additional message regarding this person.
  
      """
      forename = models.CharField(
          verbose_name=_('First name'),
          max_length=20,
      )
  
      surname = models.CharField(
          verbose_name=_('Last name'),
          max_length=20,
      )
  
      arrival = models.DateTimeField(
          verbose_name=_('Arrival'),
          blank=True, null=True,
      )
  
      booking = models.ForeignKey(
          'booking.Booking',
          verbose_name=_('Booking'),
          on_delete=models.CASCADE,
      )
  
      message = models.TextField(
          max_length=1024,
          verbose_name=_('Message'),
          blank=True,
      )
  
      class Meta:
          ordering = ['-booking__creation_date']
  
      def __str__(self):
          return u'{} {} ({})'.format(self.forename, self.surname, self.booking)
  </code></pre>
  
  <p>views.py</p>
  
  <pre><code>from django.shortcuts import render
  
  # Create your views here.
  """Views for the booking app."""
  from django.contrib.auth.decorators import login_required
  from django.contrib.sessions.models import Session
  from django.urls import reverse
  from django.http import Http404
  from django.utils.decorators import method_decorator
  from django.views.generic import CreateView, DetailView, ListView
  
  from .forms import BookingForm
  from .models import Booking
  
  
  # ------ MIXINS ------ #
  
  class BookingViewMixin(object):
      model = Booking
      form_class = BookingForm
  
  
  # ------ MODEL VIEWS ------ #
  
  class BookingCreateView(BookingViewMixin, CreateView):
      """View to create a new ``Booking`` instance."""
      def get_success_url(self):
          return reverse('booking_detail', kwargs={'pk': self.object.pk})
  
      def get_form_kwargs(self, *args, **kwargs):
          kwargs = super(BookingCreateView, self).get_form_kwargs(
              *args, **kwargs)
          if self.request.user.is_authenticated:
              kwargs.update({'user': self.request.user})
          else:
              # If the user is not authenticated, get the current session
              if not self.request.session.exists(
                      self.request.session.session_key):
                  self.request.session.create()
              kwargs.update({'session': Session.objects.get(
                  session_key=self.request.session.session_key)})
          return kwargs
  
  
  class BookingDetailView(BookingViewMixin, DetailView):
      """View to display a ``Booking`` instance."""
      def dispatch(self, request, *args, **kwargs):
          self.kwargs = kwargs
          self.object = self.get_object()
          if request.user.is_authenticated:
              # If user doesn't own the booking forbid access
              if not self.object.user == request.user:
                  raise Http404
          else:
              # If anonymous doesn't own the booking forbid access
              session = self.object.session
              if (not session or not request.session.session_key or
                      session.session_key != request.session.session_key):
                  raise Http404
          return super(BookingViewMixin, self).dispatch(request, *args, **kwargs)
  
  
  class BookingListView(BookingViewMixin, ListView):
      """View to display all ``Booking`` instances of one user."""
      @method_decorator(login_required)
      def dispatch(self, request, *args, **kwargs):
          return super(BookingViewMixin, self).dispatch(request, *args, **kwargs)
  
      def get_queryset(self):
          return self.request.user.bookings.all()
  </code></pre>