在 Django 中向所有用户公开主题
Posted
技术标签:
【中文标题】在 Django 中向所有用户公开主题【英文标题】:Making a topic public to all users in Django 【发布时间】:2020-09-24 22:58:45 【问题描述】:我有一个项目,用户可以在其中输入主题并选择将主题设为公开或私有。我希望所有人都可以看到所有公共主题,并且只有该主题的所有者才能看到私有主题(项目来自 Python 速成课程练习 20-5)。 当我点击我的项目时,我没有收到任何错误,但是当我创建一个新主题并选择“公开”选项时,它仍然没有显示给公众查看。
我研究过类似的问题,并按照这里的所有建议 How to make a topic public to all users in django? 和这里 Django - How to make the topics, that you create public? Learning Log Project 没有运气。
我猜我的查询集没有正确呈现数据?我也阅读了有关查询集的 Django 文档,但我尝试过的任何方法都没有奏效。我对编程真的很陌生,所以任何帮助都将不胜感激。谢谢!
这是我的models.py
:
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Topic(models.Model):
"""A topic the user is learning about"""
text = models.CharField(max_length=200)
date_added = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
public = models.BooleanField(default=False)
def __str__(self):
"""Return a string representation of the model"""
return self.text
class Entry(models.Model):
"""Something specific learned about a topic"""
topic = models.ForeignKey(Topic, on_delete=models.CASCADE)
text = models.TextField()
date_added = models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name_plural = 'entries'
def __str__(self):
"""Retrun a string representation of the model"""
if len(self.text) < 50:
return f"self.text"
else:
return f"self.text[:50]..."
views.py
:
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.http import Http404
from .models import Topic, Entry
from .forms import TopicForm, EntryForm
# Create your views here.
def index(request):
"""The home page for Learning Log"""
return render(request, 'learning_logs/index.html')
#Checks whether logged in user has access to topic
def check_topic_owner(request, topic):
if topic.owner != request.user:
raise Http404
def topics(request):
"""Shows all topics"""
#Gets public topics
public_topics = Topic.objects.filter(public=True).order_by('date_added')
#Gets private topics
if request.user.is_authenticated:
private_topics = Topic.objects.filter(owner=request.user).order_by('date_added')
topics = public_topics | private_topics
else:
topics = public_topics
context = 'topics': topics
return render(request, 'learning_logs/topics.html', context)
def topic(request, topic_id):
"""Show a single topic and all its entries"""
topic = get_object_or_404(Topic, id=topic_id)
entries = topic.entry_set.order_by('-date_added')
context = 'topic': topic, 'entries': entries
return render(request, 'learning_logs/topic.html', context)
@login_required
def new_topic(request):
"""Add a new topic"""
if request.method != 'POST':
#No data submitted; create a blank form.
form = TopicForm()
else:
#POST data submitted; process data
form = TopicForm(data=request.POST)
if form.is_valid():
new_topic = form.save(commit=False)
new_topic.owner = request.user
new_topic.save()
return redirect('learning_logs:topics')
#Display a blank or invalid form
context = 'form': form
return render(request, 'learning_logs/new_topic.html', context)
@login_required
def new_entry(request, topic_id):
"""Add a new entry for a particular topic"""
topic = get_object_or_404(Topic, id=topic_id)
check_topic_owner(request, topic)
if request.method != 'POST':
#No data submitted, create a blank form
form = EntryForm()
else:
#POST data submitted; process data
form = EntryForm(data=request.POST)
if form.is_valid():
new_entry = form.save(commit=False)
new_entry.topic = topic
if new_entry.topic.owner == request.user:
new_entry.save()
else:
return Http404
return redirect('learning_logs:topic', topic_id=topic_id)
#Display a blank or invalid form
context = 'topic': topic, 'form': form
return render(request, 'learning_logs/new_entry.html', context)
@login_required
def edit_entry(request, entry_id):
"""Edit an existing entry"""
entry = get_object_or_404(Entry, id=entry_id)
topic = entry.topic
check_topic_owner(request, topic)
if request.method != 'POST':
#Initial request; prefill with the current entry
form = EntryForm(instance=entry)
else:
#POST data submitted; process data
form = EntryForm(instance=entry, data=request.POST)
if form.is_valid():
form.save()
return redirect('learning_logs:topic', topic_id=topic.id)
context = 'entry': entry, 'topic': topic, 'form': form
return render(request, 'learning_logs/edit_entry.html', context)
new_topic.html
:
% load bootstrap4 %
% block page_header %
<h3>Add a new topic:</h3>
% endblock page_header %
% block content %
<form method="post" action="% url 'learning_logs:new_topic' %" class="form">
% csrf_token %
% bootstrap_form form %
<div class="form-check">
<input class="form-check-input" type="checkbox" value=True id="public" />
<label class="form-check-label" for="public">
<p>Make post public?<p/>
</label>
</div>
% buttons %
<button name="submit" class="btn btn-primary">Add topic</button>
% endbuttons %
</form>
% endblock content %
还有forms.py
:
from .models import Topic, Entry
class TopicForm(forms.ModelForm):
class Meta:
model = Topic
fields = ['text']
labels = 'text': ''
class EntryForm(forms.ModelForm):
class Meta:
model = Entry
fields = ['text']
labels = 'text': ''
widgets = 'text': forms.Textarea(attrs='cols': 80)
还有topics.html
:
% block page_header %
<h1>Topics</h1>
% endblock page_header %
% block content %
<ul>
% for topic in topics %
<li><h4>
<a href="%url 'learning_logs:topic' topic.id %"> topic </a>
</h4></li>
% empty %
<li><h4>No topics have been added yet.</h4></li>
% endfor %
</ul>
<h4><a href="% url 'learning_logs:new_topic' %">Add a new topic</a></h4>
% endblock content %
编辑:
在 hasnain095 的帮助下,我现在已经让项目按预期工作了。这是我更新的new_topic.html
。我仍然不明白复选框是如何生成的,因为我已经删除了我认为专门生成它的 html,但由于它仍在工作,我很满意。
% extends "learning_logs/base.html" %
% load bootstrap4 %
% block page_header %
<h3>Add a new topic:</h3>
% endblock page_header %
% block content %
<form method="post" action="% url 'learning_logs:new_topic' %" class="form">
% csrf_token %
% bootstrap_form form %
% buttons %
<button name="submit" class="btn btn-primary">Add topic</button>
% endbuttons %
</form>
% endblock content %
【问题讨论】:
能否提供topics.html
好的,刚刚做了。谢谢!
您在两次查询之间执行了|
,但只能通过Q
操作完成
【参考方案1】:
我认为问题在于您只在主题表单中指定了“文本”字段:
class TopicForm(forms.ModelForm):
class Meta:
model = Topic
fields = ['text']
labels = 'text': ''
但是在new_topic.html文件中,你只有一个复选框输入,没有地方输入文本
<div class="form-check">
<input class="form-check-input" type="checkbox" value=True id="public" />
<label class="form-check-label" for="public">
<p>Make post public?<p/>
</label>
</div>
% buttons %
<button name="submit" class="btn btn-primary">Add topic</button>
% endbuttons %
您的“将帖子公开?”复选框正在映射到您的主题的“文本”字段。
解决方法:
class TopicForm(forms.ModelForm):
class Meta:
model = Topic
fields = ['text', 'public']
labels = 'text': ''
和
<div class="form-check">
<input class="form-check-input" type="checkbox" value=True id="public" />
<label class="form-check-label" for="public">
<p>Make post public?<p/>
</label>
<input class="form-input" type="input" value=True id="text1" />
<label class="form-label" for="text1">
<p>Text<p/>
</label>
</div>
【讨论】:
将“公共”标签添加到我的 TopicForm 类中的字段就可以了!我实际上需要完全删除整个 div 类,因为这会创建额外的复选框。我有由 我没有使用过 Django 模板,所以我也不确定。很高兴我能帮上忙。【参考方案2】:使用联合添加到查询集:
def topics(request):
"""Shows all topics"""
# Gets public topics (renamed to topic_set to not shadow function name)
topic_set = Topic.objects.filter(public=True).order_by('date_added')
# Add private topics, if any. We save some work by not including the public
# topics.
if request.user.is_authenticated:
topic_set = topic_set.union(
Topic.objects.filter(public=False, owner=request.user)
)
context = 'topics': topic_set
return render(request, 'learning_logs/topics.html', context)
旁注:为您过滤的字段添加索引:
class Topic(models.Model):
"""A topic the user is learning about"""
text = models.CharField(max_length=200)
date_added = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
public = models.BooleanField(default=False, db_index=True)
def __str__(self):
"""Return a string representation of the model"""
return self.text
【讨论】:
现在这隐藏了我所有的主题,即使是以前由用户拥有的可见的主题。【参考方案3】:使用 union 将私有主题附加到公共主题后,它对我有用,但可能有一些不同。下面列出来,希望对您有所帮助: 视图.py
def check_topic_owner(topic, request):
if not topic.public:
if topic.owner != request.user:
raise Http404
def topics(request):
#Gets public topics
public_topics = Topic.objects.filter(public=True)
#Gets private topics and append the public topic
if request.user.is_authenticated:
private_topics = Topic.objects.filter(owner=request.user)
topics = public_topics.union(private_topics).order_by('date_added')
else:
topics = public_topics
context = 'topics': topics
return render(request, 'learning_logs/topics.html', context)
models.py
class Topic(models.Model):
text = models.CharField(max_length=200)
date_added = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
public = models.BooleanField(default=False)
def __str__(self):
return self.text
【讨论】:
以上是关于在 Django 中向所有用户公开主题的主要内容,如果未能解决你的问题,请参考以下文章
Django 1.4 - 在元字段 Model=User 的表单中向用户字段添加自定义错误消息