[PYTHON] Django Girls Tutorial Note

It is a study memo of django girls tutorial https://tutorial.djangogirls.org/ja/

Trial environment

Since it is a tutorial that deploys using PaaS called PythonAnywhere, it can be done in any environment where python and git can be installed. The environment construction is also in the tutorial, so if you do not have python and git, please refer to the link below. https://tutorial.djangogirls.org/ja/python_installation/

1. Create a project and run it

First, create a project directory in a suitable location. This time I created a project in / home / username / django / proj1.

terminal


mkdir django
cd django
django-admin startproject proj1

The following files will be created automatically.

/home/User name/django/proj1/


proj1
├── manage.py
├── mysite
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── myvenv
│   └── ...
└── requirements.txt

Write the necessary settings in the settings file settings.py.

Time zone and language

Below, it is set to Japan Standard Time and Japanese.

setting.py


TIME_ZONE = 'Asia/Tokyo'
LANGUAGE_CODE = 'ja'

Static file PATH

setting.py


STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')

URLs that allow reading

If ALLOWED_HOST is set to *, it will be possible to read to all URLs, but it will be vulnerable to http injection attacks. Make sure to add only the URLs you need to the list. This time, after testing with localhost on a simple server, we will deploy to pythonanywhere.com, so add the following two.

setting.py


ALLOWED_HOSTS = ['127.0.0.1', '.pythonanywhere.com']

Database settings

When using sqlite3, do as follows.

setting.py


DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

Start django's test server

Try running the temporary server and see what happened.

terminal


python manage.py migrate
python manage.py runserver

Open http: // localhost: 8000 in your browser and you should see the django sample page. Since the part related to the displayed contents has not been changed, the default sample page is displayed.

2. Create a model

Since it is possible to create multiple apps in the project, we will create a blog app in a directory called blog.

terminal


python manage.py startapp blog

A directory named blog will be added as shown below.

/home/User name/django/proj1/


proj1
├── blog
│   ├── admin.py
│   ├── apps.py
│   ├── __init__.py
│   ├── migrations
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── db.sqlite3
├── manage.py
├── mysite
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── myvenv
│   └── ...
└── requirements.txt

Add the added app to INSTALLED_APPS in settings.py so that django will come to read it.

setting.py


INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'blog.apps.BlogConfig',
]

I will write the model part that corresponds to M of the MVC model of models.py. model is responsible for the backend part such as reading and writing the database and processing data.

Inherit the django.db.models.Model class

models.py


from django.conf import settings
from django.db import models
from django.utils import timezone


class Post(models.Model):
    author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    title = models.CharField(max_length=200)
    text = models.TextField()
    created_date = models.DateTimeField(default=timezone.now)
    published_date = models.DateTimeField(blank=True, null=True)

    def publish(self):
        self.published_date = timezone.now()
        self.save()

    def __str__(self):
        return self.title
models.CharField – A field that defines text with a limited number of characters
models.TextField – This is for long, unrestricted text. It's an ideal field for blog post content, right?
models.DateTimeField – Date and time fields
models.ForeignKey – This is a link to another model

Add the model you created to the database.

terminal


python manage.py makemigrations blog
python manage.py migrate blog

result


Operations to perform:
  Apply all migrations: blog
Running migrations:
  Applying blog.0001_initial... OK

If it is displayed as above, migration is successful.

3. Add model to admin page

In order to make the model created earlier visible from the management screen, import the Post class created earlier with from .models import Post and add admin.site.register (Post) to admin.py.

blog/admin.py


from django.contrib import admin
from .models import Post

admin.site.register(Post)

Create a django super user who can log in to the admin screen.

python manage.py createsuperuser

Open the management screen. http://localhost:8000/admin/ Enter your Username and Password to enter the management screen. image.png You can add posts by pressing the add button to the right of Posts. image.png I will fill in a suitable Post. image.png Apparently the model is working fine.

By the way, the top page is still a rocket because I haven't changed the view yet. http://localhost:8000/

4. Deploy

In this chapter we will create a repository on github and deploy a blog on PythonAnywhere.

push to github

First, log in to github and create a repository. The repository name should be my-first-blog. If you do not have an account, you can create one for free, so create one. https://github.com/

Open terminal and install git.

terminal


sudo apt install git

Once installed, git init in the project directory (/ home / username / django / proj1 / in this case) and then register your username and email address. The following is for the user name "hoge" and email address "[email protected]".

terminal


git init
git config --global user.name hoge
git config --global user.email [email protected]

Register files / directories that are not reflected in git in .gitignore.

/home/username/django/proj1/.gitignore


*.pyc
*~
/.vscode
__pycache__
myvenv
db.sqlite3
/static
.DS_Store

Make sure that .gitignore is reflected.

terminal


git status

output


On branch master

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)

        .gitignore
        blog/
        manage.py
        mysite/

nothing added to commit but untracked files present (use "git add" to track)

It seems that it is reflected safely, so push it to github.

terminal


git add --all
git commit -m "first commit"
git remote add origin https://github.com/username/my-first-blog.git
git push -u origin master

If you can push normally, the file will be displayed in the repository of github. image.png

Deploy to PythonAnywhere

Create a Python AnyWhere account https://www.pythonanywhere.com/

After creating an account, go to the Account page from the menu on the upper right and create an API Token. image.png

Open the New console at the bottom left of the Dashboard. image.png When opened, the console will open as shown below. image.png Install the helper tool and deploy the contents of github with the helper tool.

PythonAnywhere_command-line


pip3.6 install --user pythonanywhere
pa_autoconfigure_django.py --python=3.6 https://github.com/github username/my-first-blog.git

Let's check the files synchronized with the ls command.

PythonAnywhere_command-line


$ ls
blog  db.sqlite3  manage.py  proj1  static
$ ls blog/
__init__.py  __pycache__  admin.py  apps.py  migrations  models.py  tests.py  views.py

You can also check it from the Files page of PythonAnywhere. image.png Since the helper tool is building a new virtual environment using the code of github, the django superuser created earlier is not registered yet, so register it with the command below.

PythonAnywhere_command-line


python manage.py createsuperuser

Now the same thing you made locally will be published on the internet. If you go to the Web Apps page from the PythonAnywhere Dashboard, you will find a link to the site that you can open from there.

When you enter the management screen, you can see that there is no Post yet. This is because the database is not synced to github as it is written in .gitignore. The .gitignore setting is very important so that you don't inadvertently overwrite the production DB. image.png

5. Make a view

Here, we will create a view to actually display the page and write a link to the view.

Write a link to view

When I open urls.py, it says something like the following, and when I come to http: // localhost / admin /, it is specified to refer to admin.site.urls. I haven't specified a link to the blog view yet, so I'll write this.

proj1/urls.py


from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('blog.urls')),
]

When you come to the top page http: // localhost /, add it to refer to proj1 / blog / urls.py.

proj1/urls.py


from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('blog.urls')),
]

Create a blog.urls.py and tell it to reference the view named post_list from blog / views.py when you come to http: // localhost /.

proj1/blog/urls.py


from django.urls import path
from . import views

urlpatterns = [
    path('', views.post_list, name='post_list'),
]

Write the post_list function set to be referenced above in views.py. Here, the contents of blog / post_list.html are returned as they are.

blog/views.py


from django.shortcuts import render

def post_list(request):
    return render(request, 'blog/post_list.html', {})

Now, when you come to http: // localhost /, the link will be connected to proj1 / urls.py → proj1 / blog / urls.py → proj1 / blog / views.py → proj1 / blog / post_list.html. ..

Now when I open the page with python manage.py runserver, I get an error page because I don't have proj1 / blog / post_list.html yet. image.png If runserver fails and the page doesn't appear, something you've written so far is wrong, so check it.

Make a view template

After creating proj1 / blog / templates / blog / post_list.html and checking the page again with python manage.py runserver, the page is finally displayed without any errors. However, since nothing has been written yet, the page will be blank. step1.png If you write html properly, it will be displayed as it is.

proj1/blog/templates/blog/post_list.html


<html>
<body>
    <p>Hi there!</p>
    <p>It works!</p>
</body>
</html>

step3.png Let's make a blog-like page.

proj1/blog/templates/blog/post_list.html


<html>
    <head>
        <title>Django Girls blog</title>
    </head>
    <body>
        <div>
            <h1><a href="/">Django Girls Blog</a></h1>
        </div>

        <div>
            <p>published: 14.06.2014, 12:14</p>
            <h2><a href="">My first post</a></h2>
            <p>Aenean eu leo quam.Hello! Thank you!</p>
        </div>

        <div>
            <p>release date: 2014/06/14, 12:14</p>
            <h2><a href="">Second post</a></h2>
            <p>Hello! Thank you!</p>
        </div>
    </body>
</html>

image.png

Deploy

Let's deploy the contents so far to PythonAnywhere.

/home/User name/django/proj1/


git add --all
git commit -m "changed the html for the site"
git push

Open the PythonAnywhere command-line and pull it.

terminal:~/PythonAnywhere username.pythonanywhere.com


git pull

If you go to a web page from the PythonAnywhere Dashboard, reload it, and then open the site, you should see the same content.

6. How to use the query set

You can use queryset to read and write to the database just as django accesses it. This allows you to write a description in view.py that works as you expected when you actually move it.

Open the queryset in django shell.

terminal


python manage.py shell

Let's import the Post class and display all the post data with Post.objects.all ().

command-line


>>> from blog.models import Post
>>> Post.objects.all()
 <QuerySet [<Post:Taitoru 1>, <Post:Taitoru 2>, <Post:Taitoru 3>]>

Let's add a Post.

command-line


>>> from django.contrib.auth.models import User
>>> me = User.objects.get(username='User name')
>>> Post.objects.create(author=me, title='Sample title', text='Test')
>>> Post.objects.all()
<QuerySet [<Post:Taitoru 1>, <Post:Taitoru 2>, <Post:Taitoru 3>, <Post: Sample title>]>

The added Post is added at the end. Next, I will display only Posts whose title contains'title'.

command-line


>>> Post.objects.filter(title__contains='title')
<QuerySet [<Post: Sample title>]>

Let's display the published Post.

command-line


>>> from django.utils import timezone
>>> Post.objects.filter(published_date__lte=timezone.now())
<QuerySet []>

I will publish it.

command-line


>>> post = Post.objects.get(title="Sample title")
>>> post.publish()
>>> Post.objects.filter(title__contains='title')
<QuerySet [<Post: Sample title>]>

You can also view a list of super users registered with django.

command-line


>>> User.objects.all()
<QuerySet [<User:User name>]>

You can also display them in the order of posting or in the reverse order.

command-line


>>> Post.objects.order_by('created_date')
<QuerySet [<Post:Taitoru 1>, <Post:Taitoru 2>, <Post:Taitoru 3>, <Post: Sample title>]>

>>> Post.objects.order_by('-created_date')
<QuerySet [<Post: Sample title>, <Post:Taitoru 3>, <Post:Taitoru 2>, <Post:Taitoru 1>]>

You can also write a series of queries.

command-line


>>> Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
<QuerySet [<Post: Sample title>]>

You can exit the query set with exit ().

command-line


exit()

7. Create a dynamic view template

We will write a view template to display the contents of the Post stored in the database. I wrote to pass the published Post data to the template and display it as I did in the query set earlier.

proj1/blog/views.py


from django.shortcuts import render
from django.utils import timezone
from .models import Post

def post_list(request):
    posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
    return render(request, 'blog/post_list.html', {'posts': posts})

The blog / post_list.html created earlier was a static html, but I will rewrite it to display the value received from the database.

The python script is executed in the range enclosed in {%%}, and the value of the passed object is inserted in the range enclosed in {{}}, so the post is displayed in order. ..

proj1/blog/templates/blog/post_list.html


<html>
    <head>
        <title>Django Girls blog</title>
    </head>
    <body>
        <div>
            <h1><a href="/">Django Girls Blog</a></h1>
        </div>

        {% for post in posts %}
            <div>
                <p>published: {{ post.published_date }}</p>
                <h2><a href="">{{ post.title }}</a></h2>
                <p>{{ post.text|linebreaksbr }}</p>
            </div>
        {% endfor %}
    </body>
</html>

You should now be able to see the Post content you entered on the admin page, so check the display with python manage.py runserver. image.png It is completed safely.

8. Cute with CSS

I will make a cute design using Bootstrap.

First, put a link in the head of post_list.html so that you can use Bootstrap.

proj1/blog/templates/blog/post_list.Of html<head>Add to


<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">

image.png This alone sets the default CSS for Bootstrap, so the design changes a bit.

Create a CSS file

Since django recognizes the folder named static as a static file, create a css directory in the static directory and put blog.css in it.

proj1
└─── blog
     └─── static
          └─── css
               └─── blog.css

I will write CSS in this file normally. For the time being, let's change the color of the a tag in the heading.

proj1/blog/static/css/blog.css


h1 a, h2 a {
    color: #C25100;
}

Add {% load static%} and {% static'css / blog / css'%} to post_list.html to reflect blog.css.

proj1/blog/post_list.html


{% load static %}
<html>
    <head>
        <title>Django Girls blog</title>
        <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
        <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">
        <link rel="stylesheet" href="{% static 'css/blog.css' %}">
    </head>
    <body>
        <div>
            <h1><a href="/">Django Girls Blog</a></h1>
        </div>

        {% for post in posts %}
            <div>
                <p>published: {{ post.published_date }}</p>
                <h2><a href="">{{ post.title }}</a></h2>
                <p>{{ post.text|linebreaksbr }}</p>
            </div>
        {% endfor %}
    </body>
</html>

The CSS is reflected and the text color of the a tag of the heading is now orange. margin2.png

I will add various things

proj1/blog/static/css/blog.css


h1 a, h2 a {
    color: #C25100;
    font-family: 'Lobster';
}
body {
    padding-left: 15px;
}
.page-header {
    background-color: #C25100;
    margin-top: 0;
    padding: 20px 20px 20px 40px;
}

.page-header h1, .page-header h1 a, .page-header h1 a:visited, .page-header h1 a:active {
    color: #ffffff;
    font-size: 36pt;
    text-decoration: none;
}

.content {
    margin-left: 40px;
}

h1, h2, h3, h4 {
    font-family: 'Lobster', cursive;
}

.date {
    color: #828282;
}

.save {
    float: right;
}

.post-form textarea, .post-form input {
    width: 100%;
}

.top-menu, .top-menu:hover, .top-menu:visited {
    color: #ffffff;
    float: right;
    font-size: 26pt;
    margin-right: 20px;
}

.post {
    margin-bottom: 70px;
}

.post h2 a, .post h2 a:visited {
    color: #000000;
}

proj1/blog/templates/blog/post_list.html


{% load static %}
<html>
    <head>
        <title>Django Girls blog</title>
        <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
        <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">
        <link href="//fonts.googleapis.com/css?family=Lobster&subset=latin,latin-ext" rel="stylesheet" type="text/css">
        <link rel="stylesheet" href="{% static 'css/blog.css' %}">
    </head>
    <body>
        <div class="page-header">
            <h1><a href="/">Django Girls Blog</a></h1>
        </div>

        {% for post in posts %}
            <div class="post">
                <p>published: {{ post.published_date }}</p>
                <h2><a href="">{{ post.title }}</a></h2>
                <p>{{ post.text|linebreaksbr }}</p>
            </div>
        {% endfor %}
    </body>
</html>

final.png It became good

9. Template extension

The view template can reuse common parts.

As an example, let's divide the post_list.html created earlier into two views. Write the part that sets the basic design in base.html, and write the part that displays the Post list in post_list.html.

blog
└───templates
    └───blog
            base.html
            post_list.html

Insert the contents of post_list.html from {% block content%} to {% endblock%}.

proj1/blog/templates/blog/base.html


{% load static %}
<html>
    <head>
        <title>Django Girls blog</title>
        <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
        <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">
        <link href="//fonts.googleapis.com/css?family=Lobster&subset=latin,latin-ext" rel="stylesheet" type="text/css">
        <link rel="stylesheet" href="{% static 'css/blog.css' %}">
    </head>
    <body>
        <div class="page-header">
            <h1><a href="/">Django Girls Blog</a></h1>
        </div>
        <div class="content container">
            <div class="row">
                <div class="col-md-8">
                {% block content %}
                {% endblock %}
                </div>
            </div>
        </div>
    </body>
</html>

The first line on the post_list.html side tells you to extend base.html by writing {% extends'blog / base.html'%}.

proj1/blog/templates/blog/post_list.html


{% extends 'blog/base.html' %}

{% block content %}
    {% for post in posts %}
        <div class="post">
            <div class="date">
                {{ post.published_date }}
            </div>
            <h2><a href="">{{ post.title }}</a></h2>
            <p>{{ post.text|linebreaksbr }}</p>
        </div>
    {% endfor %}
{% endblock %}

When you restart the server and view the page, you should see the same thing as before.

10. Application extension

Add a page to display each blog post.

Create a link to the template

Specifies to refer to the view.post_detail () function when it comes to html: // localhost / post / **** /. <int: pk> means to convert the string to int type, assign it to pk, and give it as an argument like views.post_detail (request, pk).

proj1/blog/urls.py


from django.urls import path
from . import views

urlpatterns = [
    path('', views.post_list, name='post_list'),
    path('post/<int:pk>/', views.post_detail, name='post_detail'),
]

Add the post_detail function to proj1 / blog / views.py. I also use get_object_or_404 () to return 404 if there is no corresponding article in the Post object. The second argument of the render function specifies that'blog / post_detail.html' is used as the view template.

proj1/blog/views.py


from django.shortcuts import render, get_object_or_404

def post_detail(request, pk):
    post = get_object_or_404(Post, pk=pk)
    return render(request, 'blog/post_detail.html', {'post': post})

Add a view template to display the article. Since I use base.html, I can write it short.

proj1/blog/templates/blog/post_detail.html


{% extends 'blog/base.html' %}

{% block content %}
    <div class="post">
        {% if post.published_date %}
            <div class="date">
                {{ post.published_date }}
            </div>
        {% endif %}
        <h2>{{ post.title }}</h2>
        <p>{{ post.text|linebreaksbr }}</p>
    </div>
{% endblock %}

Finally, add a link to the

tag displaying the article title of post_list.html to complete.

proj1/blog/templates/blog/post_list.html


<h2><a href="{% url 'post_detail' pk=post.pk %}">{{ post.title }}</a></h2>

A page to display articles has been created. image.png

Deploy

Let's push the contents so far to git and deploy it.

terminal


git status
git add --all .
git status
git commit -m "Added view and template for detailed blog post as well as CSS for the site."
git push

terminal:~/User name.pythonanywhere.com


cd ~/Domain name.pythonanywhere.com
git pull

image.png It doesn't reflect CSS, because PythonAnywhere has a different location for static files. If you use the tool, it will be placed automatically.

terminal:~/PythonAnywhere username.pythonanywhere.com


workon username.pythonanywhere.com
python manage.py collectstatic

image.png

11-1. Make a post form

In the operation so far, the blog Post was entered from the management screen http: // localhost / admin /, but you can create a form to make it a little easier to enter.

Make a post form

blog
   └── forms.py

Inherit the forms.ModelForm class and add only a part to create a form. Here, it is a form for inputting title and text.

proj1/blog/forms.py


from django import forms
from .models import Post

class PostForm(forms.ModelForm):
    class Meta:
        model = Post
        fields = ('title', 'text',)

Put a link to the post form in base.html

Add the following line to put a link to the posting form at the top of base.html. If class = "glyphicon glyphicon-plus" is set, + will be displayed using the Bootstrap function.

proj1/blog/templates/blog/base.Added to html


<a href="{% url 'post_new' %}" class="top-menu"><span class="glyphicon glyphicon-plus"></span></a>

proj1/blog/templates/blog/base.After html modification


{% load static %}
<html>
    <head>
        <title>Django Girls blog</title>
        <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
        <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">
        <link href='//fonts.googleapis.com/css?family=Lobster&subset=latin,latin-ext' rel='stylesheet' type='text/css'>
        <link rel="stylesheet" href="{% static 'css/blog.css' %}">
    </head>
    <body>
        <div class="page-header">
            <a href="{% url 'post_new' %}" class="top-menu"><span class="glyphicon glyphicon-plus"></span></a>
            <h1><a href="/">Django Girls Blog</a></h1>
        </div>
        <div class="content container">
            <div class="row">
                <div class="col-md-8">
                    {% block content %}
                    {% endblock %}
                </div>
            </div>
        </div>
    </body>
</html>

Added to urls.py

When you come to http: // localhost: 8000 / post / new /, call the views.post_new function.

blog/urls.Add to py


path('post/new/', views.post_new, name='post_new'),

blog/urls.After py modification


from django.urls import path 
from . import views

urlpatterns = [
    path('', views.post_list, name='post_list'),
    path('post/<int:pk>/', views.post_detail, name='post_detail'),
    path('post/new/', views.post_new, name='post_new'),
]

Add the function called by urls.py to views.py

blog/views.Add to py


from django.shortcuts import redirect

def post_new(request):
    if request.method == "POST":
        form = PostForm(request.POST)
        if form.is_valid():
            post = form.save(commit=False)
            post.author = request.user
            post.published_date = timezone.now()
            post.save()
            return redirect('post_detail', pk=post.pk)
    else:
        form = PostForm()
    return render(request, 'blog/post_edit.html', {'form': form})

If you do python manage.py runserver and open http: // localhost: 8000 / post / new / in your browser, the new post page will be displayed as shown below. image.png

11-2. Create an edit form for posted posts

Let's add the article editing function in the same way as before.

Edit form

The form itself uses the same as the new post form.

Place an edit button

blog/templates/blog/post_detail.Add to html


<a class="btn btn-default" href="{% url 'post_edit' pk=post.pk %}"><span class="glyphicon glyphicon-pencil"></span></a>

blog/templates/blog/post_detail.After html modification


{% extends 'blog/base.html' %}

{% block content %}
    <div class="post">
        {% if post.published_date %}
            <div class="date">
                {{ post.published_date }}
            </div>
        {% endif %}
        <a class="btn btn-default" href="{% url 'post_edit' pk=post.pk %}"><span class="glyphicon glyphicon-pencil"></span></a>
        <h2>{{ post.title }}</h2>
        <p>{{ post.text|linebreaksbr }}</p>
    </div>
{% endblock %}

Add link to urls.py

python:proj1.blog/urls.Add to py


path('post/<int:pk>/edit/', views.post_edit, name='post_edit'),

Add a function to views.py

proj1/blog/views.Add to py


def post_edit(request, pk):
    post = get_object_or_404(Post, pk=pk)
    if request.method == "POST":
        form = PostForm(request.POST, instance=post)
        if form.is_valid():
            post = form.save(commit=False)
            post.author = request.user
            post.published_date = timezone.now()
            post.save()
            return redirect('post_detail', pk=post.pk)
    else:
        form = PostForm(instance=post)
    return render(request, 'blog/post_edit.html', {'form': form})

11-3. Editable only at login

New post button

proj1/blog/templates/blog/base.Before editing html


<a href="{% url 'post_new' %}" class="top-menu"><span class="glyphicon glyphicon-plus"></span></a>

proj1/blog/templates/blog/base.After editing html


{% if user.is_authenticated %}
    <a href="{% url 'post_new' %}" class="top-menu"><span class="glyphicon glyphicon-plus"></span></a>
{% endif %}

Article edit button

proj1/blog/templates/blog/post_detail.Before editing html


<a class="btn btn-default" href="{% url 'post_edit' pk=post.pk %}"><span class="glyphicon glyphicon-pencil"></span></a>

proj1/blog/templates/blog/post_detail.After editing html


{% if user.is_authenticated %}
     <a class="btn btn-default" href="{% url 'post_edit' pk=post.pk %}"><span class="glyphicon glyphicon-pencil"></span></a>
{% endif %}

The edit button no longer appears if you are not logged in.

Deploy

terminal


git status
git add --all .
git status
git commit -m "Added view and template for detailed blog post as well as CSS for the site."
git push

terminal:~/User name.pythonanywhere.com


cd ~/Domain name.pythonanywhere.com
git pull

image.png That's why it's completed. I did it

Recommended Posts

Django Girls Tutorial Note
Django note 4
Django Note 5
Django Note 1
Django note 3
Django note 2
Django Girls Tutorial Summary First Half
Python Django Tutorial (5)
Python Django Tutorial (2)
django tutorial memo
Python Django Tutorial (8)
Python Django Tutorial (6)
Start Django Tutorial 1
Django girls-3 workflow
Python Django Tutorial (7)
Python Django Tutorial (1)
Python Django tutorial tutorial
Python Django Tutorial (3)
Python Django Tutorial (4)
Python Django tutorial summary
django oscar simple tutorial
GO Official Tutorial Note 1
Get started with Django! ~ Tutorial ⑤ ~
Get started with Django! ~ Tutorial ④ ~
Get started with Django! ~ Tutorial ⑥ ~
(Note) Django in Vagrant environment
Python Django Tutorial Cheat Sheet
[Note] [For myself] Django command
Note
[Note] Django project creation and terminology
Django
Note
Note
Stumble when doing the django 1.7 tutorial
Deploy the Django tutorial to IIS ①
[Note] Run Django on Amazon Linux 2
Note: Send an email with Django
Django Crispy Tutorial (Environment Building on Mac)
(Note) Template file search order in Django
Django tutorial summary for beginners by beginners ③ (View)
Django Tutorial (Blog App Creation) ⑤ --Article Creation Function
Django Foreign Key Tutorial Ends in 10 Minutes
A note on enabling PostgreSQL with Django
Django Tutorial (Blog App Creation) ④ --Unit Test
DJango Note: From the beginning (form processing)
Django tutorial summary for beginners by beginners ⑤ (test)
A note about doing the Pyramid tutorial