基于Django实现特定用户查看特定文件的方案咨询
Hey there! Let's walk through how to build this document access control feature in Django— I’ve implemented similar systems before, so here’s a practical, step-by-step approach that fits your requirements:
First, we need to model our data to link documents with their allowed viewers. We’ll use a Document model for the uploaded files, and a join table (DocumentShare) to track which users have been granted access (this lets us add metadata like share timestamps later if needed):
from django.db import models from django.contrib.auth.models import User class Document(models.Model): title = models.CharField(max_length=255) file = models.FileField(upload_to='documents/') # Stores files in MEDIA_ROOT/documents/ uploader = models.ForeignKey(User, on_delete=models.CASCADE, related_name='uploaded_docs') created_at = models.DateTimeField(auto_now_add=True) # Link to users allowed to view this document (via our join table) allowed_viewers = models.ManyToManyField(User, through='DocumentShare', related_name='accessible_docs') # Helper method to check if a user can access this document def is_accessible_by(self, user): # Uploader always has access if user == self.uploader: return True # Check if the user is in the allowed viewers list return self.allowed_viewers.filter(id=user.id).exists() class DocumentShare(models.Model): document = models.ForeignKey(Document, on_delete=models.CASCADE) user = models.ForeignKey(User, on_delete=models.CASCADE) shared_at = models.DateTimeField(auto_now_add=True) # Optional: Add a permission_type field if you want to support edit access later # permission_type = models.CharField(max_length=20, choices=[('view', 'View'), ('edit', 'Edit')], default='view')
Next, let’s build a view that lets document uploaders share files with specific users (by email or user ID):
from django.shortcuts import get_object_or_404, redirect, render from django.contrib.auth.decorators import login_required from django.http import HttpResponseForbidden from .models import Document, DocumentShare from django.contrib.auth.models import User @login_required def share_document(request, doc_id): document = get_object_or_404(Document, id=doc_id) # Only the uploader can share the document if request.user != document.uploader: return HttpResponseForbidden("You don't have permission to share this document.") if request.method == 'POST': # Get the user to share with (you can use user ID instead of email if preferred) target_email = request.POST.get('user_email') try: target_user = User.objects.get(email=target_email) # Avoid duplicate shares if not DocumentShare.objects.filter(document=document, user=target_user).exists(): DocumentShare.objects.create(document=document, user=target_user) return redirect('document_detail', doc_id=document.id) except User.DoesNotExist: return render(request, 'share_document.html', { 'document': document, 'error': 'User with this email does not exist.' }) return render(request, 'share_document.html', {'document': document})
Now, we need to ensure only authorized users can view document details or download files. Let’s use a class-based detail view as an example:
from django.views.generic import DetailView from django.contrib.auth.mixins import LoginRequiredMixin from django.http import HttpResponseForbidden from .models import Document class DocumentDetailView(LoginRequiredMixin, DetailView): model = Document template_name = 'document_detail.html' context_object_name = 'document' def get_object(self, queryset=None): document = super().get_object(queryset) # Check if the user has access if not document.is_accessible_by(self.request.user): return HttpResponseForbidden("You don't have permission to view this document.") return document
For a function-based view (great for file downloads), it looks like this:
from django.shortcuts import get_object_or_404 from django.contrib.auth.decorators import login_required from django.http import HttpResponseForbidden, FileResponse import os @login_required def download_document(request, doc_id): document = get_object_or_404(Document, id=doc_id) if not document.is_accessible_by(request.user): return HttpResponseForbidden("You don't have permission to download this document.") # Serve the file (ensure MEDIA_URL is configured correctly) file_path = document.file.path if os.path.exists(file_path): return FileResponse(open(file_path, 'rb'), as_attachment=True, filename=document.title) return HttpResponseForbidden("File not found.")
Make sure users only see documents they can access in their list view:
from django.shortcuts import render from django.contrib.auth.decorators import login_required from .models import Document from django.db.models import Q @login_required def document_list(request): # Show documents uploaded by the user OR shared with them accessible_docs = Document.objects.filter( Q(uploader=request.user) | Q(allowed_viewers=request.user) ).distinct() # Avoid duplicates if a user is both uploader and shared with return render(request, 'document_list.html', {'documents': accessible_docs})
- Add Notifications: When a document is shared with a user, send them an email using Django’s
send_mailfunction. - Revoke Access: Build a view to delete
DocumentSharerecords so uploaders can revoke access later. - Permission Levels: Extend the
DocumentSharemodel with apermission_typefield (e.g., 'view' vs 'edit') if you need to support more granular access. - Template Checks: In your templates, only show the "Share" button to the document’s uploader:
{% if user == document.uploader %} <a href="{% url 'share_document' document.id %}" class="btn">Share Document</a> {% endif %}
内容的提问来源于stack exchange,提问作者biagio dipalma

