Widoki klas w Django

Widok Django wskazuje na funkcję, która może być problemem, jeśli chcesz zmienić tylko część funkcjonalności. Tak, mógłbym mieć milion argumentów słów kluczowych, a nawet więcej wyrażeń if W funkcji, ale myślałem raczej o podejściu obiektowym.

Na przykład mam stronę, która wyświetla użytkownika. Ta strona jest bardzo podobna do strony, która wyświetla grupę, ale nadal nie jest tak podobna do po prostu użyj innego modelu danych. Grupa ma również członków itp...

One sposobem byłoby wskazywanie widoków na metody klasy, a następnie Rozszerzanie tej klasy. Czy ktoś próbował tego podejścia lub ma jakiś inny pomysł?

Author: Community, 2008-08-03

9 answers

Stworzyłem i użyłem własnych generic view classes, definiując __call__ tak więc instancja klasy jest wywoływalna. Bardzo mi się podoba; podczas gdy widoki generyczne Django pozwalają na pewne dostosowywanie poprzez argumenty słów kluczowych, widoki generyczne oo (jeśli ich zachowanie jest podzielone na kilka oddzielnych metod) mogą mieć znacznie bardziej drobnoziarniste dostosowywanie poprzez podklasowanie, co pozwala mi powtarzać się o wiele mniej. (Mam dość przepisywania tej samej logiki tworzenia/aktualizacji widoku w każdej chwili, gdy muszę dostosować coś, czego ogólne poglądy Django nie pozwalają).

Wrzuciłem jakiś kod na djangosnippets.org .

Jedynym prawdziwym minusem, jaki widzę, jest mnożenie wewnętrznych wywołań metod, które mogą nieco wpłynąć na wydajność. Nie sądzę, że jest to duże zmartwienie; rzadko zdarza się, że wykonywanie kodu Pythona byłoby wąskim gardłem wydajności w aplikacji internetowej.

UPDATE : własne ogólne widoki Django są teraz oparte na klasach.

UPDATE : FWIW, Od czasu napisania tej odpowiedzi zmieniłem zdanie na temat poglądów klasowych. Po intensywnym użyciu ich w kilku projektach, czuję, że prowadzą one do kodu, który jest zadowalająco suchy do napisania, ale bardzo trudny do odczytania i utrzymania później, ponieważ funkcjonalność jest rozłożona na tak wiele różnych miejsc, a podklasy są tak zależne od każdego szczegółu implementacji superklas i mixinów. Teraz czuję, że TemplateResponse i view decorators jest lepszą odpowiedzią na rozkładanie kodu widoku.

 42
Author: Carl Meyer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-15 20:39:59

Musiałem używać widoków opartych na klasach, ale chciałem móc używać pełnej nazwy klasy w moim Urlconfie bez konieczności tworzenia instancji klasy widoku przed jej użyciem. To, co mi pomogło, to zaskakująco prosta metaklasa: {]}

class CallableViewClass(type):
    def __call__(cls, *args, **kwargs):
        if args and isinstance(args[0], HttpRequest):
            instance = super(CallableViewClass, cls).__call__()
            return instance.__call__(*args, **kwargs)
        else:
            instance = super(CallableViewClass, cls).__call__(*args, **kwargs)
            return instance


class View(object):
    __metaclass__ = CallableViewClass

    def __call__(self, request, *args, **kwargs):
        if hasattr(self, request.method):
            handler = getattr(self, request.method)
            if hasattr(handler, '__call__'):
                return handler(request, *args, **kwargs)
        return HttpResponseBadRequest('Method Not Allowed', status=405)

Mogę teraz zarówno instantiate view classes jak i używać instancji jako funkcji widoku, lub mogę po prostu skierować mój URLconf do mojej klasy i poprosić metaclass instantiate (i wywołać) klasę widoku dla mnie. Działa to poprzez sprawdzenie pierwszego argumentu __call__ – jeśli jest to HttpRequest, musi to być rzeczywiste żądanie HTTP, ponieważ nonsensem byłoby dołączanie instancji klasy view do instancji HttpRequest.

class MyView(View):
    def __init__(self, arg=None):
        self.arg = arg
    def GET(request):
        return HttpResponse(self.arg or 'no args provided')

@login_required
class MyOtherView(View):
    def POST(request):
        pass

# And all the following work as expected.
urlpatterns = patterns(''
    url(r'^myview1$', 'myapp.views.MyView', name='myview1'),
    url(r'^myview2$', myapp.views.MyView, name='myview2'),
    url(r'^myview3$', myapp.views.MyView('foobar'), name='myview3'),
    url(r'^myotherview$', 'myapp.views.MyOtherView', name='otherview'),
)

(zamieściłem do tego fragment na http://djangosnippets.org/snippets/2041/)

 13
Author: Erik Allik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-05-31 15:54:36

Jeśli po prostu wyświetlasz dane z modeli, dlaczego nie użyć Generic Views Django ? Są one zaprojektowane tak, aby umożliwić łatwe wyświetlanie danych z modelu bez konieczności pisania własnego widoku i rzeczy o mapowaniu parametrów URL do widoków, pobieraniu danych, obsłudze przypadków brzegowych, renderowaniu danych itp.

 10
Author: rossp,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-12 19:06:48

Zawsze możesz utworzyć klasę, nadpisać __call__ funkcji, a następnie skierować plik URL do instancji klasy. Możesz spojrzeć na klasę FormWizard , aby zobaczyć, jak to się robi.

 3
Author: dguaraglia,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-15 20:41:16

Wygląda na to, że próbujesz łączyć rzeczy, których nie należy łączyć. Jeśli chcesz wykonać inne przetwarzanie w widoku w zależności od tego, czy jest to obiekt użytkownika lub grupy, na który próbujesz spojrzeć, powinieneś użyć dwóch różnych funkcji widoku.

Z drugiej strony mogą istnieć typowe idiomy, które chcesz wyodrębnić z widoków typu object_detail... może przydałby ci się dekorator lub po prostu funkcje pomocnicze?

-Dan

 2
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-03 17:40:25

Jeśli nie chcesz zrobić czegoś skomplikowanego, użyj ogólnych widoków. Są one znacznie potężniejsze, niż sugeruje ich nazwa, a jeśli tylko wyświetlasz dane modelu, ogólne widoki wykonają zadanie.

 2
Author: Harley Holcombe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-11 22:59:42

Ogólne widoki zazwyczaj będą dobrym rozwiązaniem, ale ostatecznie możesz obsługiwać adresy URL w dowolny sposób. FormWizard działa w sposób klasowy, podobnie jak niektóre aplikacje dla interfejsów API RESTful.

Zasadniczo z adresem URL otrzymujesz kilka zmiennych i miejsce na dostarczenie funkcji wywołującej, to, co możesz wywołać, zależy całkowicie od Ciebie - standardowym sposobem jest dostarczenie funkcji - ale ostatecznie Django nie nakłada żadnych ograniczeń na to, co robisz.

Zgadzam się, że jeszcze kilka przykładów Jak to zrobić byłoby dobre, FormWizard jest prawdopodobnie miejscem, aby zacząć choć.

 1
Author: Andrew Ingram,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-23 19:05:51

Jeśli chcesz dzielić wspólną funkcjonalność między stronami, proponuję spojrzeć na niestandardowe tagi. Są dość łatwe do stworzenia i są bardzo potężne.

Również szablony mogą rozszerzać się z innych szablonów . Dzięki temu możesz mieć podstawowy szablon, aby skonfigurować układ strony i udostępnić go między innymi szablonami, które wypełniają puste pola. Możesz zagnieżdżać szablony do dowolnej głębokości; pozwalając określić układ na oddzielnych grupach powiązanych stron w jednym miejsce.

 1
Author: Andrew Wilkinson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-12 19:05:51

Możesz użyć ogólnych widoków Django. Możesz łatwo osiągnąć pożądaną funkcjonalność poprzez ogólne widoki Django

 1
Author: Varun Chadha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-08 05:53:09