No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Curso Básico de Django

Curso Básico de Django

Facundo García Martoni

Facundo García Martoni

Implementando generic views en la aplicación

28/29
Recursos

Aportes 26

Preguntas 14

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

o inicia sesión.

Haciendo uso de OOP podemos redicir aun mas el problema de DRY haciendo uso de la herencia

class DetailView(generic.DetailView):
    model = Question
    template_name = "polls/details.html"


class ResultView(DetailView):
    template_name = "polls/results.html"

¿Cuando usar Generic views ?
 
Usar solo si podemos seguir el patrón:

  • Cargar de la base de datos
  • Generar template
  • Mostrarlo

|
Si en la lógica debemos implementar cosas más complejas hay que utilizar Function views.
 
Les dejo el código de todo el proyecto en mi GitHub
https://github.com/xtiv/encuesta_crypto/tree/main/awardsRanking

Comentarios en VSC:

CTRL + K + C
CTRL + K + U

Acá algo interesante. En mi modelo Question yo le puse el nombre “Published Date” al atributo pub_date

class Question(models.Model):
    question_text = models.CharField(max_length=255)
    pub_date = models.DateTimeField(default=timezone.now, name="Published Date")
...

Luego al llamar a la función order_by me decía que no existía ‘pub_date’ como field y dentro de las opciones figuraba Published Date

Cannot resolve keyword 'pub_date' into field. Choices are: Published Date, choice, id, question_text

Por lo que la view la tuve que escribir así:

    def get_queryset(self):
        """Return the last published questions"""
        return Question.objects.order_by('-Published Date')[:5]

Para importar de manera individual cada generic puedes hacer lo siguiente:

from django.views.generic import ListView, DetailView

Cuando cambie de funciones a clases, mis templates no eran localizados por el broswer, me decia que no encontraba Question_list.html, y ese file no existe.

Lo arregle asi: Primero borre los atributos template_view y context_object_name de cada clase en "views’, y luego las puse en ‘urls’, como argumentos de cada url

Ejemplo:

urls.py-----------
urlpatterns = [
    #ex: /polls/
    path("", views.IndexView.as_view(template_name="polls/index.html", context_object_name= "latest_questions_list"), name="index"),
    #ex: /polls/5/
    path("<int:pk>/", views.DetailView.as_view(template_name="polls/detail.html"), name="detail"),
]

views.py-----------
class IndexView(generic.ListView):
    def get_queryset(self):
        """Returns the last five published questions"""
        return Question.objects.order_by("-pub_date")[:5]

class DetailView(generic.DetailView):
    model = Question

Esto funciono, y luego por curiosidad decidi retornarlo a la normalidad (corte los atributos que puse en los links de ‘urls’, y los pegue denuevo en las classes de ‘views’, donde estaban al darme error)

Por alguna razon, ya no me salia el mismo error, aunque puse todo de la misma manera que me dio el error.

Tal vez como el browser logro conectarse con mi primer arreglo (moviendo los atributos a ‘urls’), eso ayudo, o talvez porque copie y pegue en ‘views’ en vez de escribirlos, no estoy seguro.

Ya que las dos clases (DetailView, ResultView) hacen exactamente los mismo y lo que cambia son los valores de los atributos, podemos definir una sola clase y esos valores pasarlos como parámetros. Después que empecé a hacerlo me di cuenta que en ningún momento se instancia la clase, así que donde se pueden pasar esos valores?. Revisé un poco y resulta que se le puden pasar al método as_view() que invocamos en urls. Así quedó el código.

De esta forma la clase se puede reutilizar incluso si el módelo también cambia. Por ejemplo cuando implementemos el crud con Choice.

// Esta es la clase, la cual hereda de django.views.generic.DetailView
class CustomBaseDetailView(DetailView):
    def __init__(self, model, template_name):
        super().__init__()
        self.model = model
        self.template_name = template_name

// Esta es la definición del path en urls.py
path(
        '<int:pk>/',
        views.CustomBaseDetailView.as_view(model=Question, template_name='polls/detail.html'),
        name='detail'
    )

Si se puede:

  • Generic views.
    Si podemos seguir el patrón:
    • cargar datos de la base de datos
    • Generar template
    • Mostrar template

Si no se pude:

  • Functions based views.
    Escaparse del patrón anterior. Si es mas complejo, como mostrar 2 formularios en la misma página

Excelente curso, Y eso que apenas es el basico, no me imagino los que vendrán

Lo ideal es utilizar generic views en caso de que existan o Django nos la brinde, son un recurso muy útil.

def vote(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    try:
        selected_choice = question.choice_set.get(pk=request.POST["choice"])
    
    except (KeyError, Choice.DoesNotExist):
        template = 'polls/detail.html'
        context = {
            'question': question,
            'error_message': 'No elegiste una respuesta',
        }
        return render(request, template, context)
    
    else:
        selected_choice.votes += 1
        selected_choice.save()
        
        viewname = 'polls:results'
        context = {
            'pk': question.id
        }
        
        return HttpResponseRedirect(reverse(viewname, kwargs=context))

En la función vote del archivo views, hay que actualizar los argumentos, antes estaba con la variable ‘question_id’ y ahora vamos a utilizar la variable ‘pk’. Si no se hace este cambio, aparece error al momento de votar.

Generic Views

DRY: Don´t Repeat Yourself

Hasta ahora hemos programado Class Based Views, lo que podemos observar en el archivo views.py es que por ejemplo las funciones results y detail son exactamente iguales, por lo que estaríamos incumpliendo el principio DRY.
Las generic views nos permiten evitar caer en este error, estas funcionan por clases y existen multiples que se adaptan a distintos casos, actualización, login, formularios, etc. (info completa en los links de referencia)

Example: vamos a cambiar las vistas que tenemos definidas por funciones a generic views:
En el archivo views.py

# generic views
from django.views import generic

class IndexView(generic.ListView):
    template_name = "polls/index.html"
    context_object_name = "latest_question_list"

    def get_queryset(self):
        return Question.objects.order_by("-pub_date")[:5]


class DetailView(generic.DetailView):
    model = Question
    template_name = "polls/detail.html"



class ResultView(generic.DetailView):
    model = Question
    template_name = "polls/results.html"

la función vote no se cambia por una clase porque es muy compleja.
Las clase de las vistas genéraicas deben siempre cumplir con estas reglas en su nombre: Empezar en mayúscula porque son una clase y terminar en View, esto es una buena práctica

Se le debe hacer saber al archivo urls.py que debe reconocer clases en vez de funciones:

    # ex: /polls/
    path("", views.IndexView.as_view(), name="index"),
    # ex: /polls/5/
    path("<int:pk>/", views.DetailView.as_view(), name="detail"),
    path("<int:pk>/results/", views.ResultView.as_view(), name="results"),

Mucho love muchachosss 💚 terminamos el curso :33

IndexView tambien lo podriamos reescribir asi:

class IndexView(generic.ListView):
	template_name = "polls/index.html"
	context_object_name = "latest_question_list"
	model = Question
	ordering = "-pub_date"
	paginate_by = 5

Al revisar un poco el modelo ListView hay un monton de métodos y atributos configurables para “no reinventar la rueda”. Son diferentes opciones que tenemos al momento de desarrollar.

para comentar código seleccionado solo presionar Ctrl + }

Una alternativa para comentar en archivos Python es usar 3 comillas sencillas de apertura y 3 comillas sencillas de cierre, aqui el ejemplo:

'''
def index(request):
    latest_question_list = Question.objects.all()
    return render(request, "polls/index.html", {"latest_question_list": latest_question_list})


def detail(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    return render(request, "polls/detail.html", {"question": question})

def result(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    return render(request, "polls/result.html", {"question": question})
'''

Como desarrollador de Node.js, estoy sorprendido y feliz de conocer las generic views de Django 😃

Para comentar en visual studio code es necesario presionar ctrl+k y mantener presionado ctrl+c

Para comentar código Django pueden utilizarlos el atajo CTRL + }

Para comentar parrafos de código se puede usar “”" código de python “”"

¿Cuándo usar Generic y Function views?

Si sigues el modelo de la BBDD, usa Generic Views. Si haces algo más complejo, usa Function-based views.

Si se puede, Generic, si no se puede, Function.

Se ve mas sencillo así!

Excelente curso mil gracias

Para comentar varias lineas de código a la vez lo puedes hacer con:

  • selecciona el código a comentar
  • preciona ctrl + shift + 7
    Listo!!

Cuándo usar Generic Views o Fuctions based views

Curso Básico de Django
Pero bien consistentes estas bases aprendidas hasta ahora.

  • Clase: DateDetailView
    Vista de un objeto en una fecha; difiere del DetailView estándar aceptando una fecha con formato: year/month/day en la URL.
from django.views.generic import DateDetailView