django 入门基础示例

Demo 是最好的老师。原书里边的部分代码有错误(你就当是一些意料之外的彩蛋),所以最好自己敲一下,发现这些错误并修改过来。

学习的时候,可以自己在 GitHub 建个仓库保存一下学习记录:https://github.com/2392863668/learning_log 。

建立项目

创建虚拟环境

python3 -m venv ll_env

激活虚拟环境

可使用 deactivate 停止使用虚拟环境。

[root@master ~]$ source ll_env/bin/activate
(ll_env) [root@master ~]$ 
(ll_env) [looking@master ~]$ deactivate
[looking@master ~]$ 

安装指定版本的 django

(ll_env) [looking@master ~]$ pip3 install django==2.1.8
Collecting django==2.1.8
...

创建 learning_log 目录

(ll_env) [root@master ~]$ mkdir learning_log
(ll_env) [root@master ~]$ cd learning_log/
(ll_env) [root@master learning_log]$ 

在 django 中创建项目

(ll_env) [root@master learning_log]# django-admin startproject learning_log .
(ll_env) [root@master learning_log]# ls
learning_log  manage.py

创建数据库

如果出现以下错误:

TypeError: argument of type 'PosixPath' is not iterable

按照如下方法修改 learning_log 项目下的 settings.py 文件:

+ import os
  ...

- 'NAME': BASE_DIR / 'db.sqlite3',
+ 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
(ll_env) [root@master learning_log]# python3 manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying sessions.0001_initial... OK

(ll_env) [root@master learning_log]# ls
db.sqlite3  learning_log  manage.py

查看项目

(ll_env) [root@master learning_log]# python3 manage.py runserver 0.0.0.0:8000
Performing system checks...

System check identified no issues (0 silenced).
January 12, 2021 - 10:23:00
Django version 2.1.8, using settings 'learning_log.settings'
Starting development server at http://0.0.0.0:8000/
...
[12/Jan/2021 10:24:10] "GET / HTTP/1.1" 400 61735
Invalid HTTP_HOST header: '192.168.128.139:8000'. You may need to add '192.168.128.139' to ALLOWED_HOSTS.
Bad Request: /favicon.ico

如果 Windows 中用 ip:port 访问不到的话,还需要修改一下 setting.py 配置:

...

- ALLOWED_HOSTS = []
+ ALLOWED_HOSTS = ['*']

...

再次启动就可以正常查看到了 “worked successfully” 界面了。

(ll_env) [root@master learning_log]# python3 manage.py runserver 0.0.0.0:8000
Performing system checks...

System check identified no issues (0 silenced).
January 12, 2021 - 10:29:04
Django version 2.1.8, using settings 'learning_log.settings'
Starting development server at http://0.0.0.0:8000/
Quit the server with CONTROL-C.
[12/Jan/2021 10:29:08] "GET / HTTP/1.1" 200 16348
[12/Jan/2021 10:29:08] "GET /static/admin/css/fonts.css HTTP/1.1" 200 423
[12/Jan/2021 10:29:08] "GET /static/admin/fonts/Roboto-Bold-webfont.woff HTTP/1.1" 200 82564
Not Found: /favicon.ico
[12/Jan/2021 10:29:08] "GET /favicon.ico HTTP/1.1" 404 1984
[12/Jan/2021 10:29:08] "GET /static/admin/fonts/Roboto-Regular-webfont.woff HTTP/1.1" 200 80304
[12/Jan/2021 10:29:08] "GET /static/admin/fonts/Roboto-Light-webfont.woff HTTP/1.1" 200 81348
...

创建应用程序

(ll_env) [root@master learning_log]# python3 manage.py startapp learning_logs
(ll_env) [root@master learning_log]# ls
db.sqlite3  learning_log  learning_logs  manage.py
(ll_env) [root@master learning_log]# ls learning_logs
admin.py  apps.py  __init__.py  migrations  models.py  tests.py  views.py

定义模型

# models.py

from django.db import models

# Create your models here.

class Topic(models.Model):
    """用户学习的主题"""
    text = models.CharField(max_length=200)
    date_added = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        """返回模型的字符串表示"""
        return self.text

激活模型

在 settings.py 添加 app。

  INSTALLED_APPS = [
      'django.contrib.admin',
      'django.contrib.auth',
      'django.contrib.contenttypes',
      'django.contrib.sessions',
      'django.contrib.messages',
      'django.contrib.staticfiles',

      # my app
+     'learning_logs',
  ]
(ll_env) [root@master learning_log]# ls
db.sqlite3  learning_log  learning_logs  manage.py
(ll_env) [root@master learning_log]# python3 manage.py makemigrations learning_logs
Migrations for 'learning_logs':
  learning_logs/migrations/0001_initial.py
    - Create model Topic
(ll_env) [root@master learning_log]# python3 manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, learning_logs, sessions
Running migrations:
  Applying learning_logs.0001_initial... OK

创建超级用户

(ll_env) [root@master learning_log]# python3 manage.py createsuperuser
Username (leave blank to use 'root'): 
Email address: 
Password: 
Password (again): 
This password is too short. It must contain at least 8 characters.
This password is too common.
This password is entirely numeric.
Bypass password validation and create user anyway? [y/N]: y
Superuser created successfully.

向管理网站注册模型

# admin.py

from django.contrib import admin

# Register your models here.

from learning_logs.models import Topic
admin.site.register(Topic)
(ll_env) [root@master learning_log]# python3 manage.py runserver 0.0.0.0:8000
Performing system checks...

System check identified no issues (0 silenced).
January 12, 2021 - 11:18:19
Django version 2.1.8, using settings 'learning_log.settings'
Starting development server at http://0.0.0.0:8000/
Quit the server with CONTROL-C.
[12/Jan/2021 11:18:29] "GET / HTTP/1.1" 200 16348
[12/Jan/2021 11:18:29] "GET /static/admin/css/fonts.css HTTP/1.1" 304 0
...

定义模型 Entry

# models.py
...
class Entry(models.Model):
	"""学到的有关某个主题的具体知识"""
	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):
		"""返回模型的字符串表示"""
		if len(self.text) > 50:	
			return self.text[:50] + "..."
		else:
			return self.text

向管理网站注册模型 Topic

# admin.py

from django.contrib import admin

# Register your models here.

from learning_logs.models import Topic, Entry
admin.site.register(Topic)
admin.site.register(Entry)

迁移模型 Entry 

(ll_env) [root@master learning_log]# python3 manage.py makemigrations learning_logs
Migrations for 'learning_logs':
  learning_logs/migrations/0002_entry.py
    - Create model Entry

(ll_env) [root@master learning_log]# python3 manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, learning_logs, sessions
Running migrations:
  Applying learning_logs.0002_entry... OK

The opening is the first part of the game, roughly the first ten moves or so. In the opening, it's a good idea to do three things —bring out your bishops and knights, try to control the center of the board, and castle your king.

Of course, these are just guidelines, It will be important to learn when to follow these guidelines and when to disregard these suggestions.

------------------------------------------------------------
In the opening phase of the game, it's important to bring out your bishops and knights. These pieces are powerful and maneuverable enough to play a significant role in the beginning moves of a game.

------------------------------------------------------------
One of the most important concepts in climbing is to keep you weight on your feet as much as possible. There's a myth that climbers can hang all day on their arms. In reality, good climbers have practiced specific ways of keeping their weight over their feet whenever possible.

Django Shell

(ll_env) [root@master learning_log]# python3 manage.py shell
Python 3.6.8 (default, Aug  7 2019, 17:28:10) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-39)] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from learning_logs.models import Topic
>>> Topic.objects.all()
<QuerySet [<Topic: Chess>, <Topic: Climbing>]>
>>> topics = Topic.objects.all()
>>> for topic in topics:
...     print(topic.id, topic)
... 
1 Chess
2 Climbing

>>> t = Topic.objects.get(id=1)
>>> t.text
'Chess'
>>> t.date_added
datetime.datetime(2021, 1, 12, 14, 37, 24, 500078, tzinfo=<UTC>)
>>> t.entry_set.all()
<QuerySet [<Entry: The opening is the first part of the game, roughly...>, <Entry: In the opening phase of the game, it's important t...>]>
>>> 

创建网页

映射 URL

[root@master learning_log]# pwd
/root/learning_log/learning_log
[root@master learning_log]# vim urls.py
# urls.py

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

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include(('learning_logs.urls', 'learning_logs'), namespace='learning_logs')),
]
[root@master learning_logs]# pwd
/root/learning_log/learning_logs
[root@master learning_logs]# vim urls.py
# urls.py

"""定义 learning_logs 的 URL 模式"""
from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^$', views.index, name='index'),
]

 编写视图

[root@master learning_logs]# pwd
/root/learning_log/learning_logs
[root@master learning_logs]# vim views.py 
# views.py

from django.shortcuts import render

# Create your views here.

def index(request):
    """学习笔记的主页"""
    return render(request, 'learning_logs/index.html')

编写模板

[root@master learning_logs]# pwd
/root/learning_log/learning_logs/templates/learning_logs
[root@master learning_logs]# vim index.html
# index.html

<p>Learning Log</p>

<p>Learning Log helps you keep track of your learning, for any topic you're
learning about.</p>

创建其他网页

模板继承

[root@master learning_logs]# pwd
/root/learning_log/learning_logs/templates/learning_logs
[root@master learning_logs]# vim base.html
# base.html

<p>
    <a href="{% url 'learning_logs:index' %}">Learning Log</a>
</p>

{% block content %}
  <p>Learning Log helps you keep track of your learning, for any topic you're
  learning about.</p>
{% endblock content %}
[root@master learning_logs]# pwd
/root/learning_log/learning_logs/templates/learning_logs
[root@master learning_logs]# vim index.html
# index.html

{% extends "learning_logs/base.html" %}

{% block content %}
  <p>Learning Log helps you keep track of your learning, for any topic you're
  learning about.</p>
{% endblock content %}

 

显示所有主题页面

[root@master learning_logs]# pwd
/root/learning_log/learning_logs
[root@master learning_logs]# vim urls.py 
# urls.py

"""定义 learning_logs 的 URL 模式"""
from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^$', views.index, name='index'),
    url(r'^topics/$', views.topics, name='topics'),
]
[root@master learning_logs]# pwd
/root/learning_log/learning_logs
[root@master learning_logs]# vim views.py
# views.py

from django.shortcuts import render
from .models import Topic

# Create your views here.

def index(request):
	"""学习笔记的主页"""	
	return render(request, 'learning_logs/index.html')

def topics(request):
	"""显示所有主题"""
	topics = Topic.objects.order_by('date_added')
	context = {'topics': topics}
	return render(request, 'learning_logs/topics.html', context)
[root@master learning_logs]# pwd
/root/learning_log/learning_logs/templates/learning_logs
[root@master learning_logs]# vim topics.html
# topics.html

{% extends "learning_logs/base.html" %}

{% block content %}
  <p>Topics</p>
  
  <ul>
    {% for topic in topics %}
      <li>{
    
    { topic }}</li>
      {% empty %}
      <li>No topics have been added yet.</li>
    {% endfor %}
  </ul>
{% endblock content %}
[root@master learning_logs]# pwd
/root/learning_log/learning_logs/templates/learning_logs
[root@master learning_logs]# vim base.html 
# base.html

<p>
    <a href="{% url 'learning_logs:index' %}">Learning Log</a>
    <a href="{% url 'learning_logs:topics' %}">Topics</a>
</p>

{% block content %}
  <p>Learning Log helps you keep track of your learning, for any topic you're
  learning about.</p>
{% endblock content %}

显示特定主题页面

[root@master learning_logs]# pwd
/root/learning_log/learning_logs
[root@master learning_logs]# vim urls.py 
# urls.py

"""定义 learning_logs 的 URL 模式"""
from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^$', views.index, name='index'),
    url(r'^topics/$', views.topics, name='topics'),
    url(r'^topics/(?P<topic_id>\d+)/$', views.topic, name='topic'),
]
[root@master learning_logs]# pwd
/root/learning_log/learning_logs
[root@master learning_logs]# vim views.py
# views.py

from django.shortcuts import render
from .models import Topic

# Create your views here.

...

def topic(request, topic_id):
	"""显示单个主题及其所有的条目"""
	topic = Topic.objects.get(id=topic_id)
	entries = topic.entry_set.order_by('-date_added')
	context = {'topic': topic, 'entries': entries}
	return render(request, 'learning_logs/topic.html', context)
这是第一个除  request 对象外还包含另一个形参的视图函数。这个函数接受正则表达式 (?P<topic_id>\d+) 捕获的值,并将其存储到 topic_id 我 们使用 get() 来获取指定的主题,就像前面在  Django shell  中所做的那样。 我们获取与该主题相关联的条目,并将它们按  date_added 排序: date_added 前面的减号 指定按降序排列,即先显示最近的条目。我们将主题和条目都存储在字典 context ,再将这个字典发送给模板  topic.html
 
[root@master learning_logs]# pwd
/root/learning_log/learning_logs/templates/learning_logs
[root@master learning_logs]# vim topic.html
# topic.html

{% extends "learning_logs/base.html" %}

{% block content %}
  <p>Topics: {
    
    { topic }}</p>
  
  <p>Entries:</p>
  <ul>
    {% for entry in entries %}
      <li>
        <p>{
    
    { entry.date_added|date:'M d, Y H:i' }}</p>
        <p>{
    
    { entry.text|linebreaks }}</p>
      </li>
      {% empty %}
      <li>There are no entries for this topic yet.</li>
    {% endfor %}
  </ul>
{% endblock content %}
[root@master learning_logs]# pwd
/root/learning_log/learning_logs/templates/learning_logs
[root@master learning_logs]# vim topics.html
# topics.html

{% extends "learning_logs/base.html" %}

{% block content %}
  <p>Topics</p>
  
  <ul>
    {% for topic in topics %}
      <li>
        <a href="{% url 'learning_logs:topic' topic.id %}">{
    
    {topic}}</a>
      </li>
      {% empty %}
      <li>No topics have been added yet.</li>
    {% endfor %}
  </ul>
{% endblock content %}
[root@master learning_logs]# pwd
/root/learning_log/learning_logs/templates/learning_logs
[root@master learning_logs]# vim base.html 
# base.html

<p>
    <a href="{% url 'learning_logs:index' %}">Learning Log</a>
    <a href="{% url 'learning_logs:topics' %}">Topics</a>
</p>

{% block content %}
  <p>Learning Log helps you keep track of your learning, for any topic you're
  learning about.</p>
{% endblock content %}

 

让用户能输入数据

添加新主题

(ll_env) [root@master learning_logs]# pwd
/root/learning_log/learning_logs
(ll_env) [root@master learning_logs]# vim forms.py
# forms.py

from django import forms
from .models import Topic

class TopicForm(forms.ModelForm):
    class Meta:
        model = Topic
        fields = ['text']
        labels = {'text': ''}
[root@master learning_logs]# pwd
/root/learning_log/learning_logs
[root@master learning_logs]# vim urls.py 
# urls.py

"""定义 learning_logs 的 URL 模式"""
from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^$', views.index, name='index'),
    url(r'^topics/$', views.topics, name='topics'),
    url(r'^topics/(?P<topic_id>\d+)/$', views.topic, name='topic'),
    url(r'^new_topic/$', views.new_topic, name='new_topic'),
]
(ll_env) [root@master learning_logs]# pwd
/root/learning_log/learning_logs
(ll_env) [root@master learning_logs]# vim views.py 
# views.py

from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.urls import reverse

from .models import Topic
from .forms import TopicForm

# Create your views here.

...

def new_topic(request):
    """添加新主题"""
    if request.method != 'POST':
        # 未提交数据:创建一个新表单
        form = TopicForm()
    else:
        # POST 提交数据,对数据进行处理
        form = TopicForm(request.POST)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse('learning_logs:topics'))
    context = {'form': form}
    return render(request, 'learning_logs/new_topic.html', context)
[root@master learning_logs]# pwd
/root/learning_log/learning_logs/templates/learning_logs
[root@master learning_logs]# vim new_topic.html
# new_topic.html

{% 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 %}
[root@master learning_logs]# pwd
/root/learning_log/learning_logs/templates/learning_logs
[root@master learning_logs]# vim topics.html
# topics.html

{% extends "learning_logs/base.html" %}

{% block content %}
  <p>Topics</p>

  <ul>
    {% for topic in topics %}
      <li>
        <a href="{% url 'learning_logs:topic' topic.id %}">{
   
   {topic}}</a>
      </li>
      {% empty %}
      <li>No topics have been added yet.</li>
    {% endfor %}
  </ul>

  <a href="{% url 'learning_logs:new_topic' %}">Add a new topic:</a>
{% endblock content %}

 

添加新条目

(ll_env) [root@master learning_logs]# pwd
/root/learning_log/learning_logs
(ll_env) [root@master learning_logs]# vim forms.py
# forms.py

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})}
[root@master learning_logs]# pwd
/root/learning_log/learning_logs
[root@master learning_logs]# vim urls.py 
# urls.py

"""定义 learning_logs 的 URL 模式"""
from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^$', views.index, name='index'),
    url(r'^topics/$', views.topics, name='topics'),
    url(r'^topics/(?P<topic_id>\d+)/$', views.topic, name='topic'),
    url(r'^new_topic/$', views.new_topic, name='new_topic'),
    url(r'^new_entry/(?P<topic_id>\d+)/$', views.new_entry, name='new_entry'),
]
(ll_env) [root@master learning_logs]# pwd
/root/learning_log/learning_logs
(ll_env) [root@master learning_logs]# vim views.py 
# views.py

from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.urls import reverse

from .models import Topic
from .forms import TopicForm, EntryForm

# Create your views here.

...

def new_entry(request, topic_id):
    """在特定主题中添加新条目"""
    topic = Topic.objects.get(id=topic_id)

    if request.method != 'POST':
        # 未提交数据,创建一个空表单
        form = EntryForm()
    else:
        # POST 提交数据,对数据进行处理
        form = EntryForm(data=request.POST)
        if form.is_valid():
            new_entry = form.save(commit=False)
            new_entry.topic = topic
            new_entry.save()
            return HttpResponseRedirect(reverse('learning_logs:topic', args=[topic_id]))

    context = {'topic': topic, 'form': form}
    return render(request, 'learning_logs/new_entry.html', context)
[root@master learning_logs]# pwd
/root/learning_log/learning_logs/templates/learning_logs
[root@master learning_logs]# vim new_entry.html
# new_entry.html

{% 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 %}
[root@master learning_logs]# pwd
/root/learning_log/learning_logs/templates/learning_logs
[root@master learning_logs]# vim topic.html
# topic.html

{% extends "learning_logs/base.html" %}

{% block content %}
  <p>Topic: {
   
   { topic }}</p>

  <p>Entries:</p>
  <p><a href="{% url 'learning_logs:new_entry' topic.id %}">add new entry</a></p>
  <ul>
    {% for entry in entries %}
      <li>
        <p>{
   
   { entry.date_added|date:'M d, Y H:i' }}</p>
        <p>{
   
   { entry.text|linebreaks }}</p>
      </li>
      {% empty %}
      <li>There are no entries for this topic yet.</li>
    {% endfor %}
  </ul>
{% endblock content %}
The bishops and knights are good pieces to have out in the opening phase of the game. They're both powerful enough to be useful in attacking your opponent, but not so powerful that you can't afford to lose them in an early trade.

 

  

编辑条目

[root@master learning_logs]# pwd
/root/learning_log/learning_logs
[root@master learning_logs]# vim urls.py 
# urls.py

"""定义 learning_logs 的 URL 模式"""
from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^$', views.index, name='index'),
    url(r'^topics/$', views.topics, name='topics'),
    url(r'^topics/(?P<topic_id>\d+)/$', views.topic, name='topic'),
    url(r'^new_topic/$', views.new_topic, name='new_topic'),
    url(r'^new_entry/(?P<topic_id>\d+)/$', views.new_entry, name='new_entry'),
    url(r'^edit_entry/(?P<entry_id>\d+)/$', views.edit_entry, name='edit_entry'),
]
(ll_env) [root@master learning_logs]# pwd
/root/learning_log/learning_logs
(ll_env) [root@master learning_logs]# vim views.py 
# views.py

from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.urls import reverse

from .models import Topic, Entry
from .forms import TopicForm, EntryForm

# Create your views here.

...

def edit_entry(request, entry_id):
    """编辑既有条目"""
    entry = Entry.objects.get(id=entry_id)
    topic = entry.topic

    if request.method != 'POST':
        # 初次请求,使用当前条目填充表单
        form = EntryForm(instance=entry)
    else:
        # POST 提交的数据,对数据进行处理
        form = EntryForm(instance=entry, data=request.POST)
        if form.is_valid():
            form.save()
            return HttpResponseRedirect(reverse('learning_logs:topic', args=[topic.id]))

    context = {'entry': entry, 'topic': topic, 'form': form}
    return render(request, 'learning_logs/edit_entry.html', context)
(ll_env) [root@master learning_logs]# pwd
/root/learning_log/learning_logs/templates/learning_logs
(ll_env) [root@master learning_logs]# vim edit_entry.html
# edit_entry.html

{% 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 %}
[root@master learning_logs]# pwd
/root/learning_log/learning_logs/templates/learning_logs
[root@master learning_logs]# vim topic.html
# topic.html

{% extends "learning_logs/base.html" %}

{% block content %}
  <p>Topic: {
   
   { topic }}</p>

  <p>Entries:</p>
  <p><a href="{% url 'learning_logs:new_entry' topic.id %}">add new entry</a></p>
  <ul>
    {% for entry in entries %}
      <li>
        <p>{
   
   { entry.date_added|date:'M d, Y H:i' }}</p>
        <p>{
   
   { entry.text|linebreaks }}</p>
        <p>
         <a href="{% url 'learning_logs:edit_entry' entry.id %}">edit entry</a>
        </p>
      </li>
      {% empty %}
      <li>There are no entries for this topic yet.</li>
    {% endfor %}
  </ul>
{% endblock content %}

 

 

创建用户账户

创建应用程序 users

(ll_env) [root@master learning_log]# pwd
/root/learning_log
(ll_env) [root@master learning_log]# ls
db.sqlite3  learning_log  learning_logs  manage.py
(ll_env) [root@master learning_log]# python3 manage.py startapp users
(ll_env) [root@master learning_log]# ls
db.sqlite3  learning_log  learning_logs  manage.py  users
(ll_env) [root@master learning_log]# ls users/
admin.py  apps.py  __init__.py  migrations  models.py  tests.py  views.py
(ll_env) [root@master learning_log]# pwd
/root/learning_log/learning_log
(ll_env) [root@master learning_log]# vim settings.py 
  INSTALLED_APPS = [
      'django.contrib.admin',
      'django.contrib.auth',
      'django.contrib.contenttypes',
      'django.contrib.sessions',
      'django.contrib.messages',
      'django.contrib.staticfiles',
 
      # my app
      'learning_logs',
+     'users',
  ]
(ll_env) [root@master learning_log]# pwd
/root/learning_log/learning_log
(ll_env) [root@master learning_log]# vim urls.py
# urls.py

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

urlpatterns = [
    path('admin/', admin.site.urls),
    path('users/', include(('users.urls', 'users'), namespace='users')),
    path('', include(('learning_logs.urls', 'learning_logs'), namespace='learning_logs')),
]
(ll_env) [root@master users]# pwd
/root/learning_log/users
(ll_env) [root@master users]# ls
admin.py  apps.py  __init__.py  migrations  models.py  tests.py  views.py
(ll_env) [root@master users]# vim urls.py
# urls.py

"""为应用程序 users 定义 URL 模式"""

from django.conf.urls import url
from django.contrib.auth.views import LoginView

from . import views

urlpatterns = [
    # 登录页面
    url(r'^login/$', LoginView.as_view(template_name='users/login.html'), name='login'),
]
(ll_env) [root@master users]# pwd
/root/learning_log/users
(ll_env) [root@master users]# mkdir -p templates/users
(ll_env) [root@master users]# cd templates/users/
(ll_env) [root@master users]# pwd
/root/learning_log/users/templates/users
(ll_env) [root@master users]# vim login.html
# login.html

{% extends "learning_logs/base.html" %}

{% block content %}

  {% if form.errors %}
    <p>Your username and password didn't match. Please try again.</p>
  {% endif %}

  <form method="post" action="{% url 'users:login' %}">
    {% csrf_token %}
    {
   
   { form.as_p }}
    <button name="submit">log in</button>
    <input type="hidden" name="next" value="{% url 'learning_logs:index' %}" />
  </form>
{% endblock content %}
(ll_env) [root@master learning_logs]# pwd
/root/learning_log/learning_logs/templates/learning_logs
(ll_env) [root@master learning_logs]# vim base.html
# base.html

<p>
    <a href="{% url 'learning_logs:index' %}">Learning Log</a>
    <a href="{% url 'learning_logs:topics' %}">Topics</a>
    {% if user.is_authenticated %}
      Hello, {
   
   { user.username }}.
    {% else %}
      <a href="{% url 'users:login' %}">log in</a>
    {% endif %}
</p>

{% block content %}
  <p>Learning Log helps you keep track of your learning, for any topic you're
  learning about.</p>
{% endblock content %}

注销

(ll_env) [root@master users]# pwd
/root/learning_log/users
(ll_env) [root@master users]# ls
admin.py  apps.py  __init__.py  migrations  models.py  tests.py  views.py
(ll_env) [root@master users]# vim urls.py
# urls.py

"""为应用程序 users 定义 URL 模式"""

from django.conf.urls import url
from django.contrib.auth.views import LoginView

from . import views

urlpatterns = [
    # 登录页面
    url(r'^login/$', LoginView.as_view(template_name='users/login.html'), name='login'),
    # 注销
    url(r'^logout/$', views.logout_view, name='logout'),
]
(ll_env) [root@master users]# pwd
/root/learning_log/users
(ll_env) [root@master users]# vim views.py 
# view.py

from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.contrib.auth import logout

# Create your views here.

def logout_view(request):
	"""注销用户"""
	logout(request)
	return HttpResponseRedirect(reverse('learning_logs:index'))
(ll_env) [root@master learning_logs]# pwd
/root/learning_log/learning_logs/templates/learning_logs
(ll_env) [root@master learning_logs]# vim base.html
# base.html

<p>
    <a href="{% url 'learning_logs:index' %}">Learning Log</a>
    <a href="{% url 'learning_logs:topics' %}">Topics</a>
    {% if user.is_authenticated %}
      Hello, {
   
   { user.username }}.
      <a href="{% url 'users:logout' %}">log out</a>
    {% else %}
      <a href="{% url 'users:login' %}">log in</a>
    {% endif %}
</p>

{% block content %}
  <p>Learning Log helps you keep track of your learning, for any topic you're
  learning about.</p>
{% endblock content %}

注册

(ll_env) [root@master users]# pwd
/root/learning_log/users
(ll_env) [root@master users]# vim urls.py 
# urls.py

"""为应用程序 users 定义 URL 模式"""

from django.conf.urls import url
from django.contrib.auth.views import LoginView

from . import views

urlpatterns = [
    # 登录页面
    url(r'^login/$', LoginView.as_view(template_name='users/login.html'), name='login'),
    # 注销
    url(r'^logout/$', views.logout_view, name='logout'),
    # 注册页面
    url(r'^register/$', views.register, name='register'),
]
(ll_env) [root@master users]# pwd
/root/learning_log/users
(ll_env) [root@master users]# vim views.py 
# view.py

from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.contrib.auth import login, logout, authenticate
from django.contrib.auth.forms import UserCreationForm

# Create your views here.

...
def register(request):
    """注册新用户"""
    if request.method != 'POST':
        # 显示空的注册表单
        form = UserCreationForm()
    else:
        # 处理填写好的表单
        form = UserCreationForm(data=request.POST)

        if form.is_valid():
            new_user = form.save()
            # 让用户自动登录,再重定向到主页
            authenticated_user = authenticate(username=new_user.username,
                password=request.POST['password1'])
            login(request, authenticated_user)
            return HttpResponseRedirect(reverse('learning_logs:index'))

    context = {'form': form}
    return render(request, 'users/register.html', context)
(ll_env) [root@master users]# pwd
/root/learning_log/users/templates/users
(ll_env) [root@master users]# vim register.html 
# register.html

{% extends "learning_logs/base.html" %}

{% block content %}

  <form method="post" action="{% url 'users:register' %}">
    {% csrf_token %}
    {
   
   { form.as_p }}

    <button name="submit">register</button>
    <input type="hidden" name="next" value="{% url 'learning_logs:index' %}" />
  </form>
{% endblock content %}
(ll_env) [root@master learning_logs]# pwd
/root/learning_log/learning_logs/templates/learning_logs
(ll_env) [root@master learning_logs]# vim base.html 
# base.html

<p>
    <a href="{% url 'learning_logs:index' %}">Learning Log</a>
    <a href="{% url 'learning_logs:topics' %}">Topics</a>
    {% if user.is_authenticated %}
      Hello, {
   
   { user.username }}.
      <a href="{% url 'users:logout' %}">log out</a>
    {% else %}
      <a href="{% url 'users:register' %}">register</a>
      <a href="{% url 'users:login' %}">log in</a>
    {% endif %}
</p>

{% block content %}
  <p>Learning Log helps you keep track of your learning, for any topic you're
  learning about.</p>
{% endblock content %}

(ll_env) [root@master learning_log]# python3 manage.py shell
Python 3.6.8 (default, Aug  7 2019, 17:28:10) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-39)] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from django.contrib.auth.models import User  
>>> User.objects.all()
<QuerySet [<User: root>, <User: looking>]>
>>> user= User.objects.get(username='looking')
>>> user
<User: looking>
>>> user.delete()
(1, {'admin.LogEntry': 0, 'auth.User_groups': 0, 'auth.User_user_permissions': 0, 'auth.User': 1})
>>> User.objects.all()
<QuerySet [<User: root>]>

让用户拥有自己的数据

限制 topics 页面的访问

(ll_env) [root@master learning_logs]# pwd
/root/learning_log/learning_logs
(ll_env) [root@master learning_logs]# vim views.py 
# view.py

from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.contrib.auth.decorators import login_required

from .models import Topic, Entry
from .forms import TopicForm, EntryForm

# Create your views here.

def index(request):
    """学习笔记的主页"""
    return render(request, 'learning_logs/index.html')

@login_required
def topics(request):
    """显示所有主题"""
    topics = Topic.objects.order_by('date_added')
    context = {'topics': topics}
    return render(request, 'learning_logs/topics.html', context)
...
(ll_env) [root@master learning_log]# pwd
/root/learning_log/learning_log
(ll_env) [root@master learning_log]# vim settings.py 
# settings.py

...

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.1/howto/static-files/

STATIC_URL = '/static/'
LOGIN_URL = '/users/login/'

如果只对 topics 函数添加限制的话,我们还是可以让过 topics 访问到 topics 下的子页面,因此需要添加更加严格的限制。

(ll_env) [root@master learning_logs]# pwd
/root/learning_log/learning_logs
(ll_env) [root@master learning_logs]# vim views.py 
# view.py

from django.shortcuts import render
from django.http import HttpResponseRedirect
from django.urls import reverse
from django.contrib.auth.decorators import login_required

from .models import Topic, Entry
from .forms import TopicForm, EntryForm

# Create your views here.

def index(request):
    """学习笔记的主页"""
    return render(request, 'learning_logs/index.html')

...

@login_required
def topic(request, topic_id):
...

@login_required
def new_topic(request):
...

@login_required
def new_entry(request, topic_id):
...

@login_required
def edit_entry(request, entry_id):
...

@login_required
def edit_entry(request, entry_id):
...

将数据关联到用户

(ll_env) [root@master learning_logs]# pwd
/root/learning_log/learning_logs
(ll_env) [root@master learning_logs]# vim models.py 
# models.py

from django.db import models
from django.contrib.auth.models import User

# Create your models here.

class Topic(models.Model):
    """用户学习的主题"""
    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 self.text
...
(ll_env) [root@master learning_log]# python3 manage.py shell
Python 3.6.8 (default, Aug  7 2019, 17:28:10) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-39)] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from django.contrib.auth.models import User
>>> User.objects.all()
<QuerySet [<User: root>, <User: looking>]>
>>> from django.contrib.auth.models import User
>>> User.objects.all()
<QuerySet [<User: root>, <User: looking>]>
>>> for user in User.objects.all():
...     print(user.username, user.id)
... 
root 1
looking 3
(ll_env) [root@master learning_log]# python3 manage.py makemigrations learning_logs
You are trying to add a non-nullable field 'owner' to topic without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
 1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
 2) Quit, and let me add a default in models.py
Select an option: 1
Please enter the default value now, as valid Python
The datetime and django.utils.timezone modules are available, so you can do e.g. timezone.now
Type 'exit' to exit this prompt
>>> 1
Migrations for 'learning_logs':
  learning_logs/migrations/0003_topic_owner.py
    - Add field owner to topic


(ll_env) [root@master learning_log]# python3 manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, learning_logs, sessions
Running migrations:
  Applying learning_logs.0003_topic_owner... OK
(ll_env) [root@master learning_log]# python3 manage.py shell
Python 3.6.8 (default, Aug  7 2019, 17:28:10) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-39)] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from learning_logs.models import Topic
>>> for topic in Topic.objects.all():
...     print(topic, topic.owner)
... 
Chess root
Climbing root
Reading root

只允许用户访问自己的主题

(ll_env) [root@master learning_logs]# pwd
/root/learning_log/learning_logs
(ll_env) [root@master learning_logs]# vim views.py 
# views.py

from django.shortcuts import render
from django.http import HttpResponseRedirect, Http404
from django.urls import reverse
from django.contrib.auth.decorators import login_required

...

@login_required
def topics(request):
    """显示所有主题"""
    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):
    """显示单个主题及其所有的条目"""
    topic = Topic.objects.get(id=topic_id)
    # 确认请求的主题属于当前用户
    if topic.owner != request.user:
        raise Http404
    
    entries = topic.entry_set.order_by('-date_added')
...

@login_required
def new_topic(request):
    """添加新主题"""
    if request.method != 'POST':
        # 未提交数据:创建一个新表单
        form = TopicForm()
    else:
        # POST 提交数据,对数据进行处理
        form = TopicForm(request.POST)
        if form.is_valid():
            new_topic = form.save(commit=False)
            new_topic.owner = request.user
            new_topic.save()
            return HttpResponseRedirect(reverse('learning_logs:topics'))
    context = {'form': form}
    return render(request, 'learning_logs/new_topic.html', context)
...

@login_required
def edit_entry(request, entry_id):
    """编辑既有条目"""
    entry = Entry.objects.get(id=entry_id)
    topic = entry.topic
    if topic.owner != request.user:
        raise Http404
...

现在,各自的用户只能修改查看各自的主题,再也不会串台了。

设置样式

django-bootstrap3

(ll_env) [root@master ~]# pip3 install django-bootstrap3
Collecting django-bootstrap3
...
(ll_env) [root@master learning_log]# pwd
/root/learning_log/learning_log
(ll_env) [root@master learning_log]# vim settings.py 
# settings.py

...
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    # third-party app
    'bootstrap3',
    # my app
    'learning_logs',
    'users',
]
...
# django-bootstrap3
BOOTSTRAP3 = {
    'include_jquery': True
}

定义 HTML 头部

(ll_env) [root@master learning_logs]# pwd
/root/learning_log/learning_logs/templates/learning_logs
(ll_env) [root@master learning_logs]# vim base.html 
# base.html

{% load bootstrap3 %}

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        
        <title>Learning Log</title>
        {% bootstrap_css %}
        {% bootstrap_javascript %}
    </head>
</html>

定义导航栏

(ll_env) [root@master learning_logs]# pwd
/root/learning_log/learning_logs/templates/learning_logs
(ll_env) [root@master learning_logs]# vim base.html 
# base.html

{% load bootstrap3 %}

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>Learning Log</title>
        {% bootstrap_css %}
        {% bootstrap_javascript %}
    </head>

    <body>
        <!-- Static navbar -->
        <nav class="navbar navbar-default navbar-static-top">
            <div class="container">

                <div class="navbar-header">
                    <button type="button" class="navbar-toggle collapsed"
                            data-toggle="collapse" data-target="#navbar"
                            aria-expanded="false" aria-controls="navbar">
                    </button>
                    <a class="navbar-brand" href="{% url 'learning_logs:index' %}">Learning Log</a>
                </div>

                <div id="navbar" class="navbar-collapse collapse">
                    <ul class="nav navbar-nav">
                        <li><a href="{% url 'learning_logs:topics' %}">Topics</a> </li>
                    </ul>
                    <ul class="nav navbar-nav navbar-right">
                        {% if user.is_authenticated %}
                            <li><a>Hello, {
   
   {user.username}}.</a> </li>
                            <li><a href="{% url 'users:logout' %}">log out</a> </li>
                        {% else %}
                            <li><a href="{% url 'users:register' %}">register</a> </li>
                            <li><a href="{% url 'users:login' %}">log in</a> </li>
                        {% endif %}
                    </ul>
                </div>
            </div>
        </nav>
    </body>
</html>

定义页面主要内容

# base.html

...

            <div class="container">

                <div class="page-header">
                    {% block header %}{% endblock header %}
                </div>
                <div>
                    {% block content %}{% endblock content %}
                </div>
...

猜你喜欢

转载自blog.csdn.net/TomorrowAndTuture/article/details/112538096