To add a new post, we need a form to fill in.
path('add_post', AddPostView.as_view(), name="add_post"),
CreateView
fields = '__all__': it's from model field. if you want to specify fields, fields = ('title', 'body',) pick and choose.
Note that without the , at the end of the () is treated as a string and cause error
class AddPostView(CreateView):
    model = Post
    template_name = 'add_posts.html'
    fields = '__all__'
Django form
{{ form.as_p }} means each box will be surrounded by p tag. Variations are 'as_ul', 'as_table' 
Button 'Post' goes back to home. but how?
-> at models.py, we add get_absolute_urlmethod to redirect (check below)
<form method="POST">
    {% csrf_token %}
    {{ form.as_p }}
    <button class="btn btn-secondary"> Post </button>
-as_table needs table tags around
<table>
<form method="POST">
    {% csrf_token %}
    {{ form.as_table }}
</form>
</table>
 <button class="btn btn-secondary"> Post </button>
? get_absolute_url
to be directed to created post.
from django.urls import reverse
class Post(models.Model):
~
    def get_absolute_url(self): 
        return reverse('article-detail', args=(str(self.id))) 
        	 	#url name
 
class PostForm(forms.ModelForm): 
inherit forms. ModelForm allows us to create form fields for our Post model.
from django import forms
from .models import Post
class PostForm(forms.ModelForm): 
    class Meta:
        model = Post
        fields = ('title', 'title_tag', 'author', 'body')
#for bootstrap
        widgets = {
            'title': forms.TextInput(
            	attrs={'class': 'form-control'}), #css
            'title_tag': forms.TextInput(
            	attrs={'class': 'form-control'}),
            'author': forms.Select(
            	attrs={'class': 'form-control'}), #dropdown
            'body': forms.Textarea(
            	attrs={'class': 'form-control'}),
        }
same as above
path('add_post', AddPostView.as_view(), name="add_post"),
Note that when using form_class, we don't need to specify fields as it's already in form_class.
from .forms import PostForm
class AddPostView(CreateView):
    model = Post
    form_class = PostForm
    template_name = 'add_posts.html'
    
    #fields = '__all__' # no need anymore
<div class="form-group"> and each tag has to have 'class=form-control'  in order to be bootstrap applied. (in our case, it applied in forms.py and template got {{form}} connected. <div class="form-group">
    <form method="POST">
        {% csrf_token %}
        {{ form.as_table }}
        <br/>
        <button class="btn btn-secondary"> Post </button>
    </form>
</div>

widgets = {'title': forms.TextInput(attrs={
	   'class': 'form-control', 
           'placeholder':'This is Title Placeholder'})}

path('article/edit/<int:pk>', 
      UpdatePostView.as_view(), name="update_post"),
UpdateView
Use either form_class or fields. If you use both, It will crash. form_class to use bootstrap. Firelds are default django form. 
pre-populated
class UpdatePostView(UpdateView):
    model = Post
    template_name = 'update_post.html'
    fields = ['title', 'title_tag', 'body']
    #form_class = PostForm
create 'update_post.html'
{% extends 'base.html' %}
{% block title %} Update Post {% endblock %}
{% block content %}
<h1> Update Post </h1>
<br/>
<div class="form-group">
    <form method="POST">
        {% csrf_token %}
        {{ form.as_p }}
        <br/>
        <button class="btn btn-secondary"> Update </button>
    </form>
</div>
{% endblock %}
 <small><a href="{% url 'update_post' post.pk %}"> 
 		  Edit </a></small>
 
path('article/<int:pk>/remove',
	DeletePostView.as_view(), name="delete_post"),
Not like create, 'Post' button, where we used get_absolute_url, Delete doesn't work that way.
use success_url = reverse_lazy('home') instead.
reverse_lazy
from django.urls import reverse_lazy
class DeletePostView(DeleteView):
    model = Post
    template_name = 'delete_post.html'
    success_url = reverse_lazy('home')
 <form method="POST">: even though we don't need a form here, we need to use 'POST' method. Hence, we need a form tag.
<div class="form-group">
        <form method="POST">
        {% csrf_token %}
        <strong> Are you sure you want to delete this post? 
        	</strong><br/><br/>
        <button class="btn btn-secondary"> Delete Post </button>
</div>

Latest one shown on top of the blog list
Put negative id minus'-' for ordering
class HomeView(ListView):
      ~
    ordering = ['-id']
This is kinda hacky way tho, better to use date field. (Photo: 4th one went up! It was on the bottom.)
 
Problem: we need to modify model to add date.
But we have old post(data) that doesn't have date fields, we need to tweak a bit when makemigrations and migrate 
migrate: push the data into DB.
we can check changes in migrations folder.
models.DateField(auto_now_add=True)
automatically assign date 
from datetime import datetime, date
class Post(models.Model):
	~
	post_date = models.DateField(auto_now_add=True)
ordering done by date by using new field DateField in model.
['-post_date'] by latest
class HomeView(ListView):
    model = Post
    template_name = 'home.html'
    ordering = ['-post_date']
{{ post.post_date}}
