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 鈥淐reatePostView鈥. 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 鈥榠nstance鈥

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 鈥榙etail鈥 with arguments 鈥(鈥欌,)鈥 not found. 2 pattern(s) tried: [鈥榰sers/(?P<username>[^/]+)/$鈥, 鈥榰sers/(?P<username>[^/]+)/$鈥橾

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

Reverse for 鈥榙etail鈥 with arguments 鈥(鈥欌,)鈥 not found. 2 pattern(s) tried: [鈥榰sers/(?P<username>[^/]+)/$鈥, 鈥榰sers/(?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:

[鈥楥:\.env\platzi鈥,
鈥楥:\Users\Enzo\AppData\Local\Programs\Python\Python37\python37.zip鈥,
鈥楥:\Users\Enzo\AppData\Local\Programs\Python\Python37\DLLs鈥,
鈥楥:\Users\Enzo\AppData\Local\Programs\Python\Python37\lib鈥,
鈥楥:\Users\Enzo\AppData\Local\Programs\Python\Python37鈥,
鈥楥:\.env鈥,
鈥楥:\.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 鈥榙etail鈥 with arguments 鈥(鈥欌,)鈥 not found. 2 pattern(s) tried: [鈥榰sers/(?P<username>[^/]+)/$鈥, 鈥榰sers/(?P<username>[^/]+)/$鈥橾
1 <div class=鈥渃ol-sm-12 col-md-8 offset-md-2 mt-5 p-0 post-container鈥>
2 <div class=鈥渕edia pt-3 pl-3 pb-1鈥>
3 <a href="{% url 鈥渦sers: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 鈥渦pdate_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 鈥渋nstance鈥, 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 鈥渓abel鈥 y 鈥渨idget鈥 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.