Super (type, obj): obj должен быть экземпляром или подтипом типа

Я работаю над небольшим приложением Django и получаю сообщение об ошибке, super(type, obj): obj must be an instance or subtype of type. Я получаю его из файла views.py после введения функции get_object_or_404. Файл views.py, указанный ниже,

from django.shortcuts import render, get_object_or_404    
from django.http import HttpResponse, HttpResponseRedirect     
from django.views import View     
from .models import URL


# function based view 
def redirect_view(request, shortcode=None, *args, **kwargs):
    obj = get_object_or_404(URL, shortcode=shortcode)
    return HttpResponse("Hello World, the shortcode is {shortcode}".format(shortcode = obj.url))


# class based view 
class ShortenerView(View):

    def get(self, request, shortcode=None,  *args, **kwargs):
        obj = get_object_or_404(URL, shortcode=shortcode)
        return HttpResponse("Hello World 1, the shortcode is {shortcode}".format(shortcode = obj.url))

    def post(self, request, *args, **kwargs):
        return HttpResponse()

здесь отображается полное сообщение об ошибке,

TypeError at /b/p6jzbp/
super(type, obj): obj must be an instance or subtype of type
Request Method: GET
Request URL:    http://127.0.0.1:8000/b/p6jzbp/
Django Version: 1.11
Exception Type: TypeError
Exception Value:    
super(type, obj): obj must be an instance or subtype of type
Exception Location: /Users/Chaklader/Documents/Projects/UrlShortener/src/shortener/models.py in all, line 18

В models.py line 18 находится qs_main = super(URL, self).all(*args, **kwargs), а файл models.py находится здесь,

#  will look for the "SHORTCODE_MAX" in the settings and 
#  if not found, will put the value of 15 there 
SHORTCODE_MAX = getattr(settings, "SHORTCODE_MAX", 15)



class UrlManager(models.Manager):

    def all(self, *args, **kwargs):
        qs_main = super(URL, self).all(*args, **kwargs)
        qs      = qs_main.filter(active = True)
        return qs

    def refresh_shortcodes(self, items = None):

        qs = URL.objects.filter(id__gte=1)
        new_codes = 0

        if items is not None and isinstance(items, int):
            qs = qs.order_by('-id')[:items]

        for q in qs:
            q.shortcode = create_shortcode(q)
            print (q.id, " ", q.shortcode)
            q.save()
            new_codes += 1

        return "# new codes created {id}".format(id = new_codes)


class URL(models.Model):

    url         =  models.CharField(max_length = 220, )
    shortcode   =  models.CharField(max_length = SHORTCODE_MAX, blank = True, unique = True)
    updated     =  models.DateTimeField(auto_now = True)
    timestamp   =  models.DateTimeField(auto_now_add = True)
    active      = models.BooleanField(default = True)

    objects = UrlManager()

    def save(self, *args, **kwargs):

        if self.shortcode is  None or self.shortcode == "":
            self.shortcode = create_shortcode(self)

        super(URL, self).save(*args, **kwargs)

    def __str__(self):
        return str(self.url)

    def __unicode__(self):
        return str(self.url)

    # class Meta:
    #   ordering = '-id'

Может кто-нибудь объяснить причину ошибки для меня и как ее решить? Я открыт для предоставления дополнительной информации, если требуется.

Ответ 1

Вы должны вызывать super с использованием класса UrlManager качестве первого аргумента, а не модели URL. super не может быть вызван с несвязанным классом/типом:

Из документов,

super(type[, object-or-type]): возвращает прокси-объект, который делегирует вызовы метода родительскому или родственному классу типа.

Так что вы не можете сделать:

>>> class D:
...    pass
... 
>>> class C:
...    def __init__(self):
...        super(D, self).__init__()
... 
>>> C()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in __init__
TypeError: super(type, obj): obj must be an instance or subtype of type

Ты должен сделать:

qs_main = super(UrlManager, self).all(*args, **kwargs)

Или в Python 3:

qs_main = super().all(*args, **kwargs)

Ответ 2

Еще один способ возникновения этой ошибки - перезагрузка модуля с классом в записной книжке Jupiter.

Простое решение - перезапустить ядро.

http://thomas-cokelaer.info/blog/2011/09/382/

Ответ 3

Разработка в ответе @Oğuz Şerbetci, в python3 (не обязательно только в Jupyter), когда есть необходимость перезагрузить библиотеку, например, у нас есть class Parent и class Child определенные как

class Parent(object):
    def __init__(self):
        # do something

class Child(Parent):
    def __init__(self):
        super(self,Child).__init__(self)

тогда, если вы сделаете это

import library.Child
reload(library)

Child()

вы получите TypeError: super(type, obj): obj must be an instance or subtype of type, решение состоит в том, чтобы просто повторно импортировать класс после перезагрузки

import library.Child
reload(library)
import library.Child

Child()

Ответ 4

Еще один интересный способ заключается в том, что слияние ветвей дублирует класс, так что в файле у вас есть два определения для одного и того же имени, например

class A(Foo):
    def __init__(self):
        super(A, self).__init__()
        #...

class A(Foo):
    def __init__(self):
        super(A, self).__init__()
        #...

Если вы попытаетесь создать экземпляр из статической ссылки на первое определение A, как только он попытается вызвать super, внутри метода __init__ A будет ссылаться на второе определение A, поскольку он был перезаписан. Решение - конечно, - удалить дублирующее определение класса, поэтому оно не будет перезаписано.

Это может показаться чем-то, что никогда не произойдет, но это случилось со мной, когда я не обращал достаточно пристального внимания на слияние двух ветвей. Мои тесты не удались с сообщением об ошибке, описанным в вопросе, поэтому я думал, что остану здесь свои выводы, хотя он точно не отвечает на конкретный вопрос.