Add files via upload
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class LearningLogsConfig(AppConfig):
|
||||
name = 'learning_logs'
|
||||
@@ -0,0 +1,15 @@
|
||||
from django import forms
|
||||
from .models import Topic, Entry
|
||||
|
||||
class TopicForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Topic
|
||||
fields = ['text']
|
||||
labels = {'text': ''}
|
||||
|
||||
class EntryForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Entry
|
||||
fields = ['text']
|
||||
labels = {'text': ''}
|
||||
widgets = {'text': forms.Textarea(attrs={'cols': 80})}
|
||||
@@ -0,0 +1,26 @@
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
# Create your models here.
|
||||
class Topic(models.Model):
|
||||
""" A topic the user is learning about."""
|
||||
text = models.CharField(max_length=200)
|
||||
date_added = models.DateTimeField(auto_now_add=True)
|
||||
owner = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||
|
||||
def __str__(self):
|
||||
""" Return a string representation of the model. """
|
||||
return self.text
|
||||
|
||||
class Entry(models.Model):
|
||||
""" Something specific learned about a topic. """
|
||||
topic = models.ForeignKey(Topic, on_delete=models.CASCADE)
|
||||
text = models.TextField()
|
||||
date_added = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name_plural = 'entries'
|
||||
|
||||
def __str__(self):
|
||||
""" Return a string representation of the model. """
|
||||
return f"{self.text[:50]}..."
|
||||
@@ -0,0 +1,63 @@
|
||||
{% load bootstrap4 %}
|
||||
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1,
|
||||
shrink-to-fit=no">
|
||||
<title>Learning Log</title>
|
||||
|
||||
{% bootstrap_css %}
|
||||
{% bootstrap_javascript jquery='full' %}
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<nav class="navbar navbar-expand-md navbar-light bg-light mb-4 border">
|
||||
|
||||
<a class="navbar-brand" href="{% url 'learning_logs:index'%}">
|
||||
Learning Log</a>
|
||||
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse"
|
||||
data-target="#navbarCollapse" aria-controls="navbarCollapse"
|
||||
aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span></button>
|
||||
<div class="collapse navbar-collapse" id="navbarCollapse">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'learning_logs:topics'%}">
|
||||
Topics</a></li>
|
||||
</ul>
|
||||
<ul class="navbar-nav ml-auto">
|
||||
{% if user.is_authenticated %}
|
||||
<li class="nav-item">
|
||||
<span class="navbar-text"}">Hello, {{ user.username }}.</span>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'users:logout' %}">Log out</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'users:register' %}">Register</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="{% url 'users:login' %}">Log in</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</nav>
|
||||
|
||||
<main role="main" class="container">
|
||||
<div class="pb-2 mb-2 border-bottom">
|
||||
{% block page_header %}{% endblock page_header %}
|
||||
</div>
|
||||
<div>
|
||||
{% block content %}{% endblock content %}
|
||||
</div>
|
||||
</main>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,15 @@
|
||||
{% extends "learning_logs/base.html" %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<p><a href="{% url 'learning_logs:topic' topic.id %}">{{ topic }}</a></p>
|
||||
|
||||
<p>Edit entry:</p>
|
||||
|
||||
<form action="{% url 'learning_logs:edit_entry' entry.id %}" method="POST">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<button name="submit">Save changes</button>
|
||||
</form>
|
||||
|
||||
{% endblock content %}
|
||||
@@ -0,0 +1,14 @@
|
||||
{% extends "learning_logs/base.html" %}
|
||||
|
||||
{% block page_header %}
|
||||
<div class="jumbotron">
|
||||
<h1 class="display-3">Track your learning.</h1>
|
||||
|
||||
<p class="lead">Make your own Learning Log, and keep a list of the
|
||||
topics you're learning about. Whenever you learn something new
|
||||
about a topic, make an entry summarizing what you've learned.</p>
|
||||
|
||||
<a class="btn btn-lg btn-primary" href="{% url 'users:register' %}"
|
||||
role="button">Register »</a>
|
||||
</div>
|
||||
{% endblock page_header %}
|
||||
@@ -0,0 +1,15 @@
|
||||
{% extends "learning_logs/base.html" %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<p><a href="{% url 'learning_logs:topic' topic.id %}">{{ topic }}</a></p>
|
||||
|
||||
<p>Add a new entry:</p>
|
||||
|
||||
<form action="{% url 'learning_logs:new_entry' topic.id %}" method="POST">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<button name="submit">Add entry</button>
|
||||
</form>
|
||||
|
||||
{% endblock content %}
|
||||
@@ -0,0 +1,12 @@
|
||||
{% extends "learning_logs/base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<p>Add a new topic:</p>
|
||||
|
||||
<form action="{% url 'learning_logs:new_topic' %}" method="POST">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<button name="submit">Add topic</button>
|
||||
</form>
|
||||
|
||||
{% endblock content %}
|
||||
@@ -0,0 +1,28 @@
|
||||
{% extends 'learning_logs/base.html' %}
|
||||
|
||||
{% block page_header %}
|
||||
<h3>{{ topic }}</h3>
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block content %}
|
||||
<p>
|
||||
<a href="{% url 'learning_logs:new_entry' topic.id %}">Add new entry</a>
|
||||
</p>
|
||||
|
||||
<ul>
|
||||
{% for entry in entries %}
|
||||
<div class="card mb-3">
|
||||
<h4 class="card-header">
|
||||
{{ entry.date_added|date:'M d, Y H:i' }}
|
||||
<small><a href="{% url 'learning_logs:edit_entry' entry.id %}">
|
||||
edit entry</a></small>
|
||||
</h4>
|
||||
<div class="card-body">
|
||||
{{ entry.text|linebreaks }}
|
||||
</div>
|
||||
</div>
|
||||
{% empty %}
|
||||
<p>There are no entries for this topic yet.</p>
|
||||
{% endfor %}
|
||||
|
||||
{% endblock content %}
|
||||
@@ -0,0 +1,20 @@
|
||||
{% extends "learning_logs/base.html" %}
|
||||
|
||||
{% block page_header %}
|
||||
<h1>Topics</h1>
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block content %}
|
||||
<ul>
|
||||
{% for topic in topics %}
|
||||
<li><h3>
|
||||
<a href="{% url 'learning_logs:topic' topic.id %}">{{ topic }}</a>
|
||||
</h3></li>
|
||||
{% empty %}
|
||||
<li><h3>No topics have been added yet.</h3></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<h3><a href="{% url 'learning_logs:new_topic' %}">Add a new topic</a></h3>
|
||||
|
||||
{% endblock content %}
|
||||
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
@@ -0,0 +1,21 @@
|
||||
""" Define URL patterns for learning_logs. """
|
||||
|
||||
from django.urls import path
|
||||
|
||||
from . import views
|
||||
|
||||
app_name = 'learning_logs'
|
||||
urlpatterns = [
|
||||
# Homepage
|
||||
path('', views.index, name='index'),
|
||||
# Page that shows all topics.
|
||||
path('topics/', views.topics, name='topics'),
|
||||
# Detail page for a single topic.
|
||||
path('topics/<int:topic_id>/', views.topic, name='topic'),
|
||||
# Page for adding a new topic
|
||||
path('new_topic/', views.new_topic, name='new_topic'),
|
||||
# Page for adding a new entry
|
||||
path('new_entry/<int:topic_id>/', views.new_entry, name='new_entry'),
|
||||
# Page for editing an entry
|
||||
path('edit_entry/<int:entry_id>/', views.edit_entry, name='edit_entry'),
|
||||
]
|
||||
@@ -0,0 +1,92 @@
|
||||
from django.shortcuts import render, redirect, get_object_or_404
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.http import Http404
|
||||
|
||||
from .models import Topic, Entry
|
||||
from .forms import TopicForm, EntryForm
|
||||
|
||||
# Create your views here.
|
||||
def index(request):
|
||||
""" The homepage for Learning Log. """
|
||||
return render(request, 'learning_logs/index.html')
|
||||
|
||||
@login_required
|
||||
def topics(request):
|
||||
""" Show all topics. """
|
||||
topics = Topic.objects.filter(owner=request.user).order_by('date_added')
|
||||
context = {'topics': topics}
|
||||
return render(request, 'learning_logs/topics.html', context)
|
||||
|
||||
@login_required
|
||||
def topic(request, topic_id):
|
||||
""" Show a single topic and all its entries. """
|
||||
topic = get_object_or_404(Topic, id=topic_id)
|
||||
# Make sure the topic belongs to the current user
|
||||
if topic.owner != request.user:
|
||||
raise Http404
|
||||
|
||||
|
||||
entries = topic.entry_set.order_by('-date_added')
|
||||
context = {'topic' : topic, 'entries' : entries}
|
||||
return render(request, 'learning_logs/topic.html', context)
|
||||
|
||||
@login_required
|
||||
def new_topic(request):
|
||||
""" Add a new topic. """
|
||||
if request.method != 'POST':
|
||||
# No data submitted; create a blank form.
|
||||
form = TopicForm()
|
||||
else:
|
||||
# POST data submitted; process data.
|
||||
form = TopicForm(data=request.POST)
|
||||
if form.is_valid():
|
||||
new_topic = form.save(commit=False)
|
||||
new_topic.owner = request.user
|
||||
new_topic.save()
|
||||
return redirect('learning_logs:topics')
|
||||
|
||||
# Display a blank or invalid form.
|
||||
context = {'form': form}
|
||||
return render(request, 'learning_logs/new_topic.html', context)
|
||||
|
||||
@login_required
|
||||
def new_entry(request, topic_id):
|
||||
""" Add a new entry for a particular topic. """
|
||||
topic = Topic.objects.get(id=topic_id)
|
||||
|
||||
if request.method != 'POST':
|
||||
# No data submitted; create a blank form.
|
||||
form = EntryForm()
|
||||
else:
|
||||
# POST data submitted; process data.
|
||||
form = EntryForm(data=request.POST)
|
||||
if form.is_valid():
|
||||
new_entry = form.save(commit=False)
|
||||
new_entry.topic = topic
|
||||
new_entry.save()
|
||||
return redirect('learning_logs:topic', topic_id=topic_id)
|
||||
|
||||
# Display a blank or valid form.
|
||||
context = {'topic': topic, 'form': form}
|
||||
return render(request, 'learning_logs/new_entry.html', context)
|
||||
|
||||
@login_required
|
||||
def edit_entry(request, entry_id):
|
||||
""" Edit an existing entry. """
|
||||
entry = Entry.objects.get(id=entry_id)
|
||||
topic = entry.topic
|
||||
if topic.owner != request.user:
|
||||
raise Http404
|
||||
|
||||
if request.method != 'POST':
|
||||
# Initial request; pre-fill form with the current entry.
|
||||
form = EntryForm(instance=entry)
|
||||
else:
|
||||
# POST data submitted; process data.
|
||||
form = EntryForm(instance=entry, data=request.POST)
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
return redirect('learning_logs:topic', topic_id=topic.id)
|
||||
|
||||
context = {'entry': entry, 'topic': topic, 'form': form}
|
||||
return render(request, 'learning_logs/edit_entry.html', context)
|
||||
Reference in New Issue
Block a user