Sunday 26 May 2019

django 39 rest framework filter by url parameter

get request to http://127.0.0.1:8000/api/album_list/?author=chuanshuo&data_length=2
server returns 2 of chuanshuo's posts

#music/api/apiview

from music.models import Album
from music.api.serializers import MusicSerializer
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from django.http import Http404
from django.contrib.auth.models import User
from django.shortcuts import get_object_or_404

class AlbumList(APIView):
    def get(self, request, format=None):
        username = request.GET.get('author')
        data_length = request.GET.get('data_length')

        #filter by author
        if username==None:
            albums = Album.objects.all()
        else:
            author_id = get_object_or_404(User, username=username).pk
            albums = Album.objects.filter(author=author_id).order_by('-date_posted')

        #filter by data length
        if data_length!=None:
            try:
                int(data_length)
            except ValueError:
                return Response('data length is invvalid', status=status.HTTP_406_NOT_ACCEPTABLE)
            else:
                albums = albums[:int(data_length)]

        serializer = MusicSerializer(albums, many=True)
        return Response(serializer.data)

    def post(self, request, format=None):
        serializer = MusicSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class AlbumDetail(APIView):

    def get_object(self, pk):
        try:
            return Album.objects.get(pk=pk)
        except Album.DoesNotExist:
            raise Http404

    def get(self, request, pk, format=None):
        album = self.get_object(pk)
        serializer = MusicSerializer(album)
        return Response(serializer.data)

    def put(self, request, pk, format=None):
        album = self.get_object(pk)

        #only owner can edit
        if album.author != request.user:
            return Response({"detail": "You do not have permission to perform this action."},
                            status= status.HTTP_403_FORBIDDEN)

        serializer = MusicSerializer(album, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, pk, format=None):
        album = self.get_object(pk)

        # only owner can delete
        if album.author != request.user:
            return Response({"detail": "You do not have permission to perform this action."},
                            status=status.HTTP_403_FORBIDDEN)

        album.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

reference:
https://pypi.org/project/django-filter/
https://www.django-rest-framework.org/api-guide/status-codes/
https://stackoverflow.com/questions/25928990/catching-any-doesnotexist-error
https://chuanshuoge2.blogspot.com/2019/05/django-38-rest-framework-authentication.html

Saturday 25 May 2019

Wednesday 22 May 2019

django 38 rest framework token authentication

get from http://127.0.0.1:8000/api/album_list/, response credential not provided

post to http://127.0.0.1:8000/api/api-token-auth/ with login, obtain token

get request to http://127.0.0.1:8000/api/album_list/ with token, server responds with data

send put request to http://127.0.0.1:8000/api/album_detail/38/ to edit chuanshuo's post but with bob's token
server responds permission denied

 post request to http://127.0.0.1:8000/api/api-token-auth/ with chuanshuo's login
obtain chanshuo's token

send put request to http://127.0.0.1:8000/api/album_detail/38/ with chuanshuo's token to edit his own post, successful


#settings

INSTALLED_APPS = [
    ...
    'rest_framework',
    'rest_framework.authtoken',
]

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
                'rest_framework.authentication.TokenAuthentication',
                ),
    'DEFAULT_PERMISSION_CLASSES':(
        'rest_framework.permissions.IsAuthenticated',
    ),
}

-----------------------------------------
#powershell
python manage.py migrate

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

from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from music.api import apiview, mixins
from rest_framework.authtoken import views

app_name = 'musicAPI'

urlpatterns = [
    path('album_list/', apiview.AlbumList.as_view(), name='AlbumList'),
    path('album_detail/<int:pk>/', apiview.AlbumDetail.as_view(), name='AlbumDetail'),
    path('album_list_mixin/', mixins.AlbumListMixin.as_view(), name='AlbumListMixin'),
    path('album_detail_mixin/<int:pk>/', mixins.AlbumDetailMixin.as_view(), name='AlbumDetailMixin'),
    path('api-token-auth/', views.obtain_auth_token, name='AuthToken'),
]

urlpatterns = format_suffix_patterns(urlpatterns)

-----------------------------------------------------
#music/api/apiview

from music.models import Album
from music.api.serializers import MusicSerializer
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from django.http import Http404

class AlbumList(APIView):
    def get(self, request, format=None):
        albums = Album.objects.all()
        serializer = MusicSerializer(albums, many=True)
        return Response(serializer.data)

    def post(self, request, format=None):
        serializer = MusicSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class AlbumDetail(APIView):

    def get_object(self, pk):
        try:
            return Album.objects.get(pk=pk)
        except Album.DoesNotExist:
            raise Http404

    def get(self, request, pk, format=None):
        album = self.get_object(pk)
        serializer = MusicSerializer(album)
        return Response(serializer.data)

    def put(self, request, pk, format=None):
        album = self.get_object(pk)

        #only owner can edit
        if album.author != request.user:
            return Response({"detail": "You do not have permission to perform this action."},
                            status= status.HTTP_403_FORBIDDEN)

        serializer = MusicSerializer(album, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, pk, format=None):
        album = self.get_object(pk)

        # only owner can delete
        if album.author != request.user:
            return Response({"detail": "You do not have permission to perform this action."},
                            status=status.HTTP_403_FORBIDDEN)

        album.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

-----------------------------------------
#music/api/mixins

from music.models import Album
from music.api.serializers import MusicSerializer
from rest_framework import mixins, generics, permissions
from .permissions import IsOwnerOrReadOnly

class AlbumListMixin(mixins.ListModelMixin,
                  mixins.CreateModelMixin,
                  generics.GenericAPIView):
    queryset = Album.objects.all()
    serializer_class = MusicSerializer

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

class AlbumDetailMixin(mixins.RetrieveModelMixin,
                    mixins.UpdateModelMixin,
                    mixins.DestroyModelMixin,
                    generics.GenericAPIView):
    queryset = Album.objects.all()
    serializer_class = MusicSerializer
    permission_classes = (permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly,)

    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)

    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)

------------------------------------
#music/api/permisions

from rest_framework import permissions


class IsOwnerOrReadOnly(permissions.BasePermission):
    """
    Custom permission to only allow owners of an object to edit it.
    """

    def has_object_permission(self, request, view, obj):
        # Read permissions are allowed to any request,
        # so we'll always allow GET, HEAD or OPTIONS requests.
        if request.method in permissions.SAFE_METHODS:
            return True

        # Write permissions are only allowed to the owner of the snippet.
        return obj.author == request.user

reference:
https://www.youtube.com/watch?v=PFcnQbOfbUU&list=PLbpAWbHbi5rMV3H0S5IDK3cSRC1Jas3VP&index=3
https://stackoverflow.com/questions/39923384/str-object-is-not-callable-django-rest-framework
https://stackoverflow.com/questions/53649252/django-rest-framework-basepermissionmetaclass-object-is-not-iterable
http://chuanshuoge2.blogspot.com/2019/05/django-37-rest-framework-class-based.html
http://chuanshuoge2.blogspot.com/2019/05/django-36-rest-framework-class-based.html

Monday 20 May 2019

django 37 rest framework class based mixins

get from http://127.0.0.1:8000/api/album_list_mixin

postman posts to http://127.0.0.1:8000/api/album_list_mixin


post successful, new id =35

postman get from http://127.0.0.1:8000/api/album_detail_mixin/35/

postman send put request to http://127.0.0.1:8000/api/album_detail_mixin/35/ to change artist to 'new postman'

artist is changed, put request is successful

postman send delete request to http://127.0.0.1:8000/api/album_detail_mixin/35/

delete request is successful


#music/api/mixins

from music.models import Album
from music.api.serializers import MusicSerializer
from rest_framework import mixins
from rest_framework import generics

class AlbumListMixin(mixins.ListModelMixin,
                  mixins.CreateModelMixin,
                  generics.GenericAPIView):
    queryset = Album.objects.all()
    serializer_class = MusicSerializer

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        return self.create(request, *args, **kwargs)

class AlbumDetailMixin(mixins.RetrieveModelMixin,
                    mixins.UpdateModelMixin,
                    mixins.DestroyModelMixin,
                    generics.GenericAPIView):
    queryset = Album.objects.all()
    serializer_class = MusicSerializer

    def get(self, request, *args, **kwargs):
        return self.retrieve(request, *args, **kwargs)

    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)

    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)

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

from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from music.api import apiview, mixins

app_name = 'musicAPI'

urlpatterns = [
    path('album_list', apiview.AlbumList.as_view(), name='AlbumList'),
    path('album_detail/<int:pk>/', apiview.AlbumDetail.as_view(), name='AlbumDetail'),
    path('album_list_mixin', mixins.AlbumListMixin.as_view(), name='AlbumListMixin'),
    path('album_detail_mixin/<int:pk>/', mixins.AlbumDetailMixin.as_view(), name='AlbumDetailMixin')
]

urlpatterns = format_suffix_patterns(urlpatterns)

reference:
https://chuanshuoge2.blogspot.com/2019/05/django-35-rest-framework-apiview-get.html

Sunday 19 May 2019

django 36 rest framework class based apiview put delete

get details from http://127.0.0.1:8000/api/album_detail/33/

post send put request to http://127.0.0.1:8000/api/album_detail/33/ to change genre to 'rock' 

get details from http://127.0.0.1:8000/api/album_detail/33/ genre is changed to 'rock'

postman send delete requent to http://127.0.0.1:8000/api/album_detail/33/

album no longer exist

#music/api/apiview

from music.models import Album
from music.api.serializers import MusicSerializer
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from django.http import Http404

class AlbumList(APIView):
    def get(self, request, format=None):
        albums = Album.objects.all()
        serializer = MusicSerializer(albums, many=True)
        return Response(serializer.data)

    def post(self, request, format=None):
        serializer = MusicSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class AlbumDetail(APIView):
    def get_object(self, pk):
        try:
            return Album.objects.get(pk=pk)
        except Album.DoesNotExist:
            raise Http404

    def get(self, request, pk, format=None):
        album = self.get_object(pk)
        serializer = MusicSerializer(album)
        return Response(serializer.data)

    def put(self, request, pk, format=None):
        album = self.get_object(pk)
        serializer = MusicSerializer(album, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, pk, format=None):
        album = self.get_object(pk)
        album.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

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

from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from music.api import apiview

app_name = 'musicAPI'

urlpatterns = [
    path('album_list', apiview.AlbumList.as_view(), name='AlbumList'),
    path('album_detail/<int:pk>/', apiview.AlbumDetail.as_view(), name='AlbumDetail'),
]

urlpatterns = format_suffix_patterns(urlpatterns)

reference:

Friday 17 May 2019

HIDDEN Fees When Purchasing a House

Home inspection            $500 before closing
Appraisal fee                   $450 before closing after contract
Earnest money deposit 1.5% - 3% of sales price before closing
Title insurance                $2000 paid at closing
County transfer tax        $350 paid at closing
State transfer tax            0.0025* sales price paid at closing
State mortgage tax         0.0025 * mortgage amount
Property tax                    paid at closing
Homeowner’s insurance             $1000 paid at closing
HOA transfer fee            $300 paid at closing
Title services                   $550 paid at closing
Condo move-in fee        $100 - $300 paid at closing



reference:
https://www.youtube.com/watch?v=K3o4rwczZy0
https://www.youtube.com/watch?v=_1fTFZEB3BQ

primus internet


reference:
https://primus.ca

Thursday 16 May 2019

django 35 rest framework class based apiview get post

get request to http://127.0.0.1:8000/api/album_list, last id = 32

postman post request to http://127.0.0.1:8000/api/album_list, new id = 33

verify data posted to server

#music/api/apiview

from music.models import Album
from music.api.serializers import MusicSerializer
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status

class AlbumList(APIView):
    def get(self, request, format=None):
        albums = Album.objects.all()
        serializer = MusicSerializer(albums, many=True)
        return Response(serializer.data)

    def post(self, request, format=None):
        serializer = MusicSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

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

from django.urls import path
from rest_framework.urlpatterns import format_suffix_patterns
from music.api import apiview

app_name = 'musicAPI'

urlpatterns = [
    path('album_list', apiview.AlbumList.as_view(), name='AlbumList'),
]

urlpatterns = format_suffix_patterns(urlpatterns)

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

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

-------------------------------------
#music/api/serializers

from rest_framework import serializers
from music.models import Album

class MusicSerializer(serializers.ModelSerializer):
    class Meta:
        model = Album
        fields = ('id', 'artist', 'album_title', 'genre', 'album_logo', 'date_posted', 'author')

reference:
http://chuanshuoge2.blogspot.com/2019/05/django-34-restful-api.html

Wednesday 15 May 2019

django 34 rest framework viewset get

postman get last 5 albums from http://127.0.0.1:8000/api/albums_last5/

postman get all albums from http://127.0.0.1:8000/api/albums_all/


#powershell
pip install djangorestframework

------------------------------
#settings
INSTALLED_APPS = [
    ...
    'rest_framework',
]

---------------------------------
#music/api/serializers

from rest_framework import serializers
from music.models import Album

class MusicSerializer(serializers.ModelSerializer):
    class Meta:
        model = Album
        fields = ('id', 'artist', 'album_title', 'genre', 'album_logo', 'date_posted', 'author')

---------------------------------
#music/api/viewsets

from music.models import Album
from .serializers import MusicSerializer
from rest_framework import viewsets

class AlbumAllViewSet(viewsets.ModelViewSet):
    queryset = Album.objects.all()
    serializer_class = MusicSerializer
    http_method_names = ['get']

class AlbumLast5ViewSet(viewsets.ModelViewSet):
    queryset = Album.objects.all().order_by('-date_posted')[:5]
    serializer_class = MusicSerializer
    http_method_names = ['get']

-------------------------------------
#project1/router

from music.api.viewsets import AlbumLast5ViewSet, AlbumAllViewSet
from rest_framework import routers

router = routers.DefaultRouter()
router.register('albums_all', AlbumAllViewSet)
router.register('albums_last5', AlbumLast5ViewSet)

----------------------------
#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
from .router import router

urlpatterns = [
    path('admin/', admin.site.urls),
    path('music/', include('music.urls')),
    path('', include('django.contrib.auth.urls')),
    path('api/', include(router.urls)),
]

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


reference:
http://chuanshuoge2.blogspot.com/2019/05/django-34-restful-api.html

Wednesday 8 May 2019

tri-cities trip

expense

May 8 - taxi, delta luggage, rental car
May 9 - hotel
May 10 - taxi
May 13 - train ticket, taxi

timesheet

May 8 - ferry to tri-cities 12h
May 9 - bundle, ferry to new york 12h
May 10 - weather down 8h
May 11 - survey 12h
May12 - weather down 8h
May 13 - ferry back 8h

Sunday 5 May 2019

django 33 reset password by email

click reset password 

enter email address, django looks through users' record. If match is found, reset email will be sent.
if email is same with others, django sends email to user registered first. make sure email is unique.

notification email is sent

mail box receives email, click the link

enter new password

password changed, click log in

log in with new password

log in successful


#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')),
    path('', include('django.contrib.auth.urls')),
]

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

----------------------------------------
#settings

#email setting
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_USE_TLS = True
EMAIL_PORT = 587
EMAIL_HOST_USER = 'zchen2014chuanshuo@gmail.com'
EMAIL_HOST_PASSWORD = 'xxx'

----------------------------------------
#templates/registration/password_reset_done

{% block content %}
  <p>
    We've emailed you instructions for setting your password, if an account exists with the email you entered.
    You should receive them shortly.
  </p>
  <p>
    If you don't receive an email, please make sure you've entered the address you registered with,
    and check your spam folder.
  </p>
{% endblock %}

---------------------------------------
#templates/registration/password_reset_email

{% autoescape off %}
To initiate the password reset process for your {{ user.get_username }} TestSite Account,
click the link below:

{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}

If clicking the link above doesn't work, please copy and paste the URL in a new browser
window instead.

Sincerely,
The TestSite Team
{% endautoescape %}

---------------------------------------
#templates/registration/password_reset_confirm

{% block content %}
  {% if validlink %}
    <h3>Change password</h3>
    <form method="post">
      {% csrf_token %}
      {{ form.as_p }}
      <button type="submit">Change password</button>
    </form>
  {% else %}
    <p>
      The password reset link was invalid, possibly because it has already been used.
      Please request a new password reset.
    </p>
  {% endif %}
{% endblock %}

---------------------------------------------------
#templates/registration/password_reset_complete

{% block content %}
  <p>
    Your password has been set. You may go ahead and <a href="{% url 'signin' %}">sign in</a> now.
  </p>
{% endblock %}

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

{% extends 'music/base.html' %}
{% block title %}Log in{% 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">
                        Forgot password? Reset by email.
                        <a href="{% url 'password_reset' %}">Reset password</a>
                    </div>
                    <div class="form-group">
                        <button class="btn btn-success btn-sm" type="submit">Submit</button>
                    </div>
                </form>


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

{% endblock %}

-------------------------------------
#templates/registration/password_reset_subject

TestSite password reset

reference:
https://stackoverflow.com/questions/44676880/error-reverse-for-password-reset-done-not-found-password-reset-done-is-not
https://simpleisbetterthancomplex.com/tutorial/2016/09/19/how-to-create-password-reset-view.html

Thursday 2 May 2019

Joint Tenancy


reference:
https://kahanelaw.com/joint-tenancy-joint-tenants-alberta/

django 32 sending email

dynamically add/remove recipients

all recipients receive email


#urls
from django.urls import path
from . import views

app_name = 'music'

urlpatterns = [
#music/eamil
    path('email/', views.Email.as_view(), name='email'),
]

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

from .forms import SendEmailForm
from django.contrib import messages
from django.core.mail import send_mail
from django.conf import settings

class Email(View):
    form_class = SendEmailForm
    template_name = 'music/email_form.html'

    def get(self, request):
        #get request, display Form 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():
            subject = form.data['subject']
            message = form.data['message']
            email_from = settings.EMAIL_HOST_USER
            recipient_list = request.POST.getlist('recipients[]')
            send_mail(subject, message, email_from, recipient_list)

            messages.success(request, 'emails sent')
            return redirect('music:email')

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

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

class SendEmailForm(forms.Form):
    subject = forms.CharField(widget=forms.TextInput())
    message = forms.CharField(widget=forms.Textarea, required=False)

-------------------------------------------
#settings

#email setting
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_USE_TLS = True
EMAIL_PORT = 587
EMAIL_HOST_USER = 'zchen2014chuanshuo@gmail.com'
EMAIL_HOST_PASSWORD = 'xxx'

-------------------------------------------
#template/email_form

{% extends 'music/base.html' %}
{% block title %}Email{% 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">Send Email</legend>
                    </fieldset>
                    <div class="input_fields_wrap form-group">
                        <label>Recipients</label>
                        <button class="add_field_button btn-outline-dark">Add more</button><br>
                        <input type="email" name="recipients[]" required="required">
                    </div>
                    <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>

<script type="text/javascript">
$(document).ready(function() {
var max_fields      = 10; //maximum input boxes allowed
var wrapper    = $(".input_fields_wrap"); //Fields wrapper
var add_button      = $(".add_field_button"); //Add button ID

var x = 1; //initlal text box count
$(add_button).click(function(e){ //on add input button click
e.preventDefault();
if(x < max_fields){ //max input box allowed
x++; //text box increment
$(wrapper).append('<div><input type="email" name="recipients[]" required="required"/><a href="#" class="remove_field">Remove</a></div>'); //add input box
}
});

$(wrapper).on("click",".remove_field", function(e){ //user click on remove text
e.preventDefault(); $(this).parent('div').remove(); x--;
})
});
</script>

{% endblock %}

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

<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>
....
</body>

reference:
http://chuanshuoge2.blogspot.com/2019/04/django-32-sending-email.html

Wednesday 1 May 2019

Home Tax Deductions & Tax Credits for Canadian Homeowners

Mortgage not deductible


The tax law for Canada's homeowners is very different from the system in the U.S. Notably, the interest on a mortgage for a principal private residence is not tax deductible. However, all capital gains upon selling the home are tax exempt.

Tax credit vs. tax income deduction

Tax credits effectively reduce taxes by the entire amount of the credit. For example, in 2009, new home buyers received a first-time homebuyer's credit -- which no longer exists -- of $8,000, which reduced their total tax due by $8,000.

By contrast, if you paid $8,000 in mortgage interest for the year, it would not reduce your taxes by that amount. Your taxable income is reduced instead. So if you pay $8,000 in interest and are in the 22 percent tax bracket, your mortgage interest deduction actually reduces your taxes by $1,760, or 22 percent of $8,000.

First-time Home Buyers Tax Credit $5,000. you did not live in another home owned by you or your spouse or common-law partner in the year of acquisition or in any of the four preceding years

GST/HST New Housing/ Rental Property Rebate


Purchased new housing or constructed or substantially renovated housing for use as your primary place of residence  when the construction is substantially completed is less than $450,000

landlord who purchased a newly constructed or substantially renovated residential rental property

If you rent real estate or other property, including farmland that you own or have use of, you will need to report the income to the CRA on Form T776, Statement of Real Estate Rentals, which allows you to claim allowable expenses such as advertising, insurance and interest on money you borrow to buy or improve the property.

Home Buyer’s Plan


withdraw up to $25,000 from RRSP.  completing the T1036 tax form. You will be required to pay 1/15th of the loan each year for the next 15 years. But there will be no interest charges and no taxes incurred.

Homeowners Who Work From Home


The amount that you are eligible to claim corresponds to the percentage of the home used for the business and expenses which could be claimed include, but are not limited to:
Utilities – heating, water and electricity
Insurance
Maintenance
Internet
Office supplies
Cleaning supplies

Moving Expenses


you moved and established a new home to work or run a business at a new location; or
you moved to be a student in full-time attendance in a post-secondary program at a university, college or other educational institution.
To qualify, your new home must be at least 40 kilometres (by the shortest usual public route) closer to your new work or school.

reference:
https://turbotax.intuit.ca/tips/home-tax-deductions-credits-in-canada-5223
https://www.investopedia.com/articles/mortgages-real-estate/08/tax-deductible-mortgage-canada.asp
https://www.moneysense.ca/columns/how-your-home-can-save-you-at-tax-time/