Django为超级管理员开放所有分支论坛访问权限的实现方案
问题描述
- 已实现支持动态分支分配的讨论论坛网站:普通用户注册时选择所属分支,登录后仅可查看自身所选分支下的帖子,普通用户侧功能运行正常
- 超级管理员账号访问
/forum路径时抛出报错:DoesNotExist at /forum Register matching query does not exist. - 报错根因明确:管理员账号未在
Register模型中关联分支记录,但若给管理员绑定单个分支,会导致管理员仅能查看单分支帖子,无法满足查看全部分支帖子的管理需求
项目核心代码
model.py
Post模型
class Post(models.Model): user1 = models.ForeignKey(User, on_delete=models.CASCADE, default=1) post_id = models.AutoField post_content = models.TextField(max_length=5000,verbose_name="") timestamp= models.DateTimeField(default=now) branch=models.CharField(default='',max_length=200) image = models.ImageField(upload_to="images",default="") def __str__(self): return f'{self.user1} Post'
Reply模型
class Replie(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE, default=1) reply_id = models.AutoField reply_content = models.TextField(max_length=5000,verbose_name="") post = models.ForeignKey(Post, on_delete=models.CASCADE, default='') timestamp= models.DateTimeField(default=now) image = models.ImageField(upload_to="images",default="") def __str__(self): return f'{self.user1} Post'
用户注册关联模型
class Register(models.Model): user = models.ForeignKey(User,on_delete=models.CASCADE) branch= models.CharField(max_length=100) def __str__(self): return self.user.username
view.py
forum视图逻辑(原代码)
def forum(request): user = request.user profile = Profile.objects.all() user = User.objects.get(id=request.user.id) data = Register.objects.get(user = user) user_posts = Post.objects.filter(branch=data.branch).count() if request.method=="POST": user = request.user image = request.user.profile.image content = request.POST.get('content','') branch = request.POST.get('branch','') title = request.POST.get('title','') post = Post(user1=user, post_content=content, image=image,branch=branch,title=title) post.save() messages.success(request, f'Your Question has been posted successfully!!') return redirect('/forum') posts = Post.objects.filter(branch=data.branch).order_by('-timestamp') print(data.branch) context={ 'posts':posts, 'branch':data.branch, 'user_posts':user_posts } return render(request, "forum.html",context)
forum.html
{% if user.is_superuser or user.is_staff %} {% include "instructor/admin_nav.html" %} {% else %} {% include "user/user_nav.html" %} {% endif %} {% block body %} <div class="container my-4 "> <div class="jumbotron"style="margin-bottom: 5%; text-align: center;"> {% if user.is_superuser or user.is_staff %} <h3 class="display-4 font"> Disscussion Forum</h3> <center class="lead post">Welcome to our discussion forum. You can post your question or any related queries by simply clicking on the add post button.</center> <hr class="my-4 hr1"> <p class="post">You can also reply to others post by clicking on add or see reply button.</p> {% else %} <h1 class="font mt-0"> {{branch}} Disscussion Forum</h1> <center >Welcome to discussion forum. You can post your question or any related queries by simply clicking on the add post button.</center> <p>You can also reply to others post by clicking on add or see reply button.</p> <hr class="my-4 h"> <small>keep all posts on the topic. Any posts deemed to be in the wrong category will be removed.</small><br> {% endif %} <button class="btn btn-primary btn-lg text bluebtn" data-target="#questions" data-toggle="modal" role="button">Add Post</button> <form class="form-inline my-2 my-lg-0"> <input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search"> <button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button> </form> </div> {% if user_posts == 0 %} <div class="jumbotron"> <h4 class="display-4">No Results fountd</h4> <p class="lead">Be the first person to ask question</p> </div> {% endif %} {% for post in posts %} <div class="container-fluid mt-10"> <div class="row"> <div class="col-md-12"> <div class="card mb-4 forumcardcss"> <div class="card-header forumcardheader"> <div class="media flex-wrap w-100 align-items-center imgcss"> <img src="/media/{{post.image}}" class="d-block ui-w-40 rounded-circle" alt="profileimage"style="width: 40px;height: 40px;"> <p class="ml-4 usernamecss"> {{post.user1}} </p> <div class="media-body ml-3"> </div> <div class="text-muted small ml-3"> <div class="px-4 pt-3 f" > {{post.timestamp}} </div> </div> {% if user.is_superuser or user.is_staff %} <a href="{% url 'dashboard:delete_post' post.id %}"> <button class="btn btn-danger btn-sm text" onclick="window.mytest()"style="background-color: #e60000;">Delete</button></a> <script type="text/javascript">window.mytest = function() { var isValid = confirm('If you click ok then its delete this post and related reply on it. Are you sure to delete?');if (!isValid) { event.preventDefault(); alert("It wont delete. Yay!");}}</script> {% endif %} </div> </div> <div class="card-body forumcardbody"> <p class="text">{{ post.post_content|linebreaks|truncatewords_html:10 }}</p>{% if post.post_content|length|get_digit:"-1" > 50 %} <a href="/discussion/{{post.id}}" data-abc="true"><button class="btn btn-light text" style="color:blue; font-size: 13px;">Show more </button> </a> {% endif %} </div> </div> </div> </div> </div> {% endfor %} </div> <!-- Modal --> <div class="modal fade" id="questions" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="exampleModalLabel"></h5> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> {% if user.is_authenticated %} <div class="modal-body"> <form action="/forum" method="POST"> {% csrf_token %} <div class="form-group"> <label style="font-size:1rem; font-weight:bold;">Post Your Question Here</label> <textarea class="form-control" id="content" name="content" rows="3"></textarea> </div> </div> {% else %} <h3>Please Login to post</h3> {% endif %} <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button> <button type="submit" class="btn btn-primary">Post</button> </div> </div> </div> </div> </div> {% endblock body %}
urls.py
app_name = "dashboard" urlpatterns = [ path('', views.index, name="index"), path('user_home', views.user_home, name="user_home"), path('admin_home', views.admin_home, name="admin_home"), path("forum", views.forum, name="forum"), path("discussion/<int:myid>", views.discussion, name="discussion"), path("showallusers", views.show_all_users, name="showallusers"), path('delete_user/<int:pk>', views.delete_user, name="delete_user"), path('delete_post/<int:pk>', views.delete_post, name="delete_post"), path('delete_reply/<int:pk>', views.delete_reply, name="delete_reply"), path('upload_notes', views.upload_notes, name='upload_notes'), path('view_mynotes', views.view_mynotes, name='view_mynotes'), path('delete_mynotes/<int:pk>/', views.delete_mynotes, name='delete_mynotes'), path('pending_notes', views.pending_notes, name='pending_notes'), path('assign_status/<int:pk>', views.assign_status, name='assign_status'), path('accepted_notes', views.accepted_notes, name='accepted_notes'), path('rejected_notes', views.rejected_notes, name='rejected_notes'), path('all_notes', views.all_notes, name='all_notes'), path('delete_notes/<int:pk>', views.delete_notes, name='delete_notes'), path('delete-records/', views.delete_notes, name='delete_notes'), path('view_allnotes', views.view_allnotes, name='view_allnotes'), path('notessharing', views.notessharing, name='notessharing'), path('edit_post/<int:pk>/', views.edit_post, name='edit_post'), path('edit_reply/<int:pk>/', views.edit_reply, name='edit_reply'), ]
实现方案
核心思路是在视图层增加用户身份分流逻辑,不需要修改现有模型结构,不需要给管理员账号绑定Register分支记录,完全基于Django自带的超级管理员/职员权限标识做逻辑拆分,改动量最小,不影响现有普通用户功能。
1. 修改forum视图逻辑
替换原有直接查询Register表的逻辑,先判断用户身份,管理员走全量数据查询,普通用户走原有分支过滤逻辑,同时增加异常兜底,避免普通用户未绑定分支时报错。修改后的代码如下:
def forum(request): user = request.user profile = Profile.objects.all() # 标记当前用户是否为管理员 is_admin = user.is_superuser or user.is_staff user_posts = 0 current_branch = "" posts = Post.objects.none() if is_admin: # 管理员逻辑:查询全部分支帖子 posts = Post.objects.all().order_by('-timestamp') user_posts = posts.count() current_branch = "全部分支" else: # 普通用户逻辑:查询所属分支帖子 try: data = Register.objects.get(user=user) current_branch = data.branch posts = Post.objects.filter(branch=current_branch).order_by('-timestamp') user_posts = posts.count() except Register.DoesNotExist: # 普通用户未绑定分支的兜底处理,可替换为自己的分支选择页路径 messages.error(request, "请先绑定所属分支后再访问论坛") return redirect('/user_home') if request.method=="POST": user = request.user image = request.user.profile.image content = request.POST.get('content','') branch = request.POST.get('branch','') title = request.POST.get('title','') # 普通用户发帖强制使用自身所属分支,避免前端参数篡改 if not is_admin: branch = current_branch post = Post(user1=user, post_content=content, image=image,branch=branch,title=title) post.save() messages.success(request, f'Your Question has been posted successfully!!') return redirect('/forum') context={ 'posts':posts, 'branch':current_branch, 'user_posts':user_posts, 'is_admin':is_admin } return render(request, "forum.html",context)
2. 适配模板逻辑
原有模板已经做了管理员导航、普通用户导航的区分,只需要补充两个小适配:
- 在发帖模态框的表单中增加分支选择逻辑:管理员显示分支选择下拉框,普通用户隐藏分支选择,通过隐藏域传递自身分支值,示例代码如下:
<form action="/forum" method="POST"> {% csrf_token %} <div class="form-group"> <label style="font-size:1rem; font-weight:bold;">Post Your Question Here</label> <textarea class="form-control" id="content" name="content" rows="3"></textarea> </div> <!-- 新增分支选择逻辑 --> {% if is_admin %} <div class="form-group"> <label style="font-size:1rem; font-weight:bold;">所属分支</label> <select class="form-control" name="branch" required> <!-- 替换为实际的分支选项,也可从视图传分支列表遍历生成 --> <option value="分支A">分支A</option> <option value="分支B">分支B</option> </select> </div> {% else %} <input type="hidden" name="branch" value="{{branch}}"> {% endif %} </form>
- 可选优化:在帖子卡片的用户名旁增加分支标签,管理员视角下可直接看到每个帖子所属分支,示例代码:
<p class="ml-4 usernamecss"> {{post.user1}} </p> {% if is_admin %} <span class="badge badge-info ml-2">{{post.branch}}</span> {% endif %}
注意事项
项目中其他涉及Register.objects.get(user=user)查询的视图(比如帖子详情页discussion、回复相关逻辑),都需要增加同样的管理员身份判断,避免其他页面抛出相同的DoesNotExist报错。
内容的提问来源于stack exchange,提问作者Ajay
相关产品推荐
相关产品推荐

