In this chapter we will be designing a simple pastebin. Our pastebin will be able to
- Allow users to paste some text
- Allow users to edit or delete the text
- Allow users to view all texts
- Clean up texts older than a day
Some ‘views’ that the user will see are
- A list view of all recent texts
- A detail view of any selected text
- An entry/edit form for a text
- A view to delete a text
Our work flow for this app would be
- sketch the models
- route urls to generic views
- use generic views with our models
- write the templates to use generic views
$ mkdir chapter3 && cd chapter3
$ django-admin.py startproject chap3 .
$ python manage.py startapp pastebin
# chap3/settings.py
INSTALLED_APPS = [
...
'pastebin.apps.PastebinConfig',
]
# pastebin/models.py
from django.db import models
from django.urls import reverse
# Create your models here.
class Paste(models.Model):
text = models.TextField()
name = models.CharField(max_length=40, null=True, blank=True)
created_on = models.DateTimeField(auto_now_add=True)
updated_on = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name or str(self.id)
def get_absolute_url(self):
return reverse('pastebin_paste_detail', args=[str(self.id)])
$ python manage.py makemigrations
$ python manage.py migrate
# chap3/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('pastebin/', include('pastebin.urls')),
]
from django.urls import path
from .views import PasteCreate, PasteDetail, PasteList, PasteDelete, PasteUpdate
urlpatterns = [
path(r'', PasteCreate.as_view(), name='pastebin_paste_create'),
path('paste/<int:pk>', PasteDetail.as_view(), name='pastebin_paste_detail'),
path('pastes/', PasteList.as_view(), name='pastebin_paste_list'),
path('paste/delete/<int:pk>', PasteDelete.as_view(), name='pastebin_paste_delete'),
path('paste/edit/<int:pk>', PasteUpdate.as_view(), name='pastebin_paste_edit'),
]
# chap3/views.py
from django.urls import reverse_lazy
from django.views.generic import DeleteView
from django.views.generic.edit import CreateView, UpdateView
from django.views.generic.detail import DetailView
from django.views.generic.list import ListView
from .models import Paste
class PasteCreate(CreateView):
model = Paste
fields = ['text','name']
class PasteDetail(DetailView):
model = Paste
template_name = "pastebin/paste_detail.html"
class PasteList(ListView):
model = Paste
template_name = "pastebin/paste_list.html"
queryset = Paste.objects.all()
context_object_name = 'queryset'
class PasteDelete(DeleteView):
model = Paste
success_url = reverse_lazy('pastebin_paste_list')
class PasteUpdate(UpdateView):
model = Paste
fields = ['text', 'name']
<!-- templates/pastebin/paste_form.html -->
<h1>Create new Paste</h1>
<form action="" method="POST">
{% csrf_token %}
<table>
{{ form.as_table }}
</table>
<input type="submit" name="create" value="Create">
</form>
<!-- templates/pastebin/paste_detail.html -->
{% if messages %}
<div class="messages">
<ul>
{% for message in messages %}
<li class="{{ message.tag }}">
{{ message }}
</li>
{% endfor %}
</ul>
</div>
{% endif %}
<h1>Paste Details: </h1>
<p>
<div>
<label>ID</label>
<span>{{ object.id }}</span>
</div>
<div>
<label>Name</label>
<span>{{ object.name }}</span>
</div>
<div>
<label>Text</label>
<textarea rows="10" cols="50" OnClick="this.select();" readonly="true">{{ object.text }}</textarea>
</div>
<div>
<label>Created</label>
<span>{{ object.created_on }}</span>
</div>
<div>
<label>Modified</label>
<span>{{ object.updated_on }}</span>
</div>
</p>
<h2>Actions</h2>
<ul>
<li>
<a href="{% url 'pastebin_paste_edit' object.id %}">Edit this paste</a>
</li>
<li>
<a href="{% url 'pastebin_paste_delete' object.id %}">Delete this paste</a>
</li>
</ul>
<a href="{% url 'pastebin_paste_list' %}">View All</a>
<!-- templates/pastebin/paste_list.html -->
{% if messages %}
<div class="messages">
<ul>
{% for message in messages %}
<li class="{{ message.tag }}">
{{ message }}
</li>
{% endfor %}
</ul>
</div>
{% endif %}
{% if object_list %}
<h1>Recent Pastes:</h1>
<ul>
{% for paste in object_list %}
<li>
<a href="{% url 'pastebin_paste_detail' paste.id %}">{{ paste }}</a>
</li>
{% endfor %}
</ul>
{% else %}
<h1>No recent pastes</h1>
{% endif %}
<a href="{% url 'pastebin_paste_create' %}">Create new</a>
<!-- templates/pastebin/paste_confirm_delete.html -->
<h1>Really delete paste {{ object }}?</h1>
<h2>This action cannot be undone</h2>
<form action="{% url 'pastebin_paste_delete' object.id %}" method="POST">
{% csrf_token %}
<input type="submit" value="Delete">
</form>
$ mkdir -p pastebin/management/commands
# pastebin/management/commands/delete_old.py
import datetime
from django.core.management.base import BaseCommand
from pastebin.models import Paste
class Command(BaseCommand):
help = """
deletes pastes not updated in last 24 hrs
Use this subcommand in a cron job
to clear older pastes
"""
def handle(self, **options):
now = datetime.datetime.now()
yesterday = now - datetime.timedelta(1)
old_pastes = Paste.objects.filter(updated_on__lte=yesterday)
old_pastes.delete()
$ python manage.py delete_old