Django __str__返回非字符串(类型NoneType),但来自django / contrib / admin

时间:2018-08-21 15:45:43

标签: django django-admin

对不起,如果以前已经有人问过这个问题,但是我还没有找到解决方法,请仔细阅读前面的问题。

我正在尝试在我的网站/应用程序上使用django-booking(https://github.com/bitlabstudio/django-booking/tree/master/booking),现在我可以作为客户端进行预订并保存预订了,但是在管理端,如果我单击预订,我会和错误

> TypeError at /admin/booking/booking/
> 
> __str__ returned non-string (type NoneType)
> 
> Request Method:   GET Request URL:
>   http://127.0.0.1:8000/admin/booking/booking/ Django Version:    2.0.8
> Exception Type:   TypeError Exception Value:  
> 
> __str__ returned non-string (type NoneType)
> 
> Exception Location:   C:\Program
> Files\Python37\lib\site-packages\django\contrib\admin\templatetags\admin_list.py
> in items_for_result, line 235 Python Executable:  C:\Program
> Files\Python37\python.exe Python Version:     3.7.0 Python Path:  
> 
> ['C:\\Users\\Agustin Landivar\\Desktop\\Marie\\drLandivar', 
> 'C:\\Program Files\\Python37\\python37.zip',  'C:\\Program
> Files\\Python37\\DLLs',  'C:\\Program Files\\Python37\\lib', 
> 'C:\\Program Files\\Python37',  'C:\\Program
> Files\\Python37\\lib\\site-packages']
> 
> Server time:  Tue, 21 Aug 2018 15:20:18 +0000 Error during template
> rendering
> 
> In template C:\Program
> Files\Python37\lib\site-packages\django\contrib\admin\templates\admin\base.html,
> error at line 70

我该如何解决这个问题,以便能够在不出现此错误的情况下查看管理员中的所有预订,我通常看到此错误是由于str引起的,但是它也说该错误在django / contrib文件夹中我从没碰过:/

admin.py

"""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)

forms.py

"""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

models.py

"""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)

views.py

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()

1 个答案:

答案 0 :(得分:1)

根据我的经验,当 str 函数中使用的至少一个变量为None时,会发生此错误。从外壳检查数据库中所有模型中的对象,并查找 str 函数中提到的变量。如果其中任何一个为“无”,请修复它。请注意,在访问与故障对象无关的页面时,您可能会遇到此错误。祝你好运