使用Django2搭建WEB项目

本文详细介绍使用Django框架搭建Web项目的全过程,包括环境搭建、项目创建、模型设计、视图编写、表单处理及页面展示等内容,适合初学者快速入门。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


本来想写在自己电脑上,但是怕哪天电脑炸了东西都没了,还是写这把

创建虚拟环境

使用python的venv模块创建一个虚拟环境命令:

python -m venv 环境名称

PS:先创建一个文件夹,名字随便,然后cmd命令行中进入这个文件夹执行上边的代码

安装Django2

创建完虚拟环境就进入虚拟环境里边执行pip安装就行了

环境名称\Scripts\activate

进去后就安装Django

pip install -i 镜像 django

创建项目

还是在虚拟环境里,调用\Scripts\django-admin.py文件创建项目

django-admin.py startproject 项目名称 .

PS:这个点不要省去,意思应该是在当先目录下,也就是最外边那个目录,我下去在琢磨琢磨
项目创建完了当前目录下就有了项目配置文件夹和一个manage.py文件
然后把数据库也弄出来,迁移出来

python manage.py migrate

执行完上边代码当前目录下会出现一个db.sqlite3数据库文件

打开服务器

python manage.py runserver

现在可以打开浏览器输入localhost:8000看看Django提供的入坑页面了

创建应用程序

还是用manage.py文件来创建

python manage.py startapp 应用名称

执行完会创建一个应用名称的文件夹,里边就是你的应用内容了
别忘了在项目文件夹下的settings.py里边声明一下,在INSTALLED_APPS里边加上一项你的应用名称_

配置url

打开项目文件夹下的urls.py文件,在里边的urlpatterns列表里加个path

path('前缀',include('应用名称.urls',namespace='命名空间'))

虽说所有的url也都能在这配,但是都配一块都点乱,就分开配
上边那个path意思是引入应用名称下的urls.py里边的url
所以接下来你就在应用文件夹下边创建一个urls.py文件,导入一切该导入的
在urls文件中写入下列代码

app_name = '[应用名称]'

也可以在include函数中写入

include(('应用名称.urls','app_name'),namespace='')

没有app_name这一项的话总的urls引入应用的urls时会报错
源码看看:

def include(arg, namespace=None):
    app_name = None
    if isinstance(arg, tuple):
        try:
            urlconf_module, app_name = arg
        except ValueError:
           #抛个异常
    else:
    	# No namespace hint - use manually provided namespace.
  		urlconf_module = arg

之后就跟总的urls一样了

urlpattern = [path('',views.xxx,name='')]

总url配置到这就没了,具体的url配置看后边
PS:Django2url换成了re_path,用re_path就能完成url一样的功能

re_path('xxx/(?P\<name>)',views.xxx,name='xxx')

源码看看:

def _path(route, view, kwargs=None, name=None, Pattern=None):
   	if isinstance(view, (list, tuple)):
	     # For include(...) processing.
	     pattern = Pattern(route, is_endpoint=False)
	     urlconf_module, app_name, namespace = view
	     return URLResolver(
     		pattern,
            urlconf_module,
            kwargs,
            app_name=app_name,
            namespace=namespace,
	        )
    elif callable(view):
        pattern = Pattern(route, name=name, is_endpoint=True)
        return URLPattern(pattern, view, kwargs, name)
    else:
        raise TypeError('view must be a callable or a list/tuple in the case of include().')
        
path = partial(_path, Pattern=RoutePattern)
re_path = partial(_path, Pattern=RegexPattern)

path和re_path调用的还是同一个函数,只不过正则表达式处理不太一样

模型编写

应用文件夹下的models里边,在这写模型内容
举个栗子:

class Test(models.Model):
	title = models.CharField(max_length=20)
	text = models.TextField()
	#时间戳字段,设置了auto_now_add
	date_added = models.DateTimeField(auto_now_add=True)
	
	class Meta:
		#附加选项

	def __str__(self):
		return self.title

就像创建一个正常的类一样,在Java里就是JavaBean,只不过类字段用的是models模块下的特定类字段
这里的模型都会被ORM的API根据模型的结构映射到数据库

在admin中注册模型

在应用文件夹下打开admin.py添加代码:

from 应用名.models import Test

admin.site.register(Test)

在admin中注册后就能在Django提供的管理页面中进行管理,不过先别急,先把数据库表创建出来

迁移数据库

在虚拟环境下执行

python manage.py makemigrations

python manage.py migrate

第一行代码是检测你有没有添加新的模型,程序会根据你编写的模型制定数据库表
第二行代码就是执行迁移了,把表创建出来
这两个代码也可以用于更新数据库,比如果你的两个模型之间有关联,添加外键后再次执行上边的两行代码

创建超级管理员账号

在虚拟环境中执行代码

python manage.py createsuperuser

然后输入用户名密码就能进行创建了

登录admin界面管理模型

输入网址:

http://localhost:8000/admin

输入创建的管理员的用户名和密码就能登录Django自带的管理界面

完善框架

在之前已经初步应用了Django框架,当然使用的是Django自带的功能,下边来搭建自己的框架,举个栗子,来搭建一个自己的博客网站。
网站模型:

BlogTopic	#主题
BlogEntry	#条目

网站页面:

base.html
index.html
topics.html
topic.html
new_topic.html
new_entry.html

表单:

TopicForm	#主题表单
EntryForm	#条目表单

内容只有两个主题和条目,一个主题包含多个条目,两者是一对多的关系。
文档说明:

访问localhost:8000后显示出首页index,首页中能够跳转到主题列表页面topics
在主题列表页面中能添加主题new_topic
点击主题就能够进入条目列表页面
条目列表页面能够添加条目new_entry

写代码前先把文档定好,免得不知道要干啥,接下来就开始了。
首先创建应用Blogs,就像上边一样

编写网页

首先在应用文件夹下创建以下文件夹

templates/blogs/

至于为什么创建个templates文件夹,是因为使用模板规定需要创建个这么个文件夹,等我下去翻翻看源码在做进一步说明。
编写base.html页面

base.html	#此页面是所有页面的父页面
<!DOCTYPE>
<html>
	<head>
	</head>
	<body>
		<p>
			<a href="{% url 'blogs:index' %}">index</a> -
			<a href="{% url 'blogs:topics' %}">topics</a>
		</p>
		{% block content%}{% endblock content%}
	</body>
</html>

为了演示就写的简单点,上边的{% url ‘xxx:xxx’%}表示一个url,框架会匹配urls文件中的url,格式就是namespace:name
{% block content %}{% endblock content%}表示一个块,content是块名称,用以引入子内容,继续往下看就明白了。

index.html	#首页
{% extends 'blogs/base.html'%}
{% block content %}
	<p>这是一个index页面</p>
{% endblock content %}

{% extends ‘blogs/base.html’ %}表示继承自base.html同时content块中的内容填充到父html中
同样的编写其他几个页面,内容可以先不填充但是把框架写好

配置urls

在总的urls配置中加入下边代码,表示引入外部urls文件

path('blogs/',include('blogs.urls',namespace='blogs'))	#app_name在文件中写入

打开urls.py(应用下的),导入django.urls下的path,re_path
编写index的url

from . import views

urlpatterns = [
	#主题列表url
	re_path('topics/',views.topics,name='topics'),
	#主题url
	re_path('topic/(?P<topic_id>\d+)',views.topic,name='topic'),
	#添加主题url
	re_path('new_topic/',views.new_topic,name='new_topic'),
	#添加条目url
	re_path('new_entry/(?P<topic_id>\d+)',views.new_entry,name='new_entry'),
	#index ulr
	re_path('',views.index,name='index')
]

上述代码分别配置了主题列表url,单个主题url,新建主题url,新建条目url,index页面
在这里使用re_path的原因是因为要用到正则表达式
首先导入视图文件views
在re_path函数中第一个参数是配置的访问的url;第二个参数是视图,也就是处理信息的函数,他会根据处理结果返回给一个页面;第三个参数是名称
这里的

(?P<topic_id>\d+)

是一个正则表达式中的group,使用(?P<name>)表示给这个组起个名称,在后续能够根据名称直接找到相应的group,而(?P=name)表示引用之前命名的group
在上边的代码中给一个group命名为topic_id,匹配模式为一或多个数字用于获取id号
想要再详细了解re中的group可以去查官方文档

编写视图views

打开views.py

#index视图
def index(request):
	return render(request,'blogs/index.html')
	
#主题列表视图
def topics(request):
	pass

#主题视图
def topic(request,topic_id):
	pass

#添加主题视图
def new_topic(request):
	pass

#添加条目视图
def new_entry(request,topic_id):
	pass

这里先把视图框架写上,后边在完善一下
现在可以打开网页访问index页面了,记得加上命名空间

http://localhost:8000/blogs/index

完善模型

打开models.py文件

class BlogTopic(models.Model):
	name= models.CharField(max_length=100)
	#时间戳
	date_added = models.DateTimeField(auto_now_add=True)

	#打印对象名称
	def __str__(self):
		return self.name

class BlogEntry(models.Model):
	title = models.CharField(max_length=100)
	text = models.TextField()
	#外键
	topic = models.ForeignKey(BlogTopic,on_delete=models.CASCADE)
	date_added = models.DateTimeField(auto_now_add=True)

	def __str__(self):
		if len(self.text) > 50:
			return self.text[:50]
		return self.text

模型继承models.Model,使用模型中的定义的字段类来映射数据库中对应的字段。
从models的包中就可以看出来,其实models是数据库的API

from django.db import models

其中字段类都放在虚拟环境文件夹下的

django\db\models\fields\__init__.py

具体就不做解释了,有兴趣自己查,大致意思就是
BlogTopic模型定义了name字段和一个自动添加的时间戳字段用以判断添加的先后顺序
BlogEntry模型定义了title字段和text文本字段还有一个时间戳
同时因为BlogTopic和BlogEntry之间的关联关系,又定义了一个外键ForeignKey,外键的字段类在

django\db\models\fields\related

有兴趣自己翻,这里列出来他的__init__函数

def __init__(self, to, on_delete, related_name=None, related_query_name=None,
             limit_choices_to=None, parent_link=False, to_field=None,
             db_constraint=True, **kwargs):
             pass

第一个参数to指的就是关联谁,on_delete就是删除连带操作了,也就是级联,这里我用的是models.CASCADE
其他类型在

django\db\models\deletion.py

PS:记得迁移数据库

在admin中注册

from .models import BlogTopic,BlogEntry

admin.site.register(BlogTopic)
admin.site.register(BlogEntry)

视图和界面详细设计

主题列表视图

def topics(request):
	#根据添加时间进行排序
	topics = BlogTopic.objects.order_by('date_added')
	context = {'topics':topics}
	return render(request,'blogs/topics.html',context)

前边说了,models其实是操作数据库的API,BlogTopics继承了models.Model也就能够操作数据库进行增删改查

objects是Django帮我们自动生成的管理器对象,通过这个管理器可以实现对数据的查询, objects是models.Manager类的一个对象,如果我们模型类中添加一个models.Manger类或者其子类变量,那么Django就不再帮我们生成默认的objects管理器。(引用自https://blog.youkuaiyun.com/weixin_40576010/article/details/88621357)

调用order_by根据字段‘date_added’排序,搜索出所有的记录,然后放到一个字典中,并将这个字典作为参数传入render中,render函数会将字典中的值放入页面中,我们就可以在页面中根据名称直接引用了

主题列表页面:

{% extends 'blogs/base.html'%}
{% block content%}
	<ul>
		{% for topic in topics %}
			<li><p>{{topic}}</p></li>
		{% empty %}
			<p>暂时没有添加任何主题</p>
		{% endfor %}
	</ul>
{% endblock content%}

页面中引用变量用{{变量名}},{%%}中编写代码
在浏览器中打开看一下

http://localhost:8000/blogs/topics

没有数据的可以登录admin界面插入一点

主题视图

def topic(request,topic_id):
	#根据id获取对象	数据库自动创建id
	topic = BlogTopic.objects.get(id=topic_id)
	#外键反向查询
	entries = topic.blogentry_set.order_by('date_added')
	context = {'topic':topic,'entries':entries}
	return render(request,'blogs/topic.html',context)

一个主题包含多个条目,在查询单个主题后要把相应主题下的所有条目也一并查询出来

这里函数有两个参数,一个是所有views下的函数都有的request请求,另一个是我们在定义urls的时候从url中捕获的参数,名称要与url中group的名称相同,忘记的可以往上翻翻
这里获取topic就像是SQL中的where id = topic_id,拿到制定id的topic记录
这里blogEntry_set是获取topic下的entry集合格式为主表.子表_set,主表处替换成查询出来的topic,子表名是类全小写

完成主题视图后,前边的主题列表页面可以改动一下啦
主题列表页面

{% extends 'blogs/base.html'%}
{% block content%}
	<ul>
		{% for topic in topics %}
			<li>
				<p>
					<a href="{% url 'blogs:topic' topic.id %}">{{topic}}</a>
				</p>
			</li>
		{% empty %}
			<p>暂时没有添加任何主题</p>
		{% endfor %}
	</ul>
{% endblock content%}

将标题改为一个链接,通过点击标题跳转到相应的主题页面,url是blogs下的topic,参数带在后边
这里注意一下,用 . 的方式获取id,并且topic要是已经放入页面的参数
如果直接访问这个页面而不是通过视图的方式,就会发现这里什么都没有

主题页面

路径blogs/templates/blogs/topic.html

{% extends 'blogs/base.html'%}
{% block content%}
	<p>主题:{{topic}}</p>
	<ul>
		{% for entry in entries%}
			<li><p>{{entry}}</p></li>
		{% empty %}
			<p>暂时没有添加任何条目</p>
		{% endfor %}
	</ul>
{% endblock content%}

这里主题页面类似于主题列表页面,毕竟主题页面也是条目列表页面

添加主题页面

这里我们先写页面
路径:blogs/templates/blogs/new_topic.html

{% extends 'blogs/base.html'%}
{% block content%}
		<form action="{% url 'blogs:new_topic' %}" method="post">
			{% csrf_token %}
			主题名称:<input type="text" name="name"/><br>
			<input type="submit" value="添加"/>
		</form>
{% endblock content%}

这里我们看到有一个表单,在django框架中,表单也是要被定义的一个类
页面显示的表单其实是后台发送过来的一个表单对象
这里的 {% csrf_token %} 必须带上,{% csrf_token %} 来防止攻击者利用表单来获得对服务器未经授权的访问(这种攻击被称为跨站请求伪造 )
下边编写TopicForm主题表单
在应用文件夹下创建forms.py文件,所有应用下的表单都写在这个文件中

#forms.py
from django.forms import forms

class TopicForm(forms.Form):
	name = forms.CharField(max_length=100)

这里定义了TopicForm,表单只有一个name字段
父类是django.forms下的forms文件中的Form类
表单中的字段要跟你页面中的表单字段一致,更多其他字段见forms.fields.py文件
添加主题的表单就写完了,如果想要知道更多表单信息可以看环境中的源码库

添加主题视图

from .forms import TopicForm
from django.http import HttpResponseRedirect
from django.urls import reverse

def new_topic(request):
	#判断请求方法
	if request.method != 'POST':
		form = TopicForm()
	else:
		form = TopicForm(request.POST)
		if form.is_valid():
			topic = BlogTopic()
			#获取提交数据
			topic.name = request.POST.get('name','')
			topic.save()
			#重定向
			return HttpResponseRedirect(reverse('blogs:topics'))
	context = {'form':form}
	return render(request,'blogs/new_topic.html',context)

首先判断请求是什么类型的,一般GET是请求服务器数据,而POST是向服务器提交数据的
在第一次访问new_topic页面时要先向服务器请求表单数据,所以我们发现method是GET后创建一个空的表单返还给页面
当用户提交表单后method就是POST,我们根据请求的POST内容创建表单,然后判断表单是否符合规范,如果符合规范就创建一个主题对象并将表单中的数据赋值给主题对象的属性,然后主题调用父类的save方法保存到数据库中

正常流程是添加成功后跳转到主题列表页面,但是render中的url是以页面路径的方式来填写的,这样虽然能够访问页面,但是因为没有经过视图的处理,所以页面的内容是空的,为了解决这个问题这里我们用重定向的方式来重新访问主题列表视图,以此获取数据
HttpResponseRedirect就是重定向类
reverse能够将字符串解析为url,格式为namespace:name

视图写完后我们再次更改一下主题列表页面:

{% extends 'blogs/base.html'%}
{% block content%}
	<p><a href="{% url 'blogs:new_topic'%}">添加主题</a></p>
	<ul>
		{% for topic in topics %}
			<li>
				<p>
					<a href="{% url 'blogs:topic' topic.id %}">{{topic}}</a>
				</p>
			</li>
		{% empty %}
			<p>暂时没有添加任何主题</p>
		{% endfor %}
	</ul>
{% endblock content%}

访问页面试一下

http://localhost:8000/blogs/new_topic

添加条目页面

{% extends 'blogs/base.html'%}
{% block content %}
	<form action="{% url 'blogs:new_entry' topic.id %}" method="post">
		{% csrf_token %}
		<input type="text" name="title"/><br>
		<input type="text" name="content" cols="50" rows="6"/><br>
		<input type="submit" value="添加"/>
	</form>
{% endblock content%}

条目表单

#forms.py

class EntryForm(forms.Form):
	title = forms.CharField(max_length=100)
	content = forms.TextField()

添加条目视图

#views.py

from .forms import EntryForm

def new_entry(request,topic_id):
	#根据id获取对象
	topic = BlogTopic.objects.get(id=topic_id)
	if request.method != 'POST':
		form = EntryForm()
	else:
		form = EntryForm(request.POST)
		if form.is_valid():
			entry = BlogEntry()
			#关联外键
			entry.topic = topic
			entry.title = request.POST.get('title','')
			entry.text= request.POST.get('content','')
			#保存对象 在数据库中插入一条记录
			entry.save()
			#重定向
			return HttpResponseRedirect(reverse('blogs:topic',args=[topic_id]))
	context = {'form':form,'topic':topic}
	return render(request,'blogs/new_entry.html',context)

跟之前差不多,外键关联一下,然后重定向的时候带个参数args
PS:这里注意一下,BlogEntry里用的是text表示内容,而表单用的是content表示内容,不要搞混了

更改一下主题页面

{% extends 'blogs/base.html'%}
{% block content%}
	<p>主题:{{topic}}</p>
	<p><a href="{% url 'blogs:new_entry' topic.id %}">添加条目</a></p>
	<ul>
		{% for entry in entries%}
			<li>
				<p>{{entry.title}}</p>
				<p>{{entry.text}}</p>
			</li>
		{% empty %}
			<p>暂时没有添加任何条目</p>
		{% endfor %}
	</ul>
{% endblock content%}

到这里就大功告成了

上边就是搭建一个web项目的方法,这篇写的很基础,如果想要更复杂的功能,可以看源码,或者上网搜搜。
其实上边提供的表单还有另一个方式,就是继承自forms.FormModel
这个父类能更加方便的创建表单,并且还能根据表单内容直接在数据库中插入数据,而不是先创建出来模型,再调用模型的方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值