diff --git a/en/authentication_authorization/README.md b/en/authentication_authorization/README.md
index cd29f51..c128f96 100644
--- a/en/authentication_authorization/README.md
+++ b/en/authentication_authorization/README.md
@@ -8,12 +8,14 @@ First let's make things secure. We will protect our `post_new`, `post_edit`, `po
So edit your `blog/views.py` and add these lines at the top along with the rest of the imports:
+{% filename %}blog/views.py{% endfilename %}
```python
from django.contrib.auth.decorators import login_required
```
Then add a line before each of the `post_new`, `post_edit`, `post_draft_list`, `post_remove` and `post_publish` views (decorating them) like the following:
+{% filename %}blog/views.py{% endfilename %}
```python
@login_required
def post_new(request):
@@ -37,6 +39,7 @@ We could now try to do lots of magical stuff to implement users and passwords an
In your `mysite/urls.py` add a url `path('accounts/login/', views.LoginView.as_view(), name='login')`. So the file should now look similar to this:
+{% filename %}mysite/urls.py{% endfilename %}
```python
from django.urls import path, include
from django.contrib import admin
@@ -52,6 +55,7 @@ urlpatterns = [
Then we need a template for the login page, so create a directory `blog/templates/registration` and a file inside named `login.html`:
+{% filename %}blog/templates/registration/login.html{% endfilename %}
```django
{% extends "blog/base.html" %}
@@ -83,6 +87,7 @@ You will see that this also makes use of our _base_ template for the overall loo
The nice thing here is that this _just worksTM_. We don't have to deal with handling of the form submission nor with passwords and securing them. Only more thing is left to do. We should add a setting to `mysite/settings.py`:
+{% filename %}mysite/settings.py{% endfilename %}
```python
LOGIN_REDIRECT_URL = '/'
```
@@ -93,22 +98,27 @@ so that when the login page is accessed directly, it will redirect a successful
We already set things up so that only authorized users (i.e. us) see the buttons for adding and editing posts. Now we want to make sure a login button appears for everybody else.
-We will add a login button that looks like this:
+We will add a login button using an unlock icon.
+
+Download the unlock image from [https://icons.getbootstrap.com/assets/icons/unlock.svg](https://icons.getbootstrap.com/assets/icons/unlock.svg) and save it in the folder `blog/templates/registration/icons/`
+
+We will add the login button like this
```django
-
+
```
-For this we need to edit the templates, so let's open up `blog/templates/blog/base.html` and change it so the part between the `
` tags looks like this:
+We want to ensure the button is only visible to non-authenticated users, so let's open up `base.html` and change it so the part between the `` tags looks like this:
+{% filename %}blog/templates/blog/base.html{% endfilename %}
```django
@@ -123,20 +133,21 @@ For this we need to edit the templates, so let's open up `blog/templates/blog/ba
```
-You might recognize the pattern here. There is an if-condition in the template that checks for authenticated users to show the add and edit buttons. Otherwise it shows a login button.
+You might recognize the pattern here. There is an if-condition in the template that checks for authenticated users to show the add and edit buttons. {% raw %}`{% else %}`{% endraw %} it shows a login button.
## More on authenticated users
-Let's add some sugar to our templates while we're at it. First we will add some details to show when we are logged in. Edit `blog/templates/blog/base.html` like this:
+Let's add some sugar to our templates while we're at it. First we will add some details to show when we are logged in. Edit `base.html` like this:
+{% filename %}blog/templates/blog/base.html{% endfilename %}
```django
@@ -148,6 +159,7 @@ We decided to rely on Django to handle login, so let's see if Django can also ha
Done reading? By now you may be thinking about adding a URL in `mysite/urls.py` pointing to Django's logout view (i.e. `django.contrib.auth.views.logout`), like this:
+{% filename %}mysite/urls.py{% endfilename %}
```python
from django.urls import path, include
from django.contrib import admin
@@ -162,6 +174,30 @@ urlpatterns = [
]
```
+## Is there anything missing?
+
+We made sure non-logged in users can't access the `post_draft_list` view by using the `@login_required` decorator. We also decorated the `post_edit`, `post_remove` and `post_publish` views so they can't make changes. But could a non-logged in user still see a draft post?
+
+While logged out, try navigating to a draft post by editing the url address bar directly. Whoops! We can still see the draft post!
+
+This is because we use the `post_detail()` view method for both published and draft posts. We need to protect this view as well. We definitely want non-logged in users to see published posts, so using the decorator won't work.
+
+Instead, let's go to the `blog/views.py` file and update the `post_detail()` view to check for a `published_date` or whether a `user` `is_authenticated`. If neither condition is true, we will redirect the user to login.
+
+{% filename %}blog/views.py{% endfilename %}
+```
+def post_detail(request, pk):
+ post = get_object_or_404(Post, pk=pk)
+ if post.published_date or request.user.is_authenticated:
+ return render(request, 'blog/post_detail.html', {'post': post})
+ else:
+ return redirect("/accounts/login/")
+```
+
+Check again if you can navigate directly to a draft post using the address bar.
+
+
+
That's it! If you followed all of the above up to this point (and did the homework), you now have a blog where you
- need a username and password to log in,
diff --git a/en/homework/README.md b/en/homework/README.md
index 227346b..ac14df2 100644
--- a/en/homework/README.md
+++ b/en/homework/README.md
@@ -6,6 +6,7 @@ Our blog has come a long way but there's still room for improvement. Next, we wi
Currently when we're creating new posts using our *New post* form the post is published directly. To instead save the post as a draft, **remove** this line in `blog/views.py` in the `post_new` and `post_edit` methods:
+{% filename %}blog/views.py{% endfilename %}
```python
post.published_date = timezone.now()
```
@@ -18,20 +19,23 @@ Remember the chapter about querysets? We created a view `post_list` that display
Time to do something similar, but for draft posts.
-Let's add a link in `blog/templates/blog/base.html` in the header. We don't want to show our list of drafts to everybody, so we'll put it inside the {% raw %}`{% if user.is_authenticated %}`{% endraw %} check, right after the button for adding new posts.
+Let's add a link to the header.of our `base.html` template. We don't want to show our list of drafts to everybody, so we'll put it inside the {% raw %}`{% if user.is_authenticated %}`{% endraw %} check, right after the button for adding new posts.
+{% filename %}blog/templates/blog/base.html{% endfilename %}
```django
-
+
```
-Next: urls! In `blog/urls.py` we add:
+Next we define the url path!
+{% filename %}blog/urls.py{% endfilename %}
```python
path('drafts/', views.post_draft_list, name='post_draft_list'),
```
-Time to create a view in `blog/views.py`:
+Time to create a view:
+{% filename %}blog/views.py{% endfilename %}
```python
def post_draft_list(request):
posts = Post.objects.filter(published_date__isnull=True).order_by('created_date')
@@ -40,8 +44,9 @@ def post_draft_list(request):
The line ` posts = Post.objects.filter(published_date__isnull=True).order_by('created_date')` makes sure that we take only unpublished posts (`published_date__isnull=True`) and order them by `created_date` (`order_by('created_date')`).
-Ok, the last bit is of course a template! Create a file `blog/templates/blog/post_draft_list.html` and add the following:
+Ok, the last bit is of course a template! Create a new template file `post_draft_list.html` and add the following:
+{% filename %}blog/templates/blog/post_draft_list.html{% endfilename %}
```django
{% extends 'blog/base.html' %}
@@ -66,8 +71,9 @@ Yay! Your first task is done!
It would be nice to have a button on the blog post detail page that will immediately publish the post, right?
-Let's open `blog/templates/blog/post_detail.html` and change these lines:
+Let's open `post_detail.html` and change these lines:
+{% filename %}blog/templates/blog/post_detail.html{% endfilename %}
```django
{% if post.published_date %}
@@ -78,26 +84,29 @@ Let's open `blog/templates/blog/post_detail.html` and change these lines:
into these:
+{% filename %}blog/templates/blog/post_detail.html{% endfilename %}
```django
{% if post.published_date %}
{{ post.published_date }}
{% else %}
-
Publish
+
Publish
{% endif %}
```
-As you noticed, we added {% raw %}`{% else %}`{% endraw %} line here. That means, that if the condition from {% raw %}`{% if post.published_date %}`{% endraw %} is not fulfilled (so if there is no `published_date`), then we want to do the line {% raw %}`
Publish`{% endraw %}. Note that we are passing a `pk` variable in the {% raw %}`{% url %}`{% endraw %}.
+As you noticed, we added {% raw %}`{% else %}`{% endraw %} line here. That means, that if the condition from {% raw %}`{% if post.published_date %}`{% endraw %} is not fulfilled (so if there is no `published_date`), then we want to do the line {% raw %}`
Publish`{% endraw %}. Note that we are passing a `pk` variable in the {% raw %}`{% url %}`{% endraw %}.
-Time to create a URL (in `blog/urls.py`):
+Time to create a URL:
+{% filename %}blog/urls.py{% endfilename %}
```python
path('post/
/publish/', views.post_publish, name='post_publish'),
```
-and finally, a *view* (as always, in `blog/views.py`):
+and finally, a *view*:
+{% filename %}blog/views.py{% endfilename %}
```python
def post_publish(request, pk):
post = get_object_or_404(Post, pk=pk)
@@ -107,6 +116,7 @@ def post_publish(request, pk):
Remember, when we created a `Post` model we wrote a method `publish`. It looked like this:
+{% filename %}blog/models.py{% endfilename %}
```python
def publish(self):
self.published_date = timezone.now()
@@ -123,22 +133,25 @@ Congratulations! You are almost there. The last step is adding a delete button!
## Delete post
-Let's open `blog/templates/blog/post_detail.html` once again and add this line:
+First let's download a trash icon and save with others in `blog/templates/blog/icons/`: [https://icons.getbootstrap.com/assets/icons/trash.svg](https://icons.getbootstrap.com/assets/icons/trash.svg)
+Let's open `post_detail.html` once again and add this line just under the line with the edit button:
+
+{% filename %}blog/templates/blog/post_detail.html{% endfilename %}
```django
-
+ {% include './icons/trash3.svg' %}
```
-just under a line with the edit button.
-
-Now we need a URL (`blog/urls.py`):
+Now we need a URL:
+{% filename %}blog/urls.py{% endfilename %}
```python
path('post//remove/', views.post_remove, name='post_remove'),
```
-Now, time for a view! Open `blog/views.py` and add this code:
+Now, time for a view!
+{% filename %}blog/views.py{% endfilename %}
```python
def post_remove(request, pk):
post = get_object_or_404(Post, pk=pk)
diff --git a/en/homework_create_more_models/README.md b/en/homework_create_more_models/README.md
index e3b3583..4fcd188 100644
--- a/en/homework_create_more_models/README.md
+++ b/en/homework_create_more_models/README.md
@@ -6,6 +6,7 @@ Currently, we only have a Post model. What about receiving some feedback from yo
Let's open `blog/models.py` and append this piece of code to the end of file:
+{% filename %}blog/models.py{% endfilename %}
```python
class Comment(models.Model):
post = models.ForeignKey('blog.Post', on_delete=models.CASCADE, related_name='comments')
@@ -55,6 +56,7 @@ Our Comment model exists in the database now! Wouldn't it be nice if we had acce
To register the Comment model in the admin panel, go to `blog/admin.py` and add this line:
+{% filename %}blog/admin.py{% endfilename %}
```python
admin.site.register(Comment)
```
@@ -67,6 +69,7 @@ admin.site.register(Post)
Remember to import the Comment model at the top of the file, too, like this:
+{% filename %}blog/admin.py{% endfilename %}
```python
from django.contrib import admin
from .models import Post, Comment
@@ -79,8 +82,9 @@ If you type `python manage.py runserver` on the command line and go to [http://1
## Make our comments visible
-Go to the `blog/templates/blog/post_detail.html` file and add the following lines before the {% raw %}`{% endblock %}`{% endraw %} tag:
+Go to the `post_detail.html` file and add the following lines before the {% raw %}`{% endblock %}`{% endraw %} tag:
+{% filename %}blog/templates/blog/post_detail.html{% endfilename %}
```django
{% for comment in post.comments.all %}
@@ -96,22 +100,25 @@ Go to the `blog/templates/blog/post_detail.html` file and add the following line
Now we can see the comments section on pages with post details.
-But it could look a little bit better, so let's add some CSS to the bottom of the `static/css/blog.css` file:
+But it could look a little bit better, so let's add some configuration to the CSS file:
+{% filename %}static/css/blog.css{% endfilename %}
```css
.comment {
margin: 20px 0px 20px 20px;
}
```
-We can also let visitors know about comments on the post list page. Go to the `blog/templates/blog/post_list.html` file and add the line:
+We can also let visitors know about comments on the post list page. Go to the `post_list.html` file and add the line:
+{% filename %}blog/templates/blog/post_list.html{% endfilename %}
```django
Comments: {{ post.comments.count }}
```
After that our template should look like this:
+{% filename %}blog/templates/blog/post_list.html{% endfilename %}
```django
{% extends 'blog/base.html' %}
@@ -135,6 +142,7 @@ Right now we can see comments on our blog, but we can't add them. Let's change t
Go to `blog/forms.py` and add the following lines to the end of the file:
+{% filename %}blog/forms.py{% endfilename %}
```python
class CommentForm(forms.ModelForm):
@@ -151,12 +159,14 @@ from .models import Post
into:
+{% filename %}blog/forms.py{% endfilename %}
```python
from .models import Post, Comment
```
-Now, go to `blog/templates/blog/post_detail.html` and before the line {% raw %}`{% for comment in post.comments.all %}`{% endraw %}, add:
+Now, go to `post_detail.html` and before the line {% raw %}`{% for comment in post.comments.all %}`{% endraw %}, add:
+{% filename %}blog/templates/blog/post_detail.html{% endfilename %}
```django
Add comment
```
@@ -167,6 +177,7 @@ If you go to the post detail page you should see this error:
We know how to fix that! Go to `blog/urls.py` and add this pattern to `urlpatterns`:
+{% filename %}blog/urls.py{% endfilename %}
```python
path('post//comment/', views.add_comment_to_post, name='add_comment_to_post'),
```
@@ -175,8 +186,9 @@ Refresh the page, and we get a different error!

-To fix this error, add this view to `blog/views.py`:
+To fix this error, add this view:
+{% filename %}blog/views.py{% endfilename %}
```python
def add_comment_to_post(request, pk):
post = get_object_or_404(Post, pk=pk)
@@ -194,6 +206,7 @@ def add_comment_to_post(request, pk):
Remember to import `CommentForm` at the beginning of the file:
+{% filename %}blog/views.py{% endfilename %}
```python
from .forms import PostForm, CommentForm
```
@@ -208,8 +221,9 @@ However, when you click that button, you'll see:

-Like the error tells us, the template doesn't exist yet. So, let's create a new one at `blog/templates/blog/add_comment_to_post.html` and add the following code:
+Like the error tells us, the template doesn't exist yet. So, let's create a new one at `add_comment_to_post.html` and add the following code:
+{% filename %}blog/templates/blog/add_comment_to_post.html{% endfilename %}
```django
{% extends 'blog/base.html' %}
@@ -230,8 +244,9 @@ Not all of the comments should be displayed. As the blog owner, you probably wan
> If you haven't already, you can download all the Bootstrap icons [here](https://github.com/twbs/icons/releases/download/v1.1.0/bootstrap-icons-1.1.0.zip). Unzip the file and copy all the SVG image files into a new folder inside `blog/templates/blog/` called `icons`. That way you can access an icon like `hand-thumbs-down.svg` using the file path `blog/templates/blog/icons/hand-thumbs-down.svg`
-Go to `blog/templates/blog/post_detail.html` and change lines:
+Go to `post_detail.html` and change lines:
+{% filename %}blog/templates/blog/post_detail.html{% endfilename %}
```django
{% for comment in post.comments.all %}