zoukankan      html  css  js  c++  java
  • Django开发一个投票应用

    一、目标:前端 + 后端 + 静态文件

    前端:

    首页:简单展示一个列表页面

    投票页:有投票选项,投票按钮

    结果页:展示投票后各个投票选项的投票数

    后端

    admin:增删改查投票选项,能够按照时间排序投票选项,能够增删改查用户。

    静态文件

    css样式引入,a标签链接颜色修改,body的background设置为图片

    目录结构

    详细目录结构

     

    二、前端展示效果

     

    首页

    投票页

      

    结果页

     三、后端admin

     

    首页

    按时间排序投票选项

    增删改查某一投票选项

    用户的增删改查

      

      

    四、具体实现

    • 实现一个queckstart(见前一篇)
    • 连接数据库并建立models模型
    • views视图函数实现
    • teplates各个页面模板页面实现
    • urls注册views函数
    • 静态文件渲染修饰
    • 配置admin.py
    • 自定义admin的模板文件
    • 主项目目录修改settings
    • 启动应用

    连接数据库并建立models模型

    主项目项目settings.py配置数据库,我这里直接用的Django自带的sqlite3,配置如下

    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': str(BASE_DIR / 'db.sqlite3'),
        }
    }

    注意:'NAME': str(BASE_DIR / 'db.sqlite3') 这里的str,不加上会提示类型不对。

    投票应用polls建立models模型

    import datetime
    from django.utils import timezone
    from django.db import models
    from django.contrib import admin
    # Create your models here.
    
    
    class Question(models.Model):
        question_text = models.CharField(max_length=200)
        pub_date = models.DateTimeField('date published')
    
        # @admin.display(
        #     boolean=True,
        #     ordering='pub_date',
        #     description='Published recently?',
        # )
        # 自定义判断是否最近一天发布方法(返回True或Flase)
        def was_published_recently(self):
            now = timezone.now()
            return now - datetime.timedelta(days=1) <= self.pub_date <= now
        # 自定义对象返回的魔术方法,对象返回question_text
        def __str__(self):
            return self.question_text
        # 同__str__
        __repr__ = __str__
    
    class Choice(models.Model):
        question = models.ForeignKey(Question, on_delete=models.CASCADE) # 关系键,上面的Question表中的具体对象(记录)会多一个choice_set的属性
        choice_text = models.CharField(max_length=200)
        votes = models.IntegerField(default=0)
    
        def __str__(self):
            return self.choice_text
    
        __repr__ = __str__

    views视图函数实现

    from django.http import HttpResponseRedirect
    from django.shortcuts import get_object_or_404, render
    from django.urls import reverse
    from django.views import generic
    from django.urls import path
    from .models import Choice, Question
    
    # 这一版用到了通用视图,也更加抽象
    
    class IndexView(generic.ListView):
        template_name = 'polls/index.html'
        context_object_name = 'latest_question_list'
    
        def get_queryset(self):
            """Return the last five published questions."""
            return Question.objects.order_by('-pub_date')[:5]
    
    
    class DetailView(generic.DetailView):
        model = Question
        template_name = 'polls/detail.html'
    
    
    class ResultsView(generic.DetailView):
        model = Question
        template_name = 'polls/results.html'
    
    
    def vote(request, question_id):
        question = get_object_or_404(Question, pk=question_id)
        try:
            selected_choice = question.choice_set.get(pk=request.POST['choice'])
            selected_choice.votes += 1
            selected_choice.save()
            return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))
        except (KeyError, Choice.DoesNotExist):
            return render(request, 'polls/detail.html', {
                'question': question,
                'error_message': "You didn't select a choice.",
            })
    
    # ----------------------------------------------------------------------------下面这版更好理解
    # from django.shortcuts import render, get_object_or_404, get_list_or_404
    # from django.template import loader
    # from django.http import HttpResponse, Http404, HttpResponseRedirect
    # from .models import Question, Choice
    # from django.urls import reverse
    # # Create your views here.
    #
    # def index(request):
    #     latest_question_list = get_list_or_404(Question)[:5]
    #     context = {
    #         'latest_question_list': latest_question_list
    #     }
    #     return render(request, 'polls/index.html', context)
    #
    #
    # def detail(request, question_id):
    #     question = get_object_or_404(Question,pk=question_id)
    #     return render(request, 'polls/detail.html', {'question': question})
    #
    #
    # def results(request, question_id):
    #     question = get_object_or_404(Question, pk=question_id)
    #     return render(request, 'polls/results.html', {'question': question})
    #
    #
    # def vote(request, question_id):
    #     question = get_object_or_404(Question, pk=question_id)
    #     try:
    #         selected_choice = question.choice_set.get(pk=request.POST['choice'])
    #         selected_choice.votes += 1
    #         selected_choice.save()
    #         return HttpResponseRedirect(reverse('polls:results', args=(question.id,)))
    #     except (KeyError, Choice.DoesNotExist):
    #         return render(request, 'polls/detail.html', {
    #             'question': question,
    #             'error_message': "You didn't select a choice.",
    #         })

    teplates各个页面模板页面实现

    index页面(首页)

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>index</title>
        {% load static %}
    <link rel="stylesheet" type="text/css" href="{% static 'polls/style.css' %}">
    </head>
    <body>
    {% if latest_question_list %}
        <ul>
        {% for question in latest_question_list %}
            <li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
        {% endfor %}
        </ul>
    {% else %}
        <p>No polls are available.</p>
    {% endif %}
    </body>
    </html>

    detail页面(投票页面)

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>detail</title>
    </head>
    <body>
    <h1>{{ question.question_text }}</h1>
    {% if error_message %}
    <p><strong>{{ error_message }}</strong></p>
    {% endif %}
    <form action="{% url 'polls:vote' question.id %}" method="post">
    {% csrf_token %}
    {% for choice in question.choice_set.all %}
        <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}">
        <label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label>
        <br>
    {% endfor %}
    <input type="submit" value="Vote">
    
    </form>
    </body>
    </html>

    results页面(投票结果页面)

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>results</title>
    </head>
    <body>
    <h1>{{ question.question_test }}</h1>
    <ul>
    {% for choice in question.choice_set.all %}
        <li>{{ choice.choice_text }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li>
    {% endfor %}
    </ul>
    <a href="{% url 'polls:detail' question.id %}">Vote again?</a>
    </body>
    </html>

    urls注册views函数

    from django.urls import path
    from . import views
    
    # 使用了通用视图模板,也更加抽象
    app_name = 'polls'
    urlpatterns = [
        path('', views.IndexView.as_view(), name='index'),
        path('<int:pk>/', views.DetailView.as_view(), name='detail'),
        path('<int:pk>/results/', views.ResultsView.as_view(), name='results'),
        path('<int:question_id>/vote/', views.vote, name='vote'),
    ]
    # --------------------------------------------------------------------下面一版更好理解
    
    # from django.urls import path
    # from . import views
    #
    # app_name = 'polls'
    # urlpatterns = [
    #     path('', views.index, name='index'),
    #     path('<int:question_id>/', views.detail, name='detail'),
    #     path('<int:question_id>/results/', views.results, name='results'),
    #     path('<int:question_id>/vote/', views.vote, name='vote'),
    # ]

    静态文件渲染修饰style.css

    li a{
        color: green;
    }
    body {
        background: white url("images/background.gif") no-repeat;
    }

    配置admin.py

    from django.contrib import admin
    from .models import Question, Choice
    # Register your models here.
    
    
    class ChoiceInline(admin.TabularInline):
        model = Choice
        extra = 3
    
    # class ChoiceInline(admin.StackedInline): #StackedInline为更加详细的choice展现形式
    #     model = Choice
    #     extra = 3
    
    
    class QuestionAdmin(admin.ModelAdmin):
        fieldsets = [
            (None, {'fields': ['question_text']}),
            ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
        ]
        inlines = [ChoiceInline]
        list_display = ('question_text', 'pub_date', 'was_published_recently')
        list_filter = ['pub_date']
    
    
    admin.site.register(Question, QuestionAdmin)

    自定义admin的模板文件(django/contrib/admin/templates/admin/base_site.html复制到 主项目目录/templates/admin/base_site.html,然后修改如下)

    {% block branding %}
    <h1 id="site-name"><a href="{% url 'admin:index' %}">Polls Administration</a></h1>
    {% endblock %}

    主项目目录settings修改TEMPLATES

    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [BASE_DIR / 'templates'],
            'APP_DIRS': True,
            'OPTIONS': {
                'context_processors': [
                    'django.template.context_processors.debug',
                    'django.template.context_processors.request',
                    'django.contrib.auth.context_processors.auth',
                    'django.contrib.messages.context_processors.messages',
                ],
            },
        },
    ]

    启动应用

    python manage.py runserver

    一些坑:

    1. polls投票应用投票时候,总是被异常捕获,进入不了投票结果页results.html

    后来发现是一个低级错误,由于这里收不到POST请求,所以就一直被捕获KeyError

    2.静态文件渲染那里,一直刷新是不会有效果的,一定要重启应用。(修改配置py等文件,应用会自动帮你重启,静态文件修改应用不会帮你自动重启)

    ORM数据库迁移

    python manage.py makemigrations  #为模型的改变生成迁移文件
    
    python manage.py migrate # 应用数据库迁移
  • 相关阅读:
    程序员创业必读的几本书
    新手上路—Java的"瑞士军刀"
    小团队互联网创业记
    Coder必须自废的两样神功
    码界新手,如何更高效的解决问题
    【转载】FckEditor 2.6.3 for Java 2.4 配置
    struts2上传多文件(b)
    Java基础-Java中的Calendar和Date类
    JAVA加减日期
    Java程序员应该了解的10个面向对象设计原则
  • 原文地址:https://www.cnblogs.com/soymilk2019/p/14819170.html
Copyright © 2011-2022 走看看