Saturday, 27 April 2019

django 31 update user profile, password

logged in as bob, show bob's posts

click update profile, change username to bobby

profile updated, select bobby's posts

display all bobby's posts (originally bob's)

select change password, error if old password not match

all field entered right, password updated, bobby still logged in

log out bobby, and log in again with new password

login successful

#urls

from django.urls import path
from . import views

app_name = 'music'

urlpatterns = [
    path('', views.IndexView.as_view(), name='index'),

    path('register/', views.UserRegistration.as_view(), name='register'),

    path('editProfile/', views.UserProfileUpdate.as_view(), name='profile-update'),

    path('changePassword/', views.UserPasswordUpdate, name='password-update'),

    path('login/', views.UserLogin.as_view(), name='login'),

    path('logout/', views.UserLogout, name='logout'),

    #/music/id/
    path('<pk>/', views.DetailView.as_view(), name='detail'),

    #music/album/add/
    path('album/add/', views.AlbumCreate.as_view(), name='album-add'),

    #music/album/id/
    path('album/<pk>/', views.AlbumUpdate.as_view(), name='album-update'),

    #music/album/id/delete/
    path('album/<pk>/delete/', views.AlbumDelete.as_view(), name='album-delete'),

    #music/song/add/
    path('song/<album_pk>/add/', views.SongCreate.as_view(), name='song-add'),

    #music/song/id/
    path('song/<album_pk>/<pk>/', views.SongUpdate.as_view(), name='song-update'),

    #music/song/id/delete/
    path('song/<album_pk>/<pk>/delete/', views.SongDelete.as_view(), name='song-delete'),
]

-------------------------------------------------------------
#views

from django.views import generic
from .models import Album, Song
from django.views.generic.edit import  CreateView, UpdateView, DeleteView, View
from django.urls import reverse_lazy
from django.shortcuts import render, redirect
from django.contrib.auth import authenticate, login, logout, update_session_auth_hash
from .forms import RegistrationForm, LoginForm, ProfileUpdateForm
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.contrib import messages
from django.contrib.auth.models import User
from django.contrib.auth.forms import PasswordChangeForm
from django.contrib.auth.decorators import login_required

post_num = 4
author_name = None

#get list of username
def get_authors():
    authorNames = []
    for author in User.objects.all():
        authorNames.append(author.username)
    return authorNames

author_names = get_authors()

class IndexView(generic.ListView):
    template_name = 'music/index.html'
    paginate_by = post_num

    def get_paginate_by(self, queryset):
        global post_num
        post_num = self.request.GET.get('postNum', self.paginate_by)
        return post_num

    def get_context_data(self, **kwargs):
        context = super(IndexView, self).get_context_data(**kwargs)
        context['post_num'] = post_num
        context['author_name'] = author_name
        context['all_authors_names'] = author_names
        return context

    def get_queryset(self):
        global author_name
        author_name = self.request.GET.get('userName', None)

        if(author_name not in [None,'None','All']):
            author_id = User.objects.get(username=author_name).pk
            return  Album.objects.filter(author=author_id).order_by('-date_posted')
        else:
            return Album.objects.all()

class DetailView(generic.DetailView):
    model = Album
    template_name = 'music/detail.html'

#protected route, require authentication
class AlbumCreate(LoginRequiredMixin, CreateView):
    model = Album
    fields = ['artist', 'album_title', 'genre', 'album_logo']

    def form_valid(self, form):
        form.instance.author = self.request.user
        return super().form_valid(form)

class AlbumUpdate(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
    model = Album
    fields = ['artist', 'album_title', 'genre', 'album_logo']

    def form_valid(self, form):
        form.instance.author = self.request.user
        return super().form_valid(form)

    def test_func(self):
        album = self.get_object()
        if self.request.user == album.author:
            return True
        return False

class AlbumDelete(LoginRequiredMixin, UserPassesTestMixin, DeleteView):
    model = Album
    #redirect to home page after delete
    success_url = reverse_lazy('music:index')

    def test_func(self):
        album = self.get_object()
        if self.request.user == album.author:
            return True
        return False

#protected route, require authentication
class SongCreate(LoginRequiredMixin, CreateView):
    model = Song
    fields = ['file_type', 'song_title', 'is_favorite']

    #overwrite field['album']
    def form_valid(self, form):
        form.instance.album = Album.objects.get(pk=self.kwargs['album_pk'])
        return super().form_valid(form)

    #pass variable song_album to song_form template
    def get_context_data(self, **kwargs):
        context = super(SongCreate, self).get_context_data(**kwargs)

        song_album = Album.objects.get(pk=self.kwargs['album_pk']).album_title

        context.update({'song_album':song_album})
        return context

class SongUpdate(LoginRequiredMixin, UpdateView):
    model = Song
    fields = ['file_type', 'song_title', 'is_favorite']

    # overwrite field['album']
    def form_valid(self, form):
        form.instance.album = Album.objects.get(pk=self.kwargs['album_pk'])
        return super().form_valid(form)

    # pass variable song_album to song_form template
    def get_context_data(self, **kwargs):
        context = super(SongUpdate, self).get_context_data(**kwargs)

        song_album = Album.objects.get(pk=self.kwargs['album_pk']).album_title

        context.update({'song_album': song_album})
        return context

class SongDelete(LoginRequiredMixin, DeleteView):
    model = Song
    #redirect to detail page after delete
    def get_success_url(self):
        return  reverse_lazy('music:detail',kwargs={'pk': self.kwargs['album_pk']})

#user registration
class UserRegistration(View):
    form_class = RegistrationForm
    template_name = 'music/registration_form.html'

    def get(self, request):
        #get request, display UserForm with empty fields
        form = self.form_class(None)
        return render(request, self.template_name, {'form': form})

    def post(self, request):
        form = self.form_class(request.POST)

        if form.is_valid():

            user = form.save(commit=False)

            #clearned/normalized data
            password = form.cleaned_data['password']

            user.set_password(password)
            user.save()

            messages.success(request, 'registration successful')
            return redirect('music:login')

        return render(request, self.template_name, {'form': form})

#user profile update
class UserProfileUpdate(LoginRequiredMixin, View):
    form_class = ProfileUpdateForm
    template_name = 'music/registration_form.html'

    def get(self, request):
        #get request, display UserForm with prefilled fields
        form = ProfileUpdateForm(instance=self.request.user)
        return render(request, self.template_name, {'form': form})

    def post(self, request):
        form = ProfileUpdateForm(request.POST, instance=self.request.user)

        if form.is_valid():
            form.save()

            #update author_names
            global  author_names
            author_names = get_authors()

            messages.success(request, 'profile updated')
            return redirect('music:index')

        return render(request, self.template_name, {'form': form})

#user password update
@login_required
def UserPasswordUpdate(request):
    if request.method == 'POST':
        form = PasswordChangeForm(request.user, request.POST)
        if form.is_valid():
            user = form.save()
            #keep current user logged in
            update_session_auth_hash(request, user)
            messages.success(request, 'password updated!')
            return redirect('music:index')
        else:
            messages.error(request, 'Please correct the error below.')
    else:
        form = PasswordChangeForm(request.user)

    return render(request, 'music/registration_form.html', {'form': form})

#user login
class UserLogin(View):
    form_class = LoginForm
    template_name = 'music/login_form.html'

    def get(self, request):
        #get request, display UserForm with empty fields
        form = self.form_class(None)
        return render(request, self.template_name, {'form': form})

    def post(self, request):
        form = self.form_class(request.POST)

        if form.is_valid():

            #clearned/normalized data
            username = form.cleaned_data['username']
            password = form.cleaned_data['password']

            #returns User objects if credentials are correct
            user = authenticate(username=username, password=password)

            if user is not None:

                if user.is_active:
                    login(request, user)
                    return redirect('music:index')

        messages.error(request, 'error logging in')
        return render(request, self.template_name, {'form': form})

def UserLogout(request):
    logout(request)
    return redirect('music:index')

--------------------------------------------
#forms

from django.contrib.auth.models import User
from django import forms
from django.contrib.auth.forms import UserChangeForm

class RegistrationForm(forms.ModelForm):
    password = forms.CharField(widget=forms.PasswordInput)

    class Meta:
        model = User
        fields = ['username', 'email', 'password']

class LoginForm(forms.Form):
    username = forms.CharField(widget=forms.TextInput())
    password = forms.CharField(widget=forms.PasswordInput)
    fields = ['username', 'password']

class ProfileUpdateForm(UserChangeForm):
    def __init__(self, *args, **kwargs):
        super(ProfileUpdateForm, self).__init__(*args, **kwargs)
        del self.fields['password']

    class Meta:
        model = User
        fields = ('username','email','first_name','last_name')

--------------------------------------------
#templates/base

<!DOCTYPE html>
{% load static %}
<html lang="en">
<head>
    <meta charset="UTF-8">
    <!-- bootstrap -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/css/bootstrap.min.css">
    <!-- google fonts -->
    <link href="https://fonts.googleapis.com/css?family=Srisakdi" rel="stylesheet">
    <!-- my css -->
    <link rel="stylesheet" type="text/css" href="{% static 'music/style.css' %}">
    <title>{% block title %}Django{% endblock %}</title>
</head>
<body>
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>

    <nav class="navbar navbar-expand-lg navbar-light" style="background-color: #fcefe5;">
        <a class="navbar-brand" style="font-family: 'Srisakdi', serif; font-weight: bold; text-shadow: 4px 4px 4px #aaa;" href="{% url 'music:index' %}">Django</a>

        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarTogglerDemo02" aria-controls="navbarTogglerDemo02" aria-expanded="false" aria-label="Toggle navigation">
         <span class="navbar-toggler-icon"></span>
        </button>

        <div class="collapse navbar-collapse" id="navbarTogglerDemo02">
          <ul class="navbar-nav">
            <li class="nav-item active">
              <a class="nav-link" href="{% url 'music:index' %}"><span class="glyphicon glyphicon-cd" aria-hidden="true"></span>&nbsp Albums</a>
            </li>
            <li class="nav-item">
              <a class="nav-link" href="#"><span class="glyphicon glyphicon-music" aria-hidden="true"></span>&nbsp Songs</a>
            </li>
          </ul>

            <form class="navbar-form navbar-left" role="search" method="get" action="#">
                <div class="form-group">
                    <input type="text" name="q" value=""/>
                </div>
                <button type="submit" >Search</button>
            </form>

            <ul class="navbar-nav navbar-right">
                <li>
                    <a class="nav-link" href="{% url 'music:album-add' %}">
                        <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>&nbsp; Add Album
                    </a>
                </li>
                <li>
                    {% if user.is_authenticated %}

                          <a  class="nav-link" href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                             <span class="glyphicon glyphicon-user" aria-hidden="true"></span>&nbsp; {{user.username}} &#9660
                          </a>

                          <div class="dropdown-menu" aria-labelledby="dropdownMenuLink">
                            <a class="dropdown-item" href="{% url 'music:logout' %}">
                                <span class="glyphicon glyphicon-off" aria-hidden="true"></span>&nbsp; Log out
                            </a>

                              <a class="dropdown-item" href="{% url 'music:profile-update' %}">
                                <span class="glyphicon glyphicon-edit" aria-hidden="true"></span>&nbsp; Update Profile
                            </a>

                              <a class="dropdown-item" href="{% url 'music:password-update' %}">
                                <span class="glyphicon glyphicon-barcode" aria-hidden="true"></span>&nbsp; Change Password
                            </a>
                          </div>

                    {% else %}
                        <a class="nav-link" href="{% url 'music:login' %}">
                            <span class="glyphicon glyphicon-user" aria-hidden="true"></span>&nbsp; Login
                        </a>
                    {% endif %}
                </li>
            </ul>
        </div>
    </nav>

    {% if messages %}
        {% for message in messages %}
            {% if message.tags == 'error' %}
                <div class="alert alert-danger">{{message}}</div>
            {% else %}
                <div class="alert alert-{{message.tags}}">{{message}}</div>
            {% endif %}
        {% endfor %}
    {% endif %}

    {% block body %}
    {% endblock %}
</body>
</html>

reference:
http://chuanshuoge2.blogspot.com/2019/04/django-31-update-user-profile.html

No comments:

Post a Comment