介绍
在本文中,您将构建一个 Django应用程序,显示各种城市的当前天气情况。
目前的天气数据将由 Open Weather Map API提供。
您将使用数据库工作并创建表格,您在本教程中学习的内容可以后来应用于更复杂的项目。
前提条件
*本项目将需要安装Python,您应该能够参阅此教程系列(https://www.digitalocean.com/community/tutorial_series/how-to-install-and-set-up-a-local-programming-environment-for-python-3)以获取更多信息。
本文中的代码是用Python 3和Django 3.0编写的,所以要遵循本教程,你应该熟悉两者。
步骤1 - 设置项目
安装Django就像安装任何其他Python库:
- 您可以启动虚拟环境并运行
pip
来安装Django。 * 或者您可以创建项目目录,运行pipenv
,然后激活pipenv
壳。
两种方法都起作用,但对于本文,你将使用 pipenv
)。
注意:对于替代的Django安装方法,您应该能够参阅本教程系列(https://www.digitalocean.com/community/tutorial_series/django-development)以获取更多信息。
官方文档为使用 Homebrew或 Linuxbrew安装「pipenv」提供了说明。
在您的终端中,创建一个环境目录:
1mkdir the_weather_env
接下来,导航到环境目录:
1cd the_weather_env
然后,使用 pipenv 来安装 Django:
1pipenv install django
这将为您安装最新版本的Django. 在写这篇文章时,Django是在版本 3.0.5.
利用此时刻,您还可以使用 pipenv 来安装您以后会使用的 请求库:
1pipenv install requests
通过在您的终端中运行以下命令来激活项目的 virtualenv:
1pipenv shell
这将引发一个新的壳子次进程。
第2步:启动 Django 项目
一旦你安装了Django,创建并导航到该项目的目录,如果你还没有。
你可以运行Django给你的startproject
命令来生成这个项目。
1django-admin startproject the_weather
Django应该在您的目录中创建了一些新文件。
让我们尝试启动您的开发服务器. 要做到这一点,请在您的终端中导航到新的目录:
1cd the_weather
接下来,使用manage.py
在您的终端中运行runserver
命令:
1python manage.py runserver
如果你检查你的终端,你应该看到你的应用程序的URL. 默认情况下,它应该是127.0.0.1:8000
:
现在,打开您的Web浏览器并访问该URL:
如果你收到一个恭喜
页面,你知道你已经正确设置了Django。
步骤 3 – 登录到 Admin 仪表板
接下来,您将登录到 Django 提供的管理仪表板. 要做到这一点,首先,您必须 migrate 您的数据库,这意味着 Django 将创建默认应用程序所需的预定义表。
首先,您需要停止服务器,这取决于您的环境,可以通过键盘命令CONTROL+C
或CTRL+C
完成。
接下来,在您的终端中运行迁移
命令:
1python manage.py migrate
通过运行该命令,Django 为您创建了一个 SQLite 数据库,在设置中为您创建了默认数据库,并将多个表添加到该数据库中。
Django为您提供的表之一是用户表,它将用于存储您的应用程序中的任何用户.您正在构建的应用程序不需要任何用户,但有一个管理员用户将允许您访问管理员仪表板。
要创建一个管理员用户,您将在您的终端中运行createsuperuser
命令:
1python manage.py createsuperuser
按照指示,为您的管理员用户提供用户名、电子邮件地址和密码. 完成后,您需要在您的终端中重新启动服务器:
1python manage.py runserver
在您的 Web 浏览器中,请访问 admin 仪表板,点击127.0.0.1:8000/admin
。
您可以访问此页面的原因是因为您的urls.py
中设置了admin
。
如果您使用您刚刚创建的用户名和密码登录,您将收到 Django Admin 仪表板:
Groups 和 Users 代表两个模型 Django 给你访问. Models 只是数据库中表的代码表示。
如果你点击用户
,你应该看到有关用户表的更多细节,你应该看到你创建的用户。花一会儿去探索,点击仪表板中的不同的链接,看看什么是可用的。
现在让我们离开管理器仪表板,并在代码上工作,您将需要为您的天气应用程序创建项目内部的应用程序。
步骤 4 – 创建应用程序
在Django中,您可以通过使用 apps 来分离项目中的功能,在Django的情况下,应用程序指的是项目中的特定功能。
例如,如果您查看settings.py
文件,您将看到INSTALLED_APPS
列表。
第一個安裝的應用程式 - django.contrib.admin
- 是你剛剛使用的應用程式. 它處理所有管理員功能,而不是其他任何東西。 您的項目中的另一個應用程式是 django.contrib.auth
,讓您登入您的管理員仪表板。
在您的情况下,您需要创建一个新的应用程序来处理与显示天气有关的一切。
首先,你需要关闭服务器。
接下来,在您的终端中运行startapp
命令:
1python manage.py startapp weather
通过运行startapp
,Django 已为您的项目添加了一个新的目录和更多文件。
随着最新文件的生成,让我们在您的天气
应用程序目录中创建一个名为urls.py
的新文件:
1[label the_weather/weather/urls.py]
2from django.urls import path
3
4urlpatterns = [
5]
这个文件类似于您的the_weather
目录中的urls.py
。 不同之处在于,这个urls.py
文件包含所有与应用程序本身相关的URL。
您尚未指定 URL,但您可以设置项目来识别您的应用程序,并将任何特定于您的应用程序的 URL 路由到应用程序 urls.py
文件。
首先,进入Settings.py
中的INSTALLED_APPS
列表,并将天气
添加到列表中:
1[label the_weather/the_weather/settings.py]
2...
3
4INSTALLED_APPS = [
5 'django.contrib.admin',
6 'django.contrib.auth',
7 'django.contrib.contenttypes',
8 'django.contrib.sessions',
9 'django.contrib.messages',
10 'django.contrib.staticfiles',
11 'weather',
12]
13
14...
这让Django知道你想在你的项目中使用天气
应用程序。
接下来,您需要修改原始 urls.py
以指向您的应用程序 urls.py
文件. 要做到这一点,您需要在管理员仪表板的现有路径下添加一条行。
1[label the_weather/the_weather/urls.py]
2from django.contrib import admin
3from django.urls import path, include
4
5urlpatterns = [
6 path('admin/', admin.site.urls),
7 path('', include('weather.urls')),
8]
空串意味着您不需要为应用程序的输入点使用终端点,相反,您将允许应用程序处理任何特定的终端点,您可能已经放置了类似的‘path('weather/',...)’,这意味着您将不得不键入‘127.0.0.1:8000/weather/`以获得与您的天气应用程序相关的任何内容。
步骤 5 – 添加模板和视图
现在,您需要将模板添加到您的项目中。
Django 中的 template 是一个 HTML 文件,允许额外的语法,使模板动态。您将能够处理功能,如添加变量、如果
陈述和循环。
在您的终端中,导航到天气
应用程序目录:
1cd weather
接下来,创建templates
目录:
1mkdir templates
然后导航它:
1cd templates
您还会创建另一个与您的应用程序相同的名称的目录. 这是因为Django将您所拥有的各种应用程序的所有模板目录结合在一起. 为了防止文件名复制,您可以使用您的应用程序的名称来防止复制:
1mkdir weather
在这个天气
目录中,创建一个名为index.html
的新文件,这是你的主要模板。
以下是您将为模板使用的HTML:
1[label the_weather/weather/templates/weather/index.html]
2<!DOCTYPE html>
3<html lang="en">
4<head>
5 <meta charset="UTF-8">
6 <meta name="viewport" content="width=device-width, initial-scale=1.0">
7 <meta http-equiv="X-UA-Compatible" content="ie=edge">
8 <title>What's the weather like?</title>
9 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.6.2/css/bulma.css" />
10</head>
11<body>
12 <section class="hero is-primary">
13 <div class="hero-body">
14 <div class="container">
15 <h1 class="title">
16 What's the weather like?
17 </h1>
18 </div>
19 </div>
20 </section>
21 <section class="section">
22 <div class="container">
23 <div class="columns">
24 <div class="column is-offset-4 is-4">
25 <form method="POST">
26 <div class="field has-addons">
27 <div class="control is-expanded">
28 <input class="input" type="text" placeholder="City Name">
29 </div>
30 <div class="control">
31 <button class="button is-info">
32 Add City
33 </button>
34 </div>
35 </div>
36 </form>
37 </div>
38 </div>
39 </div>
40 </section>
41 <section class="section">
42 <div class="container">
43 <div class="columns">
44 <div class="column is-offset-4 is-4">
45 <div class="box">
46 <article class="media">
47 <div class="media-left">
48 <figure class="image is-50x50">
49 <img src="http://openweathermap.org/img/w/10d.png" alt="Image">
50 </figure>
51 </div>
52 <div class="media-content">
53 <div class="content">
54 <p>
55 <span class="title">Las Vegas</span>
56 <br>
57 <span class="subtitle">29° F</span>
58 <br> thunderstorm with heavy rain
59 </p>
60 </div>
61 </div>
62 </article>
63 </div>
64 </div>
65 </div>
66 </div>
67 </section>
68 <footer class="footer">
69 </footer>
70</body>
71</html>
<$>[注] 注: 幕后,我们正在使用 Bulma来处理风格和布局。 为了深入了解 Bulma 和 CSS 框架,请考虑阅读 Get to Know Bulma: My Current Favorite CSS Framework <$>
现在你已经创建了模板,让我们创建一个视图和URL组合,以便你实际上可以在你的应用中看到这一点。
Views 在 Django 中是函数或类别. 在这种情况下,因为您正在创建一个简单的视图,您将创建一个函数. 将此函数添加到您的「views.py」文件:
1[label the_weather/weather/views.py]
2from django.shortcuts import render
3
4def index(request):
5 return render(request, 'weather/index.html') #returns the index.html template
您正在命名您的视图为索引
,因为它将位于您的应用程序的索引中,即根 URL. 要获得模板渲染,您将返回请求
,这对于渲染
函数是必要的,并且您想要渲染的模板文件的名称,在这种情况下,是天气/index.html
。
在应用程序的urls.py
文件中,更新urlpatterns
列表。
1[label the_weather/weather/urls.py]
2from django.urls import path
3from . import views
4
5urlpatterns = [
6 path('', views.index), #the path for our index view
7]
这允许您参考您刚刚创建的视图。
Django将匹配任何没有终点的 URL,并将其路由到您创建的视图函数。
现在,使用您的终端返回您的项目根(‘the_weather’)。
接下来,启动服务器:
1python manage.py runserver
然后,打开您的网页浏览器,然后再次访问127.0.0.1:8000
:
您将观察index.html
文件的渲染HTML。有一个输入来添加一个城市。还有一个显示拉斯维加斯的硬代码天气。然而,此时的表格不起作用,天气只是一个位置。
步骤 6 – 使用天气 API
现在你要做的就是注册 Open Weather Map API。这将使你能够获得你添加到你的应用程序的任何城市的实时天气。
去网站,创建一个帐户,然后去他们的仪表板上的API密钥。你可以使用他们提供的默认密钥,或者你可以创建一个新的API密钥。
<$>[注] 注: 重要的是要保密API密钥,以防止其他方使用它们。
您将使用的一个终端点是下面的,因此您可以通过使用 API 密钥修改下面的 URL 来查看返回的数据并导航到浏览器中的 URL:
1http://api.openweathermap.org/data/2.5/weather?q=las%20vegas&units=imperial&appid=YOUR_APP_KEY
您的 API 密钥可能需要几分钟才能激活,所以如果它不起作用,请在几分钟后再次尝试。
您应该看到 JSON 格式的响应,包括坐标、温度和天气条件。
随着这一点,让我们添加一个请求来将数据输入到您的应用程序中。
让我们更新您的索引
视图,将请求发送到您所拥有的 URL。
1[label the_weather/weather/views.py]
2from django.shortcuts import render
3import requests
4
5def index(request):
6 url = 'http://api.openweathermap.org/data/2.5/weather?q={}&units=imperial&appid=YOUR_APP_KEY'
7
8 city = 'Las Vegas'
9
10 city_weather = requests.get(url.format(city)).json() #request the API data and convert the JSON to Python data types
11
12 return render(request, 'weather/index.html') #returns the index.html template
添加导入请求
,url
,city
和city_weather
。
使用这些新行,您将添加您将发送请求的 URL。
请注意,此 URL 与您在浏览器中测试的 URL 略有不同. 该城市不是 URL 的一部分,它已被移动到变量。
目前,您将将城市设置为拉斯维加斯
,但稍后将从数据库中设置为城市。
最后,您将将请求发送到使用该城市的 URL,并获得该城市的 JSON 表示。
如果您将其打印
到控制台,您可以看到当您将URL放入地址栏时所看到的相同数据:
1[label the_weather/weather/views.py]
2...
3def index(request):
4 ...
5 print(city_weather) #temporarily view output
6
7 return render(request, 'weather/index.html') #returns the index.html template
如果您在 Web 浏览器中重新加载该页面,您将看到数据被打印到您的控制台。
验证为真实后,您可以从代码中删除打印
声明。
步骤 7 – 在模板中显示数据
接下来,您需要将数据传输到模板中,以便向用户显示。
让我们创建一个字典,包含你需要的所有数据. 返回的数据,你将需要temp
,描述
和图标
。
1[label the_weather/weather/views.py]
2...
3def index(request):
4 ...
5 weather = {
6 'city' : city,
7 'temperature' : city_weather['main']['temp'],
8 'description' : city_weather['weather'][0]['description'],
9 'icon' : city_weather['weather'][0]['icon']
10 }
11
12 return render(request, 'weather/index.html') #returns the index.html template
现在你有你想要的所有信息,你可以将其传递给模板. 要将其传递给模板,你将创建一个名为背景
的变量。
然后在渲染
中,您将添加背景
作为第三个参数:
1[label the_weather/weather/views.py]
2...
3def index(request):
4 ...
5 context = {'weather' : weather}
6
7 return render(request, 'weather/index.html', context) #returns the index.html template
随着在背景
中添加的天气数据,让我们去模板添加数据。
在index.html
模板中,你所需要做的就是修改HTML以使用变量而不是硬编码的值。
请注意,Django 会转换字典密钥,所以你只能使用 dot 标注 来访问它们。例如,‘weather.city’ 会给你城市名称。
查找盒子
1[label the_weather/weather/templates/weather/index.html]
2...
3<div class="box">
4 <article class="media">
5 <div class="media-left">
6 <figure class="image is-50x50">
7 <img src="http://openweathermap.org/img/w/{{ weather.icon }}.png" alt="Image">
8 </figure>
9 </div>
10 <div class="media-content">
11 <div class="content">
12 <p>
13 <span class="title">{{ weather.city }}</span>
14 <br>
15 <span class="subtitle">{{ weather.temperature }}° F</span>
16 <br> {{ weather.description }}
17 </p>
18 </div>
19 </div>
20 </article>
21</div>
22...
随着所有变量被更换,您现在将被介绍为您的城市的当前天气。
然而,该城市目前仍然是硬编码的,您下一步要做的就是从数据库中拉出并显示数据库中的城市。
要做到这一点,您将在您的数据库中创建一个表格,以保留您想要知道天气的城市。
在你的天气
应用程序中,进入models.py
文件,然后添加以下内容:
1[label the_weather/weather/models.py]
2from django.db import models
3
4class City(models.Model):
5 name = models.CharField(max_length=25)
6
7 def __str__(self): #show the actual city name on the dashboard
8 return self.name
9
10 class Meta: #show the plural of city as cities instead of citys
11 verbose_name_plural = 'cities'
这将创建一个表在您的数据库中,它将有一个名为名称
的列,这是城市的名称。
要在数据库中获得这些更改,您必须运行makemigrations
来生成代码来更新数据库,并迁移以应用这些更改。
让我们停止服务器,然后在您的终端中执行迁移:
1python manage.py makemigrations
并移民:
1python manage.py migrate
你需要让它能够在你的管理器仪表板上看到这个模型. 要做到这一点,你需要在你的admin.py
文件中注册它。
1[label the_weather/weather/admin.py]
2from django.contrib import admin
3from .models import City
4
5admin.site.register(City)
接下来,重新启动服务器并在您的 Web 浏览器中查看管理仪表板。
城市
现在是一个选择。
然后您可以进入管理仪表板并添加一些城市,例如:伦敦
,东京
和拉斯维加斯
。
对于数据库中的条目,您需要在视图中查询这些条目,首先导入城市
模型,然后对所有对象查询该模型:
1[label the_weather/weather/views.py]
2from django.shortcuts import render
3import requests
4from .models import City
然后更新请求
以城市
:
1[label the_weather/weather/views.py]
2...
3def index(request):
4 url = 'http://api.openweathermap.org/data/2.5/weather?q={}&units=imperial&appid=YOUR_APP_KEY'
5
6 cities = City.objects.all() #return all the cities in the database
7 ...
因为你有城市列表,你会想旋转它们,并获得每个城市的天气,并将其添加到最终传递到模板的列表中。
這將只是你在早期步驟中所做的變化,而不同之處在於你正在循環並將每個字典附加到列表中。
首先,您将创建一个天气_数据
列表,以保持每个城市
的天气
。
然后,替换原始的城市
变量,并用城市
的循环。
接下来,每个城市
的天气
响应应应附加到天气_数据
。
您还需要更新背景
,以通过这个列表,而不是单个字典。
在此时,你的views.py
应该看起来像:
1[label the_weather/weather/views.py]
2...
3def index(request):
4 ...
5 cities = City.objects.all() #return all the cities in the database
6
7 weather_data = []
8
9 for city in cities:
10
11 city_weather = requests.get(url.format(city)).json() #request the API data and convert the JSON to Python data types
12
13 weather = {
14 'city' : city,
15 'temperature' : city_weather['main']['temp'],
16 'description' : city_weather['weather'][0]['description'],
17 'icon' : city_weather['weather'][0]['icon']
18 }
19
20 weather_data.append(weather) #add the data for the current city into our list
21
22 context = {'weather_data' : weather_data}
23
24 return render(request, 'weather/index.html', context) #returns the index.html template
接下来,在index.html
模板中,你需要绕过这个列表并生成列表中的每个城市
的HTML。
1[label the_weather/weather/templates/weather/index.html]
2...
3<div class="column is-offset-4 is-4">
4 {% for weather in weather_data %}
5 <div class="box">
6 <article class="media">
7 <div class="media-left">
8 <figure class="image is-50x50">
9 <img src="http://openweathermap.org/img/w/{{ weather.icon }}.png" alt="Image">
10 </figure>
11 </div>
12 <div class="media-content">
13 <div class="content">
14 <p>
15 <span class="title">{{ weather.city }}</span>
16 <br>
17 <span class="subtitle">{{ weather.temperature }}° F</span>
18 <br> {{ weather.description }}
19 </p>
20 </div>
21 </div>
22 </article>
23 </div>
24 {% endfor %}
25</div>
26...
现在,您可以查看您在数据库中拥有的所有城市的数据。
步骤8 - 创建形式
最后一步是允许用户通过表单直接添加城市。
您可以手动创建表单,但由于您的表单将具有与模型完全相同的字段,您可以使用ModelForm
。
在你的天气
应用程序中创建一个名为forms.py
的新文件:
1[label the_weather/weather/forms.py]
2from django.forms import ModelForm, TextInput
3from .models import City
4
5class CityForm(ModelForm):
6 class Meta:
7 model = City
8 fields = ['name']
9 widgets = {
10 'name': TextInput(attrs={'class' : 'input', 'placeholder' : 'City Name'}),
11 } #updates the input class to have the correct Bulma class and placeholder
要显示表单,您需要在视图中创建表单,并将其传输到模板中。
要做到这一点,让我们更新index.html
来创建表单,您还需要更新背景
,以便将表单传递到模板中。
1[label the_weather/weather/views.py]
2...
3from .forms import CityForm
4
5def index(request):
6 ...
7 form = CityForm()
8
9 weather_data = []
10 ...
11 context = {'weather_data' : weather_data, 'form' : form}
现在在index.html
模板中,让我们更新表单部分以便从您的视图中使用表单和一个csrf_token
,这对于Django中的POST请求是必要的。
1[label the_weather/weather/templates/weather/index.html]
2...
3<form method="POST">
4 {% csrf_token %}
5 <div class="field has-addons">
6 <div class="control is-expanded">
7 {{ form.name }}
8 </div>
9 <div class="control">
10 <button class="button is-info">
11 Add City
12 </button>
13 </div>
14 </div>
15</form>
16...
<$>[注] 注: CSRF 代表 跨站点请求伪造。
随着表单在您的HTML工作,您将需要处理表单数据,因为它进入. 为此,您将创建一个如果
块检查POST请求. 您需要在开始抓取天气数据之前添加请求类型的检查,以便您立即获得您添加的城市的数据。
1[label the_weather/weather/views.py]
2...
3def index(request):
4 url = 'http://api.openweathermap.org/data/2.5/weather?q={}&units=imperial&appid=YOUR_APP_KEY'
5
6 cities = City.objects.all() #return all the cities in the database
7
8 if request.method == 'POST': # only true if form is submitted
9 form = CityForm(request.POST) # add actual request data to form for processing
10 form.save() # will validate and save if validate
11
12 form = CityForm()
13 ...
通过通过request.POST
,您将能够验证表单数据。
现在,你应该能够输入一个城市的名称,点击添加,然后看到它出现。
例如,添加迈阿密
为下一个城市:
当您放弃如果
块时,该表单将重新创建,以便您可以添加另一个城市,如果您选择。
现在您可以在您的应用程序中跟踪多个城市的天气。
结论
在本文中,你不得不与Django的不同部分合作,以便实现此功能:视图,模型,表单和模板. 你还不得不使用Python库请求
来获取实际的天气数据。