Home >  > 网站开发(六)财务网开发之二

网站开发(六)财务网开发之二

0

二、发布文章
1.写表单
Django中三种方式写form表单,可以参考这里,这里选用第三种,即继承django.forms.ModelForm类。

这种方式不需要逐个定义字段,只需将Book类和需要显示的字段传入,也可以用fields = '__all__'传和所有字段

class BookModelForm(forms.ModelForm):
    class Meta:
        model = models.Book
        fields = '__all__'  # 类似于fields = ['title','price','publish','author'],可以自定义需要显示的字段,__all__为所有字段

我的项目代码如下:

from django import forms
from markdownx.fields import MarkdownxFormField

from zanhuapp.models import Question


class QuestionForm(forms.ModelForm):
    status = forms.CharField(widget=forms.HiddenInput())  # 隐藏
    content = MarkdownxFormField()

    class Meta:
        model = Question
        fields = ["title", "content", "tags", "status"]

2.前端表单
和forms.Form一样,在视图函数中向前端传入BookModelForm实例对象,就能自动生成form表单

不过我测试的时候,上面的测试不成功,只好用原生form表单测试。

可参考:

https://edu.51cto.com/course/2787.html

三、测试
1.question_form

    <form  action="/ask-question/" method="post">
        {% csrf_token %}
        {% for field in form %}
        <div >
            {{ field.label }}
            {{ field }}
        </div>
        {% endfor %}
        <input type="submit" value="保存"/>
    </form>

2.views

@login_required
def myCreateQuestion(request):
    '''更新个人资料'''
    questiond = Question()
    questiond.title = "my tlll"
    questiond.content = "test content"
    questiond.user_id = 1
    questiond.tags = "mytag"
    questiond.save()
    return render(request, 'zanhuapp/question_form.html')

3.成果展示

4.进一步改进,使用下面的代码可以获得当前用户的ID

   questiond.user_id = request.user.id

5.前端原生form表单

 <form action="{% url 'qa:ask_question' %}" method="post">
       {% csrf_token %}
               <input type="text" name="title">
              <input type="submit" value="POST请求">
</form>

前端用上面的代码,views用下面的代码:

    questiond = Question()
    if request.method=='POST':
        questiond.title = request.POST.get('title')

就可以成功发布title了。

四、发布问题页面
最后终于搞定了发布问题的布面,

1.前端代码:

            <form id="question_form" method="post" action="{% url 'qa:ask_question' %}">
              {% csrf_token %}
              <div class="publish-from">
                <label class="publish-from--label">问题标题:</label>
                <input class="form-control" type="text" name="title" value="" />
              </div>
              <div class="publish-from">
                <label class="publish-from--label">问题描述:</label>
                <textarea name="content" rows="15" class="form-control"></textarea>
              </div>   
              <input type="submit" class="btn btn-large btn-success" value="发布">
            </form>

备注:
from 对应的url是点击发布成功后返回的url,所以后面对应的url必须有一个view来处理数据。

2.url

path('ask-question/', views.myCreateQuestion, name='ask_question'),

3.后台接收数据

@login_required
def myCreateQuestion(request):
    '''更新个人资料'''
    questiond = Question()
    if request.method=='POST':
        questiond.title = request.POST.get('title')
        questiond.content = request.POST.get('content')
        questiond.user_id = request.user.id
        questiond.save()
    return render(request, 'zanhuapp/index.html')

五、升级发布问题
上面的代码虽然work,但是发布问题之后仍然停留在发布问题的页面,我想实现的是用户发布问题之后跳转到问题的列表页面,尝试用class base view来实现。

开始照着别人的代码来写,老是测试不成功,而且没有报错,后为不管它,回家想了想,在网上查了一下,终于找到解决方案了。(这也是解决困难问题的方法之一,先放下,再想解决办法,而不是坐在电脑前发脾气,死嗑)

只因为我没有定义form_invalid的方法,所以没有找到问题到底出在哪儿。
view的代码:

@method_decorator(cache_page(60 * 60), name='get')
class CreateQuestionView(LoginRequiredMixin, CreateView):
    """用户提问"""

    form_class = QuestionForm
    template_name = 'zanhuapp/question_form.html'
    message = "问题已提交!"

    def form_valid(self, form):
        form.instance.user = self.request.user
        return super(CreateQuestionView, self).form_valid(form)

    def form_invalid(self, form):        # 定义表对象没有添加失败后跳转到的页面。
        print(form)
        return HttpResponse("form is invalid.. this is just an HttpResponse object")

    def get_success_url(self):
        messages.success(self.request, self.message)
        return reverse_lazy("qa:index")

后来通过print(form)才发现原来有一个字段没有填写数据,原来的代码是通过js来提交的,而且是在questionform.py中设定了为隐藏的字段,我直接将它注释掉,终于可以实现发布文章并自动返回文章列表页了。

class QuestionForm(forms.ModelForm):
    # status = forms.CharField(widget=forms.HiddenInput())  # 隐藏
    content = MarkdownxFormField()

    class Meta:
        model = Question
        fields = ["title", "content", "tags"]

六、发布回复的页面
这里被一些冗余的代码耽误了,测试老是不成功,其实很简单的。
1.前端代码:

                <form id="answer-form" method="post" action="/propose-answer/{{ question.id }}/" >
                  {% csrf_token %}
                  <textarea rows="5" name="dbwcontent" class="fe-editor form-control"></textarea>
<!--                   <div class="aw-replay-box-footer clearfix">
                    <label class="pull-left">
                      <input type="checkbox" name="anonymous" value="1" />匿名回答</label>  
                  </div> -->
                      <input type="submit" class="pull-right button button--green" value="发布回答">
                </form>

2.url

path('propose-answer/<int:question_id>/', views.myCreateAnswer, name='propose_answer'),

3.views

@login_required
def myCreateAnswer(request,question_id):
    '''更新个人资料'''
    answerd = Answer()
    if request.method=='POST':
        answerd.content = request.POST.get('dbwcontent')
        answerd.user_id = request.user.id
        answerd.question_id = question_id
        # print(question_id)
        answerd.save()
    return render(request, 'zanhuapp/hello.html',{'question_id': question_id})

七、回复者的头像
1.安装sorl-thumbnail(pip install sorl-thumbnail)
并在settings.py中添加“sorl.thumbnail”。

2.头像调用

{% load static thumbnail %}   
{% thumbnail answer.user.picture "x50" as im %}
    <a href="/" class="sw-qdata--author__name aw-user-img aw-border-radius-5" rel="nofollow" target="_blank">            
    <img src="{{ im.url }}" alt="用户头像">
{% empty %}
<a href="/" class="sw-qdata--author__name aw-user-img aw-border-radius-5" rel="nofollow" target="_blank"> 
    <img src="{% static 'img/user.png' %}" alt="没有头像"/></a>
{% endthumbnail %}  

3.头像文件
需要在项目根目录建立static文件夹,即在zanhu\static\img\文件夹下面放置user.png文件。
这样就能显示图像了。

八、回复者的用户名

1.显示回复者的用户名

<a class="aw-user-name" href="/">{{ answer.user.get_profile_name }}</a>

下面的代码最开始测试的时候必须加上,后来测试好了之后发现不加也可以了。

2.相关url

 path('update/', views.UserUpdateView.as_view(), name='update'),
 path('<username>/', views.UserDetailView.as_view(), name='detail'),

3.相关Views

class UserUpdateView(LoginRequiredMixin, UpdateView):
    """用户只能更新自己的信息"""
    fields = ['nickname', 'email', 'picture', 'introduction', 'job_title', 'location',
              'personal_url', 'weibo', 'zhihu', 'github', 'linkedin']
    model = User
    template_name = 'users/user_form.html'

    def get_success_url(self):
        """更新成功后跳转到用户自己页面"""
        return reverse('users:detail', kwargs={'username': self.request.user.username})

    def get_object(self, queryset=None):
        return self.request.user    


class UserDetailView(LoginRequiredMixin, DetailView):
    model = User
    template_name = 'users/user_detail.html'
    slug_field = 'username'
    slug_url_kwarg = 'username'

    def get_context_data(self, *args, **kwargs):
        context = super(UserDetailView, self).get_context_data(**kwargs)
        user = User.objects.get(username=self.request.user.username)
        context["moments_num"] = user.publisher.filter(reply=False).count()  # 'publisher'为News表中的related_name
        context["article_num"] = user.author.filter(status='P').count()  # 只算已发表的文章
        context["comment_num"] = user.publisher.filter(reply=True).count() + user.comment_comments.all().count()  # 文章+动态的评论数
        context["question_num"] = user.q_author.all().count()
        context["answer_num"] = user.a_author.all().count()

        # 互动数 = 动态点赞数 + 问答点赞数 + 评论数 + 私信用户数(都有发送或接收到私信)
        tmp = set()
        # 我发送私信给了多少不同的用户
        sent_num = user.sent_messages.all()
        for i in sent_num:
            tmp.add(i.recipient.username)
        # 我接收的所有私信来自多少不同的用户
        received_num = user.received_messages.all()
        for r in received_num:
            tmp.add(r.sender.username)

        context["interaction_num"] = user.liked_news.all().count() + user.qa_vote.all().count() + context["comment_num"] + len(tmp)
        return context    

九、搜索功能
基本上按以前的代码就可以了。

def search(request):
    allQuestions = Question.objects.all()
    q = request.GET.get('q')
    error_msg = ''

    if not q:
        error_msg = '请输入关键词'
        return render(request, 'zanhuapp/index.html', {'error_msg': error_msg})
    else:
        questions_list = allQuestions.filter(title__icontains=q)
    return render(request, 'zanhuapp/index.html', {'error_msg': error_msg,
                                               'questions_list': questions_list})

十、侧边栏
使用views传多个参数

    def get_context_data(self, *, object_list=None, **kwargs):
        context = super(QuestionDetailView, self).get_context_data()
        context["new_questions"] = Question.objects.all()[:10]
        context["hot_users"] = User.objects.all()[:10]       
        return context  

然后在模板中就可以使用hot_users、new_questions进行展示了。

十一、分页功能

1.上一次开发还要使用插件,现在直接修改下面代码中的paginate_by = 5的数量就可以了。

class QuestionListView(LoginRequiredMixin, ListView):
    """所有问题页"""

    queryset = Question.objects.select_related('user')
    paginate_by = 5
    context_object_name = "questions"
    template_name = "zanhuapp/question_list.html"


    def get_context_data(self, *, object_list=None, **kwargs):
        context = super(QuestionListView, self).get_context_data()
        context["popular_tags"] = Question.objects.get_counted_tags()  # 页面的标签功能
        context["active"] = "all"
        context["new_questions"] = Question.objects.all().order_by('-created_at')[:10]
        context["hot_users"] = User.objects.all()[:10]
        return context

2.然后在网上找了一段代码,直接复制上去就可以了:

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>

<h3>Django Boostrap 4分页模板</h3>
{# 注释: page_obj不要改。for里的article可以改成自己对象 #}
{% if page_obj %}
    <ul> {% for article in page_obj %}
   <li><a href="{% url 'blog:article_detail' article.id %}"> {{ article.title }}</a> {{ article.pub_date | date:"Y-m-j" }}</li>
    {% endfor %}
   </ul>

{# 注释: 下面代码一点也不要动 #}
   {% if is_paginated %}
     <ul class="pagination">
    {% if page_obj.has_previous %}
      <li class="page-item"><a class="page-link" href="?page={{ page_obj.previous_page_number }}">Previous</a></li>
    {% else %}
      <li class="page-item disabled"><span class="page-link">Previous</span></li>
    {% endif %}

    {% for i in paginator.page_range %}
        {% if page_obj.number == i %}
      <li class="page-item active"><span class="page-link"> {{ i }} <span class="sr-only">(current)</span></span></li>
       {% else %}
        <li class="page-item"><a class="page-link" href="?page={{ i }}">{{ i }}</a></li>
       {% endif %}
    {% endfor %}

         {% if page_obj.has_next %}
      <li class="page-item"><a class="page-link" href="?page={{ page_obj.next_page_number }}">Next</a></li>
    {% else %}
      <li class="page-item disabled"><span class="page-link">Next</span></li>
    {% endif %}
    </ul>
    {% endif %}

{% else %}
{# 注释: 这里可以换成自己的句子 #}
    <p>No article yet</p>
{% endif %}

参考:https://blog.csdn.net/weixin_42134789/article/details/80568089

本文暂无标签

发表评论

*

*