Sunday 31 March 2019

django 25 generic views field overwrite, pass parameter to templates

3 songs in album (the great expense)

click add song, song album field is auto filled (overwritten with current album)

new song created in album

edit last song created, all fields are auto filled , check favorite

last song is updated to favorite

#music/urls
    ...
    #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'),

---------------------------------
#music/views
...
#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']})

------------------------------------
#music/templates/detail

{% extends 'music/base.html' %}
{% block title %}Songs{% endblock %}

{% block body %}

    <div class="row">
        <div class="col">
            <img style="height: 150px; margin-bottom: 20px;" src="{{album.album_logo.url}}"><br>
            <h4>Title: {{album.album_title}}</h4>
            <h4>Artist: {{album.artist}}</h4>
            <h4>Genre: {{album.genre}}</h4>
        </div>

        <div class="col">
            <div>
                <a href="{% url 'music:song-add' album.id%}" class="btn btn-success btn-sm" role="button">
                    <span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add Song
                </a>
            </div>

            <ul class="list-group list-group-flush">
                {% for song in album.song_set.all %}
                    <li class="list-group-item d-flex justify-content-between align-items-center">
                        <div>
                            {{ song.song_title }}

                            {% if song.is_favorite %}
                                <span class="glyphicon glyphicon-heart" aria-hidden="true"></span>
                            {% endif %}
                        </div>

                        <div>
                            <!-- Edit -->
                            <a class="btn btn-default btn-sm" href="{% url 'music:song-update' album.id song.id %}">
                                <span class="glyphicon glyphicon-pencil"></span>
                            </a>

                             <!-- Delete -->
                            <a class="btn btn-default btn-sm" href="{% url 'music:song-delete' album.id song.id %}">
                                <span class="glyphicon glyphicon-trash"></span>
                            </a>
                        </div>
                    </li>
                {% endfor %}
            </ul>
        </div>
    </div>

{% endblock %}

------------------------------------------------------
#music/templates/song_form

{% extends 'music/base.html' %}
{% block title %}Song{% endblock %}
{% load crispy_forms_tags %}

{% block body %}
    <div class="container-fluid">

        <div class="row">

            <div class="col-sm-12 col-md-7">

                <form  action="" method="post" enctype="multipart/form-data">
                    {% csrf_token %}
                    <fieldset class="form-group">
                        <legend class="border-bottom mb-4">Create/Update Song</legend>
                    </fieldset>
                    <div class="form-group">
                        <label for="disabledTextInput">Album</label>
                        <input type="text" id="disabledTextInput" class="form-control" value="{{song_album}}" disabled="disabled">
                        <br>
                        {{ form|crispy }}

                        <button class="btn btn-success btn-sm" type="submit">Submit</button>
                    </div>
                </form>

            </div>
        </div>
    </div>

{% endblock %}

---------------------------------------
#music/models

from django.db import models
from django.urls import reverse

class Album(models.Model):
    artist = models.CharField(max_length=50)
    album_title = models.CharField(max_length=50)
    genre = models.CharField(max_length=50)
    album_logo = models.FileField()

    #form submitted without action redirect to detail
    def get_absolute_url(self):
        return reverse('music:detail', kwargs={'pk': self.pk})

    #query album.objects.get(pk=1)
    def __str__(self):
        return self.album_title + ' - ' + self.artist

class Song(models.Model):
    album = models.ForeignKey(Album, on_delete=models.CASCADE)
    file_type = models.CharField(max_length=50)
    song_title = models.CharField(max_length=50)
    is_favorite = models.BooleanField(default=False)

    def __str__(self):
        return self.song_title

        # form submitted without action redirect to detail
    def get_absolute_url(self):
        return reverse('music:detail', kwargs={'pk': self.album.id})

reference:
https://stackoverflow.com/questions/26407863/passing-parameters-to-django-createview
https://stackoverflow.com/questions/18232851/django-passing-variables-to-templates-from-class-based-views

Saturday 30 March 2019

kijiji sell - motomaster eliminator battery for van, truck, excellent



excellent battery, never fail to start my van in the winter, cold cranking amp = 750. dimension 12" x 7-3/8" x 7-5/8" Van broke down. No need to keep the battery. bought from Canadian tire in Jan 2018 for $150, still have receipt, has 3 years of warranty left. price is firm.

django 24 confirm delete

4 albums in database

4 pictures in media

press delete, confirm delete page opens.

confirm delete, 1 album is deleted

picture associated with album is deleted in media



#power shell
pip install django-cleanup

#project1/settings
INSTALLED_APPS = (
     ...
    'django_cleanup', # should go after your apps
)

---------------------------------------------
#music/templates/index

{% extends 'music/base.html' %}
{% block title %}Albums{% endblock %}

{% block body %}
    <div class="container-fluid">
        <div class="row">
            {% for album in object_list %}
                <div class="col" style="margin-left: auto; margin-right: auto; margin-top: 5px; margin-bottom: 5px;">
                    <div class="card" style="width: 200px;">
                        <img src="{{album.album_logo.url}}" class="card-img-top" style="height: 150px" alt="{{album.album_title}}">

                        <div class="card-body">
                            <div style="height: 40px"><h5 class="card-title">Album: {{album.album_title}}</h5></div>
                            <div style="height: 40px"><p class="card-text">Artist: {{album.artist}}</p></div>

                            <!-- Detail -->
                            <a href="{% url 'music:detail' album.id %}" class="btn btn-primary btn-sm">View Detail</a>

                            <!-- Edit -->
                            <a class="btn btn-default btn-sm" href="{% url 'music:album-update' album.id %}">
                                <span class="glyphicon glyphicon-pencil"></span>
                            </a>

                            <!-- Delete -->
                            <a class="btn btn-default btn-sm" href="{% url 'music:album-delete' album.id %}">
                                <span class="glyphicon glyphicon-trash"></span>
                            </a>

                            <!-- Favorite -->
                            <a href="" class="btn btn-default btn-sm btn-favorite">
                                <span class="glyphicon glyphicon-star {% if album.is_favorite %}active{% endif %}"></span>
                            </a>
                        </div>
                    </div>
                </div>
            {% endfor %}
        </div>
    </div>
{% endblock %}

------------------------------------------
#music/templates/album_confirm_delete

{% extends 'music/base.html' %}
{% block title %}Delete Album{% endblock %}

{% block body %}
    <div class="container-fluid">

        <div class="row">

            <div class="col-sm-12 col-md-7">

                <form  action="" method="post" enctype="multipart/form-data">
                    {% csrf_token %}
                    <fieldset class="form-group">
                        <legend class="border-bottom mb-4">Delete Album</legend>
                        <h4>Are you sure to delete Album {{album.album_title}}?</h4>
                    </fieldset>
                    <div class="form-group">
                        <button class="btn btn-danger btn-sm" type="submit">Delete</button>
                        <a class="btn btn-secondary btn-sm" href="{% url 'music:index' %}">Cancel</a>
                    </div>
                </form>


            </div>
        </div>
    </div>

{% endblock %}

--------------------------
#music/views

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

----------------------
#music/urls

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

reference:
https://stackoverflow.com/questions/21941503/django-delete-unused-media-files

Friday 29 March 2019

django 23 messages



#music/templates/base

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    {% load staticfiles %}
    <!-- my css -->
    <link rel="stylesheet" type="text/css" href="{% static 'music/style.css' %}"/>
    <!-- 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">
    <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 。。。

    {% 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>

-------------------------------------
#music/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
from .forms import RegistrationForm, LoginForm
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib import messages

...

#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 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')

Thursday 28 March 2019

django 22 crispy form





#powershell
C:\Users\bob\django\project1> pip install django-crispy-forms

#project1/settings
INSTALLED_APPS = [
    'crispy_forms',
    ...
]

CRISPY_TEMPLATE_PACK = 'bootstrap4'

---------------------------------------------
#music/templates/album_form

{% extends 'music/base.html' %}
{% block title %}Album{% endblock %}
{% block albums_active %}active{% endblock %}
{% load crispy_forms_tags %}

{% block body %}
    <div class="container-fluid">

        <div class="row">

            <div class="col-sm-12 col-md-7">

                <form  action="" method="post" enctype="multipart/form-data">
                    {% csrf_token %}
                    <fieldset class="form-group">
                        <legend class="border-bottom mb-4">Create/Update Album</legend>
                    </fieldset>
                    <div class="form-group">
                        {{ form|crispy }}
                    </div>
                    <div class="form-group">
                        <button class="btn btn-success btn-sm" type="submit">Submit</button>
                    </div>
                </form>


            </div>
        </div>
    </div>

{% endblock %}

------------------------------------------------------
#music/templates/login_form

{% extends 'music/base.html' %}
{% block title %}Album{% endblock %}
{% load crispy_forms_tags %}

{% block body %}
    <div class="container-fluid">

        <div class="row">

            <div class="col-sm-12 col-md-7">

                <form  action="" method="post" enctype="multipart/form-data">
                    {% csrf_token %}
                    <fieldset class="form-group">
                        <legend class="border-bottom mb-4">Log in</legend>
                    </fieldset>
                    <div class="form-group">
                        {{ form|crispy }}
                    </div>
                    <div class="form-group">
                        Don't have an account?
                        <a href="{% url 'music:register' %}">Register one</a>
                    </div>
                    <div class="form-group">
                        <button class="btn btn-success btn-sm" type="submit">Submit</button>
                    </div>
                </form>


            </div>
        </div>
    </div>

{% endblock %}

Tuesday 26 March 2019

Chrome ad blocker





If you’re a Chrome user then the way to find and install your ad blocker is to open a new tab then click on the colourful square grid in the upper left corner of the screen. On the following page double click the Web Store option then search for ‘ad blocker’. You’ll see a number of options in the Extensions section. Click More Extension Results to open up the full breadth of the content on offer.

django 21 DetailView

created 4 songs in the album

deleted 1 song, browser stays in the album detail page

#music/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('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/add/', views.SongCreate.as_view(), name='song-add'),

    #music/song/id/
    path('song/<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'),
]

-------------------------------------------
#music/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
from .forms import RegistrationForm, LoginForm
from django.contrib.auth.mixins import LoginRequiredMixin

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

    def get_queryset(self):
        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']

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

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

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

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

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()

            return redirect('music:login')

        return render(request, self.template_name, {'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')

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

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

------------------------------------------------
#music/templates/music/detail

{% extends 'music/base.html' %}
{% block title %}Songs{% endblock %}

{% block body %}

    <div class="row">
        <div class="col">
            <img style="height: 150px; margin-bottom: 20px;" src="{{album.album_logo.url}}"><br>
            <h4>Title: {{album.album_title}}</h4>
            <h4>Artist: {{album.artist}}</h4>
            <h4>Genre: {{album.genre}}</h4>
        </div>

        <div class="col">
            <div>
                <a href="{% url 'music:song-add'%}" class="btn btn-success btn-sm" role="button">
                    <span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add Song
                </a>
            </div>

            <ul class="list-group list-group-flush">
                {% for song in album.song_set.all %}
                    <li class="list-group-item d-flex justify-content-between align-items-center">
                        <div>
                            {{ song.song_title }}

                            {% if song.is_favorite %}
                                <span class="glyphicon glyphicon-heart" aria-hidden="true"></span>
                            {% endif %}
                        </div>

                        <div>
                            <!-- Edit -->
                            <form action="{% url 'music:song-update' song.id %}" method="post" style="display: inline;">
                                {% csrf_token %}
                                <input type="hidden" name="song_id" value="{{song.id}}"/>
                                <button type="submit" class="btn btn-default btn-sm">
                                    <span class="glyphicon glyphicon-pencil"></span>
                                </button>
                            </form>

                             <!-- Delete -->
                            <form action="{% url 'music:song-delete' album.id song.id  %}" method="post" style="display: inline;">
                                {% csrf_token %}
                                <input type="hidden" name="song_id" value="{{song.id}}"/>
                                <button type="submit" class="btn btn-default btn-sm">
                                    <span class="glyphicon glyphicon-trash"></span>
                                </button>
                            </form>
                        </div>
                    </li>
                {% endfor %}
            </ul>
        </div>
    </div>

{% endblock %}

Friday 22 March 2019

django 20 registration authentication

open webpage, not log in yet

click add, update, delete album will redirect to login page

new user, register account

new user registered

after registration, log in 

add, update, delete are enabled now, update first album picture

after submit update, log out, changes are saved


#music/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('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/views

from django.views import generic
from .models import Album
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
from .forms import RegistrationForm, LoginForm
from django.contrib.auth.mixins import LoginRequiredMixin

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

    def get_queryset(self):
        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']

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

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

#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()

            return redirect('music:login')

        return render(request, self.template_name, {'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')

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

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

-----------------------------------------------------
#project1/settings

#redirect to login page if not authenticated
LOGIN_URL = 'music:login'

--------------------------------------
#music/forms

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

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

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

#ModelForm creates new. login existing, use Form instead
class LoginForm(forms.Form):
    username = forms.CharField(widget=forms.TextInput())
    password = forms.CharField(widget=forms.PasswordInput)
    fields = ['username', 'password']

------------------------------------------------
#music/template/music/login_form

{% extends 'music/base.html' %}
{% block title %}Login{% endblock %}

{% block body %}
    <div class="container-fluid">

        <div class="row">

            <div class="col-sm-12 col-md-7">

                <div class="panel panel-default">

                    <div class="panel-body">

                        <form class="form-horizontal" action="" method="post" enctype="multipart/form-data">
                            {% csrf_token %}
                            <div class="form-group">
                                <h3 class="col-sm-offset-2 col-sm-10">Login</h3>
                            </div>
                            {% include 'music/form-template.html' %}
                            <div class="form-group">
                                <div class="col-sm-offset-2 col-sm-10">
                                    Don't have an account?
                                    <a href="{% url 'music:register' %}">Register one</a>
                                </div>
                            </div>
                            <div class="form-group">
                                <div class="col-sm-offset-2 col-sm-10">
                                    <button type="submit" class="btn btn-success" >Submit</button>
                                </div>
                            </div>
                        </form>
                    </div>
                </div>
            </div>
        </div>
    </div>

{% endblock %}

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

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    {% load staticfiles %}
    <!-- my css -->
    <link rel="stylesheet" type="text/css" href="{% static 'music/style.css' %}"/>
    <!-- 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">
    <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="{% url 'music:logout' %}">
                            <span class="glyphicon glyphicon-off" aria-hidden="true"></span>&nbsp; Logout {{user.username}}
                        </a>
                    {% 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>

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

----------------------------------------
#music/templates/music/index

{% extends 'music/base.html' %}
{% block title %}Albums{% endblock %}

{% block body %}
    <div class="container-fluid">
        <div class="row">
            {% for album in object_list %}
                <div class="col" style="margin-left: auto; margin-right: auto; margin-top: 5px; margin-bottom: 5px;">
                    <div class="card" style="width: 200px;">
                        <img src="{{album.album_logo.url}}" class="card-img-top" style="height: 150px" alt="{{album.album_title}}">

                        <div class="card-body">
                            <div style="height: 40px"><h5 class="card-title">Album: {{album.album_title}}</h5></div>
                            <div style="height: 40px"><p class="card-text">Artist: {{album.artist}}</p></div>

                            <!-- Detail -->
                            <a href="{% url 'music:detail' album.id %}" class="btn btn-primary btn-sm">View Detail</a>

                            <!-- Edit -->
                            <form action="{% url 'music:album-update' album.id %}" method="post" style="display: inline;">
                                {% csrf_token %}
                                <input type="hidden" name="album_id" value="{{album.id}}"/>
                                <button type="submit" class="btn btn-default btn-sm">
                                    <span class="glyphicon glyphicon-pencil"></span>
                                </button>
                            </form>

                            <!-- Delete -->
                            <form action="{% url 'music:album-delete' album.id %}" method="post" style="display: inline;">
                                {% csrf_token %}
                                <input type="hidden" name="album_id" value="{{album.id}}"/>
                                <button type="submit" class="btn btn-default btn-sm">
                                    <span class="glyphicon glyphicon-trash"></span>
                                </button>
                            </form>

                            <!-- Favorite -->
                            <a href="" class="btn btn-default btn-sm btn-favorite">
                                <span class="glyphicon glyphicon-star {% if album.is_favorite %}active{% endif %}"></span>
                            </a>
                        </div>
                    </div>
                </div>
            {% endfor %}
        </div>
    </div>
{% endblock %}

--------------------------------------
#music/templates/music/form-template

{% for field in form %}

    <div class="form-group">

        <div class="col-sm-offset-2 col-sm-10">

            <span class="text-danger small">{{ field.errors }}</span>
        </div>
        <label class="control-label col-sm-2">{{ field.label_tag }}</label>
        <div class="col-sm-10">{{ field }}</div>
    </div>
{% endfor %}

reference:
https://stackoverflow.com/questions/42792734/django-authenticate-a-user-with-that-username-already-exists
https://wsvincent.com/django-user-authentication-tutorial-login-and-logout/
https://kite.com/python/docs/django.contrib.auth.logout
https://docs.djangoproject.com/en/2.1/topics/auth/default/
https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Authentication
https://stackoverflow.com/questions/39554829/django-use-post-in-updateview-to-populate-forms-fields-with-instances-exist

nucleus

https://www.nucleus.com/services/internet/high-speed-internet/

Tuesday 19 March 2019

django 19 upload file

 3 albums in database

 add a new album

 upload a image

image uploaded, new album created 

uploaded files are stored in media folder

#music/models

from django.db import models
from django.urls import reverse

class Album(models.Model):
    artist = models.CharField(max_length=50)
    album_title = models.CharField(max_length=50)
    genre = models.CharField(max_length=50)
    album_logo = models.FileField()

    #form submitted without action redirect to detail
    def get_absolute_url(self):
        return reverse('music:detail', kwargs={'pk': self.pk})

    #query album.objects.get(pk=1)
    def __str__(self):
        return self.album_title + ' - ' + self.artist

class Song(models.Model):
    album = models.ForeignKey(Album, on_delete=models.CASCADE)
    file_type = models.CharField(max_length=50)
    song_title = models.CharField(max_length=50)
    is_favorite = models.BooleanField(default=False)

    def __str__(self):
        return self.song_title

--------------------------------------
#project1/settings
#at the end of file

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/dev/howto/static-files/

STATIC_URL = '/static/'

MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
MEDIA_URL = '/media/'

---------------------------------------
#project1/urls

from django.contrib import admin
from django.urls import path, include
from django.conf import  settings
from django.conf.urls.static import static

urlpatterns = [
    path('admin/', admin.site.urls),
    path('music/', include('music.urls')),
]

if settings.DEBUG:
    urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

---------------------------------------------
#music/templates/music/index & detail

<img src="{{album.album_logo.url}}" class="card-img-top" style="height: 150px" alt="{{album.album_title}}">

Sunday 17 March 2019

django 18 UpdateView DeleteView

 4 albums in database

 update second album change title to high school

updated

click delete, 3 albums left


#music/models

from django.db import models
from django.urls import reverse

class Album(models.Model):
    artist = models.CharField(max_length=50)
    album_title = models.CharField(max_length=50)
    genre = models.CharField(max_length=50)
    album_logo = models.CharField(max_length=500)

    #form submitted without action redirect to detail
    def get_absolute_url(self):
        return reverse('music:detail', kwargs={'pk': self.pk})

    #query album.objects.get(pk=1)
    def __str__(self):
        return self.album_title + ' - ' + self.artist

class Song(models.Model):
    album = models.ForeignKey(Album, on_delete=models.CASCADE)
    file_type = models.CharField(max_length=50)
    song_title = models.CharField(max_length=50)
    is_favorite = models.BooleanField(default=False)

    def __str__(self):
        return self.song_title

-----------------------------------------------
#music/urls

from django.urls import path
from . import views

app_name = 'music'

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

    #/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/views

from django.views import generic
from .models import Album
from django.views.generic.edit import  CreateView, UpdateView, DeleteView
from django.urls import reverse_lazy

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

    def get_queryset(self):
        return  Album.objects.all()

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

class AlbumCreate(CreateView):
    model = Album
    fields = ['artist', 'album_title', 'genre', 'album_logo']

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

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

---------------------------------------
#music/templates/music/index.html

{% extends 'music/base.html' %}
{% block title %}Albums{% endblock %}

{% block body %}
    <div class="container-fluid">
        <div class="row">
            {% for album in object_list %}
                <div class="col" style="margin-left: auto; margin-right: auto; margin-top: 5px; margin-bottom: 5px;">
                    <div class="card" style="width: 200px;">
                        <img src="{{album.album_logo}}" class="card-img-top" style="height: 150px" alt="{{album.album_title}}">

                        <div class="card-body">
                            <div style="height: 40px"><h5 class="card-title">Album: {{album.album_title}}</h5></div>
                            <div style="height: 40px"><p class="card-text">Artist: {{album.artist}}</p></div>

                            <!-- Detail -->
                            <a href="{% url 'music:detail' album.id %}" class="btn btn-primary btn-sm">View Detail</a>

                            <!-- Delete -->
                            <form action="{% url 'music:album-delete' album.id %}" method="post" style="display: inline;">
                                {% csrf_token %}
                                <input type="hidden" name="album_id" value="{{album.id}}"/>
                                <button type="submit" class="btn btn-default btn-sm">
                                    <span class="glyphicon glyphicon-trash"></span>
                                </button>
                            </form>

                            <!-- Favorite -->
                            <a href="" class="btn btn-default btn-sm btn-favorite">
                                <span class="glyphicon glyphicon-star {% if album.is_favorite %}active{% endif %}"></span>
                            </a>
                        </div>
                    </div>
                </div>
            {% endfor %}
        </div>
    </div>
{% endblock %}


reference:
https://simpleisbetterthancomplex.com/series/2017/10/09/a-complete-beginners-guide-to-django-part-6.html
https://rayed.com/posts/2018/05/django-crud-create-retrieve-update-delete/