Todo List with Django (Dennis Ivy)

18850 단어 djangotodoListdjango

0. Upgrade Django Version

pip install --upgrade django==3.0

1. Create Project

django-admin startproject todolist[name of project]

2. Run Server

inside the project folder

ctrl + c: break on server

3. Migrate DB

python manage.py migrate

by default, django uses sqlite but normally you'd wanna use postgresql or mysql.

created our default table: user

4. Create Admin(User)

python manage.py createsuperuser 

5. Launch an App

python manage.py startapp [app name]

Register an App into settings
settings.py
INSTALLED_APPS

6. url Routing

1. Create 'index function' at views.py

from django.http import HttpResponse

# Create your views here.
def index(request):
    return HttpResponse("hello world")

2. Create urls.py

from django.urls import path
from . import views
urlpatterns = [
    path('', views.index)
]

3. Include url in base urls.py

This should sets up the response. Turn on server to check.

from django.urls import path, include

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

Successfully set up

7. Templates

app> templates > tasks > html

Note the file name

def index(request):
    return render(request, 'tasks/list.html')

8. Create Model

__str__

when you retrieve data from DB with Blog.objects.all(), It will return <QuerySet [<Blog:>,<Blog:>,...]
It's hard to recognize the objects.
Better way is retrieving them by one of its properties which you set it as name.
<QuerySet [<Blog:itsName>,<Blog:itsName>,...]

models.py

class Task(models.Model):
    title = models.CharField(max_length=200)
    complete = models.BooleanField(default=False)
    created = models.DateTimeField(auto_now_add=True)
    
    def __str__(self):
        return self.title

any new models?

python manage.py makemigrations

create in DB

python manage.py migrate

Register model at admin
admin.py

from .models import *

admin.site.register(Task)

so we can see table in our server admin section

9. Render Data in template

  • context is our third parameter that passes DB object.

views.py

from .models import *

def index(request):
    tasks = Task.objects.all()
    context = { 'tasks': tasks }
    return render(request, 'tasks/list.html', context)
  • I already added tasks into db through admin website to see if it's rendered correctly.

list.html

<h3>todo</h3>

{% for task in tasks %}
<div>
    <p>
        {{ task }}
    </p>
</div>
{% endfor %}

10. Model Forms

Ivy prefers to use 'Model Forms' over 'built-in Class based views forms'. He thinks It's too easy to make it work but not helps to underderstand it.
Hence, He goes for 'Model Forms'

1. Create folder 'forms.py'**

inside app folder

form representation of a model

forms.py

from django import forms
from django.forms import ModelForm
from .models import *

class TaskForm(forms.ModelForm):

    class Meta:
        model = Task
        fields = '__all__'

2. Pass the data as parameter

Pass form instance as 3rd parameter inside context
views.py

from .forms import *

def index(request):
    tasks = Task.objects.all()

    form = TaskForm()

    context = {'tasks': tasks, 'form': form}
    return render(request, 'tasks/list.html', context)

3. Into Template

Pass the form into template
create html form element and get passed the data

list.html

<form>
    {{ form.title }}
    <input type="submit" name="Create Task">
</form>


CRUD

11. Create Item

when we submit data, it's gonna send it back to view

1. template

  • make sure to include csrf_token

list.html

    {% csrf_token %}

2. view

  • passing the 'post method' into the form

views.py

def index(request):
    tasks = Task.objects.all()
    form = TaskForm()
    
    if request.method == 'POST':
        form = TaskForm(request.POST) 
        if form.is_valid():
            form.save() 
        return redirect('/')

    context = {'tasks': tasks, 'form': form}
    return render(request, 'tasks/list.html', context)

12. Update Item (Edit)

pk == primary key
grab the pk from url pattern

  • <str:pk>: str value works with numbers and letters
  • Dynamic Name: make url dynamic by assigning name.
    how we call the url pattern

1. url

urls.py

urlpatterns = [
    path('', views.index, name="list"),
    path('update_task/<str:pk>',
    	views.update_task, name="update_task"),
]

2. view

1) GET

pre-populated form

views.py

def update_task(request, pk):
    task = Task.objects.get(id=pk)
    form = TaskForm(instance=task) 
    context = {'form': form}

    return render(request, 'tasks/update_task.html', context)

2) POST

Add post. if we only pass request.POST, it will create a new obj. Make sure to pass instance we are updating.
form = TaskForm(request.POST, instance=task)

def update_task(request, pk):
    task = Task.objects.get(id=pk)
    form = TaskForm(instance=task)
    context = {'form': form}
    
    if request.method == 'POST':
        form = TaskForm(request.POST, instance=task) 
        if form.is_valid():
            form.save()
            return redirect('/')
    return render(request, 'tasks/update_task.html', context)

3. template

  • Create Update link to direct to edit page
    -used 'name' 'update_task' in url pattern
    <a href="{% url 'update_task' task.id %}">Update</a>
    == update_task/1

list.html

{% for task in tasks %}
<div>

    <a href="{% url 'update_task' task.id %}">Update</a>
    
    <p>{{ task }}</p>
</div>
{% endfor %}


update_task.html

<h3>Update Task</h3>

<form action="" method="POST">
    {% csrf_token %}
    {{ form }}
    <input type="submit" name="Update Task">
</form>

13. Delete Item

UI: Ask user to confirm their action: sure you want to delete?

1. url

path('delete_task/<str:pk>',views.delete_task, 
      name="delete_task"),

2. views

1. GET

Get confirmation

def delete_task(request, pk):
    item = Task.objects.get(id=pk)
    context = {'item': item}
    return render(request, 'tasks/delete.html', context)

2. POST

Actually delete from DB

def delete_task(request, pk):
    item = Task.objects.get(id=pk)
    context = {'item': item}

    if request.method == 'POST':
        item.delete()
        return redirect('/')

    return render(request, 'tasks/delete.html', context)

3. templates

list.html

<a href="{% url 'delete_task' task.id %}">Delete</a>
  • We don't need a form as it will just delete the item.

delete.html

<p> Are you sure you want to delete "{{ item }}"? </p>

<a href="{% url 'list' %}"> Cancel </a>

<form action="" method="POST">
    {% csrf_token %}
    <input type="submit" name="Confirm">
</form>

14. Cross out complete items

  • html strike tag will place a strikethrough (horizontal line) over text on the complete task (ticked off)

list.html

    {% if task.complete == True %}
        <strike>{{ task }}</strike>
    {% else %}
        <span> {{task}} </span>
    {% endif %}
  • complete is from form model

models.py

class Task(models.Model):
    complete = models.BooleanField(default=False)

15. Style template

video 36:05 - Style template

form: sets a place holder

as we don't use html form, we can't set placeholder directly from html form element.

-customizing the form field

form.py

class TaskForm(forms.ModelForm):
    title = forms.CharField(
    	widget= forms.TextInput(
        attrs={'placeholder': 'Add new task...'}))

Result


Dennis Ivy Todolist

좋은 웹페이지 즐겨찾기