Aún no tienes acceso a esta clase

Crea una cuenta y continúa viendo este curso

CreateView, FormView y UpdateView

30/37
Recursos

En esta clase incorporamos la paginación de posts utilizando page_obj, bootstrap y variables del contexto. Adicionalmente resolvemos el reto de la clase anterior usando DetailView. Remplazamos render y redirect por CreateView para los posts. Implementaremos FormView en sustitución del formulario de registro Signup que teníamos hasta ahora con el fin de optimizar el código y finalmente optimizamos la vista de actualización del perfil con UpdateView.

Aportes 32

Preguntas 19

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesión.

Interesante… pero siento que las class-views son más difíciles de leer y eso me causa estrés y toc tengo que recurrir mucho a la documentación que no está mal, pero luego no encuentro lo que necesito asi que voy a Stack Overflow preguntó intento entender el código pero no lo comprendo del todo así que lo copeo y siento que no entiendo una mie*/$, perdón la expresión pero con las funcions-views todo es más sencillo es decir tengo el control y sé que estoy haciendo
¿No les parece?

¡Hola! Fui uno de los pocos a los que no les funcionó la ClassView “CreatePostView”. Por lo cual, dejo como aporte una clase que si funciona correctamente 😉

class CreatePostView(LoginRequiredMixin, CreateView):
    """Create a new post"""

    model = Post
    template_name = 'posts/new.html'
    # form_class = PostForm
    fields = ['title', 'photo']

    def form_valid(self, form):
        form.instance.user = self.request.user
        form.instance.profile = self.request.user.profile
        print(form)
        form.save()
        return super(CreatePostView, self).form_valid(form)

    def get_success_url(self):
        return reverse('posts:feed')

Si quieren redirigir el signup con clases al feed, lo pueden hacer de la siguiente manera:


class SignUpView(FormView):
    """Users signup view"""
    template_name = "users/signup.html"
    form_class = SignupForm
    success_url = reverse_lazy('posts:feed')

    def form_valid(self, form):
        form.save()

        username = form['username'].value()
        password = form['password'].value()

        user = authenticate(
            self.request, username=username, password=password)
        
        login(self.request, user)

        return super().form_valid(form)

Lamentablemente cuando se elimina ProfileForm, también se quitan todas las validaciones del formulario, como que la foto sea obligatoria, el teléfono sea numérico y demás. ¿Que se debería colocar para que funcione? Ya que me aparece el siguiente error si deseo usar ProfileForm.

__ init __() got an unexpected keyword argument ‘instance’

Hola. Si queremos poner las clases de bootstrap desde la vista, en lugar de ponerlas en el html se puede hacer lo siguiente:

class UpdateProfileView(LoginRequiredMixin, UpdateView):
    """Update profile."""
    template_name = 'users/update_profile.html'
    model = Profile
    fields = ['website', 'biography', 'phone_number', 'picture']

    def get_object(self):
        """Return user's profile."""
        return self.request.user.profile

    def get_success_url(self):
        """Return to user's profile"""
        username = self.object.user.username
        return reverse('users:detail', kwargs={'username': username})

    def get_form(self, form_class=None):
        form = super().get_form(form_class)
        form.fields['website'].widget.attrs.update({
            'class': 'form-control'})
        form.fields['biography'].widget.attrs.update({
            'class': 'form-control',
            'rows': 3})
        form.fields['phone_number'].widget.attrs.update({
            'class': 'form-control'})
        return form```


Toda esta transición a Class Based Views lo hemos hecho para utilizar cosas mas estándares del Framework, pero falta algo que no hemos solucionado como falla en el sistema y es:

{# templates/posts/create_post.html #}
<input type="text" name="user" value="{{ user.pk}}" hidden />
<input type="text" name="profile" value="{{ profile.pk }}" hidden />

Esto es una falla de seguridad y no hemos resuelto con las Classs Bases Views, cuál es la manera de resolverlo?

Debería de haber estructurado el curso para no estar borrando lo que habíamos hecho, ya que para nosotros es documentacion…

Aaaaaaaaa siento que estoy haciendo click con django y es maravilloso.

Tengo una pequeñísima duda, ¿qué es lo que hacía el context_object_name?

Para que la SignupView tenga las clases de cualquier Framework css pueden realizar lo siguiente:

en el archivo de users/forms.py agregar widgets a todos los campos, en mi caso hice esto:

class SignupForm(forms.Form):
    """Signup From."""

    first_name = forms.CharField(
        min_length=3,
        max_length=50,
        widget=forms.TextInput(attrs={'class': 'input'})
    )

    last_name = forms.CharField(
        min_length=3,
        max_length=50,
        widget=forms.TextInput(attrs={'class': 'input'})
    )

    username = forms.CharField(
        min_length=4,
        max_length=50,
        widget=forms.TextInput(attrs={'class': 'input'})
    )

    email = forms.CharField(
        min_length=6,
        max_length=70,
        widget=forms.EmailInput(attrs={'class': 'input'})
    )

    password = forms.CharField(
        min_length=8,
        widget=forms.PasswordInput(attrs={'class': 'input'})
    )

    password_confirmation = forms.CharField(
        min_length=8,
        widget=forms.PasswordInput(attrs={'class': 'input'})
    )

Mi Post CreateView 😄

class PostCreateView(LoginRequiredMixin, CreateView):
    model = Post
    form_class = PostForm
    success_url = reverse_lazy('posts:list')

    def form_valid(self, form):
        _object = form.save(commit=False)
        _object.user = self.request.user
        _object.profile = self.request.user.profile
        self.object = _object.save()
        return super(PostCreateView, self).form_valid(form)

Tenia problemas para que me funcionara el CreatePostView ya que el post no guardaba y me redirigia al formulario de new.html. Al inspeccionar con el navegador el formulario, vi que no estaba recibiendo ningún valor en el input que se llevaba el id del profile. La solución que me funcióno fue cambiar en el value del input profile . pk por user . profile . pk

de esto:

<input type="hidden" name="Profile" value="{{profile.pk}}" />

a esto:

<input type="hidden" name="Profile" value="{{ user.profile.pk }}" />

Increíble como se ahorra código con los GENERIC EDIT

Cuando ingreso al feed de un usuario, y cliqueo en una imagen, me tira el siguiente error:

NoReverseMatch at /posts/3/

Reverse for ‘detail’ with arguments ‘(’’,)’ not found. 2 pattern(s) tried: [‘users/(?P<username>[^/]+)/$’, ‘users/(?P<username>[^/]+)/$’]

Request Method: GET
Request URL: http://localhost:8000/posts/3/
Django Version: 2.1.7
Exception Type: NoReverseMatch
Exception Value:

Reverse for ‘detail’ with arguments ‘(’’,)’ not found. 2 pattern(s) tried: [‘users/(?P<username>[^/]+)/$’, ‘users/(?P<username>[^/]+)/$’]

Exception Location: C:.env\lib\site-packages\django\urls\resolvers.py in _reverse_with_prefix, line 622
Python Executable: C:.env\Scripts\python.exe
Python Version: 3.7.2
Python Path:

[‘C:\.env\platzi’,
‘C:\Users\Enzo\AppData\Local\Programs\Python\Python37\python37.zip’,
‘C:\Users\Enzo\AppData\Local\Programs\Python\Python37\DLLs’,
‘C:\Users\Enzo\AppData\Local\Programs\Python\Python37\lib’,
‘C:\Users\Enzo\AppData\Local\Programs\Python\Python37’,
‘C:\.env’,
‘C:\.env\lib\site-packages’]

Server time: Mon, 4 Mar 2019 20:49:50 +0000
Error during template rendering

In template C:.env\platzi\templates\posts\post_card.html, error at line 3
Reverse for ‘detail’ with arguments ‘(’’,)’ not found. 2 pattern(s) tried: [‘users/(?P<username>[^/]+)/$’, ‘users/(?P<username>[^/]+)/$’]
1 <div class=“col-sm-12 col-md-8 offset-md-2 mt-5 p-0 post-container”>
2 <div class=“media pt-3 pl-3 pb-1”>
3 <a href="{% url “users:detail” post.user.username %}">

Mi post_card.html es el siguiente:

<div class="col-sm-12 col-md-8 offset-md-2 mt-5 p-0 post-container">
    <div class="media pt-3 pl-3 pb-1">
        <a href="{% url "users:detail" post.user.username %}">
            <img class="mr-3 rounded-circle" height="35" src="{{ post.profile.picture.url }}" alt="{{ post.user.get_full_name }}">
        </a>
        <div class="media-body">
            <p style="margin-top: 5px;">{{ post.user.get_full_name  }}</p>
        </div>
    </div>

    <img style="width: 100%;" src="{{ post.photo.url }}" alt="{{ post.title }}">

    <p class="mt-1 ml-2" >
        <a href="" style="color: #000; font-size: 20px;">
            <i class="far fa-heart"></i>
        </a> 30 likes
    </p>
    <p class="ml-2 mt-0 mb-2">
        <b>{{ post.title }}</b> - <small>{{ post.created }}</small>
    </p>
</div>```

Entiendo que el error esta asociado con al definicion de las url, pero no lo logro encontrar. Agradezco una ayuda! Gracias!



¿Si quiero validar el formulario de “update_profile” que método debo de utilizar?
-ModelFormMixin
-FormMixin
(no entiendo la diferencia)
Este es mi método:

@login_required
def update_profile(request):
    """ Update a users's profile view. """
    profile = request.user.profile

    if request.method == 'POST':
        # form is a instance of ProfileForm with request
        # request.FILES es utilizado para recibir los archivos, desde el FORM enctype="multipart/form-data"
        form = ProfileForm(request.POST, request.FILES)
        
        #print(form.cleaned_data)
        if form.is_valid():
            #print(form.cleaned_data)
            data = form.cleaned_data
            profile.website = data['website']
            profile.phone_number = data['phone_number']
            profile.biografy = data['biografy']
            #profile.picture = data['picture']
            #print("error------------------------------------------- {}".format(data['picture']))
            if data['picture'] == None:
                pass
            else:
                profile.picture = data['picture']
            profile.save()

            # Creacion de una url con kwargs: from django.urls import reverse
            url = reverse('users:detail', kwargs={'username': request.user.username})
            return redirect(url)

        else:
            print("NO++++++++++++++++++++++++++++++++++++++++++++++++++")
    else:
        form = ProfileForm()

    return render(
        request=request, 
        template_name='users/update_profile.html',
        context={
            'profile': profile,
            'user': request.user,
            'form': form
        }
    )```

Para usar CreateView, tienes que usar ModelForm(forms.ModelForm). Yo hice mi formulario con Form(forms.Form) y no funciona. Y no puede funcionar, porque Model form toma un argumento opcional llamado “instance”, el cual no es un argumento valido para no-ModelForms y CreateView pasa dicho argumento, causando el error.

Creo que en esta clase me quedo bastante claro por que las class-based views son mejor opcion que las vistas con funciones

Una consulta no se porque motivo es que cuando coloco una imagen esta no queda derecha, es decir queda acostada. Como puedo hacer para lograr que quede derecha??

Y si hay mas de un kwarg?

Quiero hacer un DeleteView pero no quiero colocar el ID en el slug, sino que quiero pasarlo por POST en un form, y el ID pasarlo por un <hidden>, se puede hacer eso?
quiero hacer eso para ocultar un poco mas la el ID y que simplemente no salga en el slug

TEMPLATE

<form action="{% url "delete_url" %}" method="post">
	{% csrf_token %}
	<input type="hiden" name="pk" value={{ model.pk }}
	<button type="submit">Delete</button>
</form>

URLS

#note i dont want slug
path("delete_view", views.delete_view.as_view(), name="delete_url")

VIEWS

class delete_view(DeleteView):
	model=ModelName
	success_url = reverse_lazy("success_url")

Hola, para que en el html no pasemos campos ocultos con el valor de user y profile les comparto esta solución. Saludos.

class CreatePostView(LoginRequiredMixin, CreateView):
    """Create a new post."""
    template_name = 'posts/new.html'
    form_class = PostForm
    success_url = reverse_lazy('posts:feed')

    def get_form(self, form_class=None):
        """Return an instance of the form to be used in this view."""
        kwargs = self.get_form_kwargs()

        post = self.request.POST.copy()
        post['user'] = self.request.user
        post['profile'] = self.request.user.profile

        kwargs.update({'data': post})

        if form_class is None:
            form_class = self.get_form_class()
        return form_class(**kwargs)

uff Django tiene muchas formas de hacer las cosas y de seguir optimizando!! eso es GREAT!!!

Los Class-based views encapsulan la lógica de los endpoints que tienen características comunes. Por ejemplo, nos ahorra la verificación del método, validación de formularios entre otras tareas. Esas tareas las realiza las class-based views.

¿Les paso que cuando iban al detalle del post cargaba el mismo pk?, no se si es un detalle del paginador

Increíble lo que ya viene por default en django, parece magia. Brutal.

Para darle estilo al formulario de SignUp lo que yo hice fue agregar la propiedad “label” y “widget” cuando definía los fields del formulario. Queda algo así

users/forms.py

class SignupForm(forms.Form):
    """Sign up form."""
    
    username = forms.CharField(
    label=False,
    min_length=4,
    max_length=50,
    widget = forms.TextInput(
        attrs={
            'placeholder':'Username',
            'class': 'form-control',
            'required': True}
        )
    )

    password = forms.CharField(
    label=False,
    min_length=8,
    max_length=70,
    widget = forms.PasswordInput(
        attrs={
            'placeholder':'Password',
            'class': 'form-control',
            'required': True}
        )
    )
    password_confirmation = forms.CharField(
    label=False,
    min_length=8,
    max_length=70,
    widget = forms.PasswordInput(
        attrs={
            'placeholder':'Password confirmation',
            'class': 'form-control',
            'required': True}
        )
    )

    first_name = forms.CharField(
    label=False,
    min_length=4,
    max_length=50,
    widget = forms.TextInput(
        attrs={
            'placeholder':'First name',
            'class': 'form-control',
            'required': True}
        )
    )
    last_name = forms.CharField(
    label=False,
    min_length=4,
    max_length=50,
    widget = forms.TextInput(
        attrs={
            'placeholder':'Last name',
            'class': 'form-control',
            'required': True}
        )
    )

    email = forms.CharField(
    label=False,
    min_length=4,
    max_length=50,
    widget = forms.EmailInput(
        attrs={
            'placeholder':'Email',
            'class': 'form-control',
            'required': True}
        )
    )

    def clean_username(self):
        """Username must be unique."""
        username = self.cleaned_data['username']
        username_taken = User.objects.filter(username=username).exists()
        if username_taken:
            raise forms.ValidationError('Username is already in use.')
        return username

    def clean(self):
        """Verify password confirmation match."""
        data = super().clean()

        password = data['password']
        password_confirmation = data['password_confirmation']

        if password != password_confirmation:
            raise forms.ValidationError('Passwords do not match.')

        return data

    def save(self):
        """Create user and profile."""
        data = self.cleaned_data
        data.pop('password_confirmation')

        user = User.objects.create_user(**data)
        profile = Profile(user=user)
        profile.save()
 

Ya realmente en este punto se esta volviendo mas complicado y tedioso de leer intento entender pero a la final se hace muy complicado y no quiero soalmente copiar y pegar codigo quiero practicar pero la forma en que lo hacen es dificil.

me gusto mucho la clase pero creo que las class-view no deberian haber estado en el curso basico de django, hace demasiado dificil poder continuar

Las class-view si que fueron un verdadero reto. Aun no logro entenderlas completamente he estado metido en la documentacion durante horas y he practicado con mis proyectos personales.

Diferencia que noto entre reverse y reverse_lazy.
Puede darse el caso donde los imports no hayan terminado de hacerse, y si se importa alguna URL con reverse, al no haberse importado aún dicha URL reverse dará error. (Puede ser el orden de como se plantean los imports en la cabecera de los archivos).

En ese caso, cuando sucede ese error se puede usar reverse_lazy que espera que se carguen toooodos los archivos de django para finalmente se ejecuta el reverse_lazy teniendo un response exitoso de URL porque se esperó que se cargara para ejecutar la funcion que apunta a la URL.

Espero haberme explicado 🥰

este el el view de users

"""Users views."""

# Django
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import render, redirect
from django.urls import reverse, reverse_lazy
from django.views.generic import DetailView, FormView, UpdateView

# Models
from django.contrib.auth.models import User
from posts.models import Post
from users.models import Profile

# Forms
from users.forms import SignupForm


class UserDetailView(LoginRequiredMixin, DetailView):
    """User detail view."""

    template_name = 'users/detail.html'
    slug_field = 'username'
    slug_url_kwarg = 'username'
    queryset = User.objects.all()
    context_object_name = 'user'

    def get_context_data(self, **kwargs):
        """Add user's posts to context."""
        context = super().get_context_data(**kwargs)
        user = self.get_object()
        context['posts'] = Post.objects.filter(user=user).order_by('-created')
        return context


class SignupView(FormView):
    """Users sign up view."""

    template_name = 'users/signup.html'
    form_class = SignupForm
    success_url = reverse_lazy('users:login')

    def form_valid(self, form):
        """Save form data."""
        form.save()
        return super().form_valid(form)


class UpdateProfileView(LoginRequiredMixin, UpdateView):
    """Update profile view."""

    template_name = 'users/update_profile.html'
    model = Profile
    fields = ['website', 'biography', 'phone_number', 'picture']

    def get_object(self):
        """Return user's profile."""
        return self.request.user.profile

    def get_success_url(self):
        """Return to user's profile."""
        username = self.object.user.username
        return reverse('users:detail', kwargs={'username': username})


def login_view(request):
    """Login view."""
    if request.method == 'POST':
        username = request.POST['username']
        password = request.POST['password']
        user = authenticate(request, username=username, password=password)
        if user:
            login(request, user)
            return redirect('posts:feed')
        else:
            return render(request, 'users/login.html', {'error': 'Invalid username and password'})

    return render(request, 'users/login.html')


@login_required
def logout_view(request):
    """Logout a user."""
    logout(request)
    return redirect('users:login')

En esta clase incorporamos la paginación de posts utilizando page_obj, bootstrap y variables del contexto. Adicionalmente resolvemos el reto de la clase anterior usando DetailView. Remplazamos render y redirect por CreateView para los posts. Implementaremos FormView en sustitución del formulario de registro Signup que teníamos hasta ahora con el fin de optimizar el código y finalmente optimizamos la vista de actualización del perfil con UpdateView.