Skip to content

Commit

Permalink
Merge branch 'master' into python-f-string
Browse files Browse the repository at this point in the history
  • Loading branch information
KateFinegan authored Oct 11, 2023
2 parents 096c371 + 7bcdde2 commit 4404159
Show file tree
Hide file tree
Showing 33 changed files with 704 additions and 1 deletion.
57 changes: 57 additions & 0 deletions build-a-blog-from-scratch-django/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Create Your Own Blog With Django

Follow the [step-by-step instructions](https://realpython.com/get-started-with-django-1/) on Real Python to build your own blog with Django.

## Setup

You can run the provided example project on your local machine by following the steps outlined below.

Create a new virtual environment:

```bash
$ python3 -m venv venv
```

Activate the virtual environment:

```bash
$ source venv/bin/activate
```

Install the dependencies for this project if you haven't installed them yet:

```bash
(venv) $ python -m pip install -r requirements.txt
```

Make and apply the migrations for the project to build your local database:

```bash
(venv) $ python manage.py makemigrations
(venv) $ python manage.py migrate
```

Run the Django development server:

```bash
(venv) $ python manage.py runserver
```

Navigate to `http://localhost:8000/` to see your blog in action.

## Using the Django Admin site

To create new posts, you need to create a superuser:

```bash
(venv) $ python manage.py createsuperuser
Username (leave blank to use 'root'): admin
Email address: [email protected]
Password: RealPyth0n
Password (again): RealPyth0n
Superuser created successfully.
```

When running the `createsuperuser` managemant command you're prompted to choose a username, provide an email address, and set a password. Use your own data for these fields and make sure to remember them.

Navigate to `http://localhost:8000/admin` and log in with the credentials you just used to create a superuser.
Empty file.
19 changes: 19 additions & 0 deletions build-a-blog-from-scratch-django/django-blog/blog/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from django.contrib import admin
from blog.models import Category, Comment, Post


class CategoryAdmin(admin.ModelAdmin):
pass


class PostAdmin(admin.ModelAdmin):
pass


class CommentAdmin(admin.ModelAdmin):
pass


admin.site.register(Category, CategoryAdmin)
admin.site.register(Post, PostAdmin)
admin.site.register(Comment, CommentAdmin)
6 changes: 6 additions & 0 deletions build-a-blog-from-scratch-django/django-blog/blog/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.apps import AppConfig


class BlogConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "blog"
15 changes: 15 additions & 0 deletions build-a-blog-from-scratch-django/django-blog/blog/forms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from django import forms


class CommentForm(forms.Form):
author = forms.CharField(
max_length=60,
widget=forms.TextInput(
attrs={"class": "form-control", "placeholder": "Your Name"}
),
)
body = forms.CharField(
widget=forms.Textarea(
attrs={"class": "form-control", "placeholder": "Leave a comment!"}
)
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Generated by Django 4.2.4 on 2023-08-29 12:43

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

initial = True

dependencies = [
]

operations = [
migrations.CreateModel(
name='Category',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=30)),
],
),
migrations.CreateModel(
name='Post',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=255)),
('body', models.TextField()),
('created_on', models.DateTimeField(auto_now_add=True)),
('last_modified', models.DateTimeField(auto_now=True)),
('categories', models.ManyToManyField(related_name='posts', to='blog.category')),
],
),
migrations.CreateModel(
name='Comment',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('author', models.CharField(max_length=60)),
('body', models.TextField()),
('created_on', models.DateTimeField(auto_now_add=True)),
('post', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='blog.post')),
],
),
]
Empty file.
32 changes: 32 additions & 0 deletions build-a-blog-from-scratch-django/django-blog/blog/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from django.db import models


class Category(models.Model):
name = models.CharField(max_length=30)

class Meta:
verbose_name_plural = "categories"

def __str__(self):
return self.name


class Post(models.Model):
title = models.CharField(max_length=255)
body = models.TextField()
created_on = models.DateTimeField(auto_now_add=True)
last_modified = models.DateTimeField(auto_now=True)
categories = models.ManyToManyField("Category", related_name="posts")

def __str__(self):
return self.title


class Comment(models.Model):
author = models.CharField(max_length=60)
body = models.TextField()
created_on = models.DateTimeField(auto_now_add=True)
post = models.ForeignKey("Post", on_delete=models.CASCADE)

def __str__(self):
return f"{self.author} on '{self.post}'"
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{% extends "blog/index.html" %}

{% block page_title %}
<h2>{{ category }}</h2>
{% endblock page_title %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{% extends "base.html" %}

{% block page_title %}
<h2>{{ post.title }}</h2>
{% endblock page_title %}

{% block page_content %}
<small>
{{ post.created_on.date }} | Categories:
{% for category in post.categories.all %}
<a href="{% url 'blog_category' category.name %}">
{{ category.name }}
</a>
{% endfor %}
</small>
<p>{{ post.body | linebreaks }}</p>

<h3>Leave a comment:</h3>
<form method="post">
{% csrf_token %}
<div class="form-group">
{{ form.author }}
</div>
<div class="form-group">
{{ form.body }}
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>

<h3>Comments:</h3>
{% for comment in comments %}
<p>
On {{ comment.created_on.date }} <b>{{ comment.author }}</b> wrote:
</p>
<p>
{{ comment.body | linebreaks }}
</p>
{% endfor %}
{% endblock page_content %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{% extends "base.html" %}

{% block page_title %}
<h2>Blog Posts</h2>
{% endblock page_title %}

{% block page_content %}
{% block posts %}
{% for post in posts %}
<h3><a href="{% url 'blog_detail' post.pk %}">{{ post.title }}</a></h3>
<small>
{{ post.created_on.date }} | Categories:
{% for category in post.categories.all %}
<a href="{% url 'blog_category' category.name %}">
{{ category.name }}
</a>
{% endfor %}
</small>
<p>{{ post.body | slice:":400" }}...</p>
{% endfor %}
{% endblock posts %}
{% endblock page_content %}
8 changes: 8 additions & 0 deletions build-a-blog-from-scratch-django/django-blog/blog/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from django.urls import path
from . import views

urlpatterns = [
path("", views.blog_index, name="blog_index"),
path("post/<int:pk>/", views.blog_detail, name="blog_detail"),
path("category/<category>/", views.blog_category, name="blog_category"),
]
38 changes: 38 additions & 0 deletions build-a-blog-from-scratch-django/django-blog/blog/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from django.http import HttpResponseRedirect
from django.shortcuts import render

from blog.forms import CommentForm
from blog.models import Comment, Post


def blog_index(request):
posts = Post.objects.all().order_by("-created_on")
context = {"posts": posts}
return render(request, "blog/index.html", context)


def blog_category(request, category):
posts = Post.objects.filter(categories__name__contains=category).order_by(
"-created_on"
)
context = {"category": category, "posts": posts}
return render(request, "blog/category.html", context)


def blog_detail(request, pk):
post = Post.objects.get(pk=pk)
form = CommentForm()
if request.method == "POST":
form = CommentForm(request.POST)
if form.is_valid():
comment = Comment(
author=form.cleaned_data["author"],
body=form.cleaned_data["body"],
post=post,
)
comment.save()
return HttpResponseRedirect(request.path_info)
comments = Comment.objects.filter(post=post)
context = {"post": post, "comments": comments, "form": form}

return render(request, "blog/detail.html", context)
22 changes: 22 additions & 0 deletions build-a-blog-from-scratch-django/django-blog/manage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys


def main():
"""Run administrative tasks."""
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "personal_blog.settings")
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)


if __name__ == "__main__":
main()
Empty file.
16 changes: 16 additions & 0 deletions build-a-blog-from-scratch-django/django-blog/personal_blog/asgi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""
ASGI config for personal_blog project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/
"""

import os

from django.core.asgi import get_asgi_application

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "personal_blog.settings")

application = get_asgi_application()
Loading

0 comments on commit 4404159

Please sign in to comment.