您的位置:首页 > 编程语言 > Go语言

使用Django2搭建WEB项目

2019-07-26 20:13 211 查看
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/qq_41121791/article/details/97006916

步骤

  • 主题页面
  • 添加主题页面
  • 添加主题视图
  • 添加条目页面
  • 条目表单
  • 添加条目视图

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

    创建虚拟环境

    使用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.csdn.net/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
    这个父类能更加方便的创建表单,并且还能根据表单内容直接在数据库中插入数据,而不是先创建出来模型,再调用模型的方法

    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: