• 138-使用django制作博客的个人中心页面,并进行关注,取消关注等操作


    【1】首先完善ExUser的信息

    这里考虑将username信息“复制”到ExUser,避免总是用User去做各种验证:即uid从user的username获取;

    其他各种属性包括昵称、粉丝数、微信、QQ、电子邮件、email、注册时间、最近登录时间。

    class ExUser(models.Model):
        user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='ex_user')
        uid = models.CharField(max_length=128, default='username')
        nickname = models.CharField(max_length=128, default='默认昵称')
        fans_count = models.BigIntegerField(default=0)
        confirm_password = models.CharField(max_length=32)
        wechat_id = models.CharField(max_length=128, unique=True, blank=True, null=True)
        qq_num = models.BigIntegerField(unique=True, blank=True, null=True)
        email = models.EmailField(unique=True, blank=True, null=True)
        tel_num = models.BigIntegerField(unique=True, blank=True, null=True)
        create_time = models.DateTimeField(auto_now_add=True)
        last_login_time = models.DateTimeField(blank=True, null=True)
    
        def __str__(self):
            return self.uid
    

      

    【2】新建一个用于反映关注关系的模型。

    一些不是很重要的信息,没必要做关联性,之前解决点赞时是这个思路,这里同样。不过这种方式并不推荐在生产环境下被使用,因为如果对应的user或note被删除了,和其有关的点赞或关联信息不会被删除!这里先记录一下,后续会解决这个问题。

    这里只有被关注者,关注者,关注时间。

    class FollowRelation(models.Model):
        followed = models.CharField(max_length=128, blank=True, null=True)
        following = models.CharField(max_length=128, blank=True, null=True)
        follow_time = models.DateTimeField(auto_now_add=True)
    
        def __str__(self):
            return self.followed, '<<<', self.following
    

      

    【3】显示个人信息。

    这里的逻辑比较复杂,在用一个views函数渲染个人页面之前,还有关键两步要做:

    1-让ExUser的uid记住所对应的那个User的username,这个操作在注册时完成。

    可以发现,在完成注册时,user所对应的那个exuser需要保存几个关键信息:uid,二次确认的密码,最近登录时间。另外注册时间会自动保存,这里不用显式操作。

                        new_user = User.objects.create_user(username=username, password=password)
                        # 注意!由于一对一的关系,当一个User被注册(also created)时,一个ExUser对象被创建,因此这里需要用新建实例的方式来创建对象,然后存储对象
                        # 但是已经存在的ExUser,不能用这种方式
                        new_exuser = ExUser(user=new_user)
                        new_exuser.uid = new_user.username
                        new_exuser.confirm_password = confirm_password
                        new_exuser.last_login_time = datetime.datetime.now()
                        new_exuser.save()
                        # 注册完成后,同时进行登录
                        login(request, new_user)
                        return HttpResponseRedirect(reverse('notebook:start_page'))
    

    2-将所有指向个人信息的链接中,统一传递username。

    第一个是查看自己的个人信息,传递的是user.username;

    第二个是查看别人的个人信息(在网站里有很多个这样的链接,这里以其中一个为例),由于文章的作者,其实就是某个user的username,即:new_note.author = current_user.username,所以这里的效果是等价的。

                <p> 欢迎:
                    <a href="{% url 'account:personal' user.username %}">{{user.username}}</a>
                    <a href="{% url 'account:logout' %}" class="menu_item">退出</a>
                </p>
    

      

        <p>
            分类:{{note.note_category}}
            作者:<a href="{% url 'account:personal' note.author %}">{{note.author}}</a>
        </p>
    
            form = NoteForm(request.POST)
            if form.is_valid():
                new_note = form.save(commit=False)
                new_note.user = current_user
                new_note.author = current_user.username
                new_note.save()
                # Without this next line the tags won't be saved.
                form.save_m2m()
                return HttpResponseRedirect(reverse('notebook:one_note', args=[new_note.pk]))
    

      

      

    3-现在看具体的views函数。解析如下:

    在进入if——else之前,先获取3个内容,之后都要作为上下文传入。

    the_exuser:根据uid获取,这个页面因为只查看,不能编辑,所以全部用the_exuser点出来,没有使用modelform;

    if_follow:判断是否已经有对应的记录,如果有表示已经关注了,可以取消;如果没有,提供关注操作;

    最后特别要注意username,这个属性在这里要多次传入传出。

    if部分,根据上下文,呈现信息页面;

    else部分,首先新建一个关注模型,然后写入被关注者,关注者,再存储这个模型;之后,将对应的exuser的粉丝数+1,然后保存exuser;

    完成所有操作后,重定向到个人信息页面(相当于执行if的代码)。

    def personal(request, username):
        # 这里统一使用用户名(username --> uid)的方式来寻找最终用户,然后对应到他的(1对1)的扩展模型里
        # 在实际生产环境里,如果显示的是昵称,方法类似,nickname=nickname
        # 由于exuser并不是所有的字段都适合用form来呈现,因此需要同时传入两个上下文
        the_exuser = ExUser.objects.get(uid=username)
        form = ExUserForm(instance=the_exuser)
        if_follow = FollowRelation.objects.filter(followed=username, following=request.user.username).exists()
    
        if request.method != 'POST':
            context = {'the_exuser': the_exuser, 'username': username, 'if_follow': if_follow}
            return render(request, 'personal_info.html', context)
    
        else:
            new_follow = FollowRelation()
            new_follow.followed = username
            new_follow.following = request.user.username
            new_follow.save()
            the_exuser = ExUser.objects.get(uid=username)
            the_exuser.fans_count += 1
            the_exuser.save()
    
            return HttpResponseRedirect(reverse('account:personal', args=[username]))
    

      

    【4】看具体的个人信息的模板。

    个人信息分为两部分:基础信息,个人资料。都用the_exuser点出来;

    在之后,先判断进来的这个人,看的是不是自己的个人信息页面,如果是,让他可以编辑;

    如果不是,再判断有没有关注过,如果有,则可以进行取消,如果没有,则可以进行关注。

    最后这里还有一个要点:

    如果一个函数在渲染模板后,还需要从模板那里接收返回操作(post),即便是很简单的内容,也可以放在form里,只是没有具体的值传递,但是可以检测到post,进行其他一些操作;

    如果一个函数仅仅只做一次操作,则通过一个链接指向它即可。读者可以看一下if--else里的两种不一样的写法。 

    {% block content %}
    <div class="left">
    
        {# show user info and edit #}
        <div id="basic">
            <h4>基础信息</h4>
            <table>
                <tr>
                    <td class="label">用户名</td>
                    <td class="value">{{the_exuser.uid}}</td>
                </tr>
    
                <tr>
                    <td class="label">注册时间</td>
                    <td class="value">{{the_exuser.create_time}}</td>
                    <td class="label">最近登录</td>
                    <td class="value">{{the_exuser.last_login_time}}</td>
                </tr>
    
                <tr>
                    <td>粉丝数</td>
                    <td>{{the_exuser.fans_count}}</td>
                </tr>
            </table>
        </div>
    
        <div id="personal">
            <h4>个人资料</h4>
    
            <table>
                    <tr>
                        <td class="label">昵称</td>
                        <td class="value">{{the_exuser.nickname}}</td>
                    </tr>
    
                    <tr>
                        <td class="label">微信号</td>
                        <td class="value">{{the_exuser.wechat_id}}</td>
                    </tr>
    
                    <tr>
                        <td class="label">QQ号</td>
                        <td class="value">{{the_exuser.qq_num}}</td>
                    </tr>
    
                    <tr>
                        <td class="label">电子邮件</td>
                        <td class="value">{{the_exuser.email}}</td>
                    </tr>
    
                    <tr>
                        <td class="label">电话</td>
                        <td class="value">{{the_exuser.tel_num}}</td>
                    </tr>
                </table>
    
            {% if request.user.username == username %}
               <a href="{% url 'account:personal_edit' request.user.username %}"><button>编辑</button></a>
            {% else %}
                {% if if_follow %}
                    <a href="{% url 'account:cancel_follow' username %}"><button>取消关注</button></a>
                {% else %}
                    <form action="{% url 'account:personal' username %}" method="post">
                        {% csrf_token %}
                        <input type="submit" value="关注ta!" />
                    </form>
                {% endif %}
            {% endif %}
        </div>
    
    </div>
    {% endblock content %}
    

      

    【5】编辑个人信息。先看views部分。

    首先,username,是之前那个views函数(def personal)传入模板的,然后再从那个模板把这个值再传到这个函数里,后续还会从这里传入到编辑模板;

    接着是两个要传入上下文的参数,其中的form,通过username --> uid -->exuser --> exuserform获得。

    if部分,显示待编辑的页面。不能编辑的部分通过the_exuser点出来,其他部分,通过modelform显示。

    else部分,保存,然后重定向。

    def personal_edit(request, username):
        the_exuser = ExUser.objects.get(uid=username)
        form = ExUserForm(instance=the_exuser)
        context = {'the_exuser': the_exuser, 'form': form, 'username': username}
        if request.method != 'POST':
            return render(request, 'personal_edit.html', context)
        else:
            form = ExUserForm(instance=the_exuser, data=request.POST)
            if form.is_valid():
                form.save()
                return HttpResponseRedirect(reverse('account:personal', args=[username]))
    

      

    【6】编辑个人信息,模板部分。

    基础信息部分不能被编辑,用点的方式;

    剩余部分,用modelform方式。注意:这里结合使用了form和table。

    {% block content %}
    <div class="left">
    
        {# show user info and edit #}
        <div id="basic">
            <h4>基础信息</h4>
            <table>
                <tr>
                    <td class="label">用户名</td>
                    <td class="value">{{the_exuser.uid}}</td>
                </tr>
    
                <tr>
                    <td class="label">注册时间</td>
                    <td class="value">{{the_exuser.create_time}}</td>
                    <td class="label">最近登录</td>
                    <td class="value">{{the_exuser.last_login_time}}</td>
                </tr>
    
                <tr>
                    <td>粉丝数</td>
                    <td>{{the_exuser.fans_count}}</td>
                </tr>
            </table>
        </div>
    
        <div id="personal">
            <h4>个人资料</h4>
    
                <form action="{% url 'account:personal_edit' request.user.username %}" method="post">
                    {% csrf_token %}
                    <table>
                    <tr>
                        <td class="label">昵称</td>
                        <td class="value">{{form.nickname}}</td>
                    </tr>
    
                    <tr>
                        <td class="label">微信号</td>
                        <td class="value">{{form.wechat_id}}</td>
                    </tr>
    
                    <tr>
                        <td class="label">QQ号</td>
                        <td class="value">{{form.qq_num}}</td>
                    </tr>
    
                    <tr>
                        <td class="label">电子邮件</td>
                        <td class="value">{{form.email}}</td>
                    </tr>
    
                    <tr>
                        <td class="label">电话</td>
                        <td class="value">{{form.tel_num}}</td>
                    </tr>
    
                    </table>
    
                    <input type="submit" value="提交修改" />
    
                </form>
    
        </div>
    
    </div>
    {% endblock content %}
    

      

    【7】取消关注。这里只有一个函数进行操作,然后重定向。

    取消关注的操作是从个人信息页面来的,那边的链接会传来同一个username。通过传来的username和当前的request.user.username,找到对应的关联模型,然后将它删除即可;

    之后再把粉丝数-1,然后把对应的exuser保存;

    最后重定向,重定向仍然要传递同一个username参数。

    强调:这里多次反复传入传出的参数username,是这个要被操作或浏览的个人信息对应的username,而不是当前登录用户!

    def cancel_follow(request, username):
        the_follow = FollowRelation.objects.filter(followed=username, following=request.user.username)
        the_follow.delete()
        the_exuser = ExUser.objects.get(uid=username)
        the_exuser.fans_count -= 1
        the_exuser.save()
        return HttpResponseRedirect(reverse('account:personal', args=[username]))
    

      

    【8】完成了关注和个人信息页面后,下一步,可以做做简单的社交。

  • 相关阅读:
    MYSQL查询优化:profile功能
    MYSQL查询优化:调度和锁定
    SSL/TLS 协议详解
    flash传值给javascript,并在html页面输出
    【图片预加载】
    【minheight】最小高度 IE6、7、FF
    【图片等比缩放】CSS解决
    标签的空链接 href="#" 替换方案
    【实现三角】css的border属性解决方案
    【PNG在IE6下透明】——3种方案
  • 原文地址:https://www.cnblogs.com/lzhshn/p/13664147.html
Copyright © 2020-2023  润新知