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_url
method 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}}