如何在django中向所有用户公开主题?

时间:2018-10-11 03:19:59

标签: python django

有问题

我正在创建一个项目,您可以在其中创建主题,该主题对于未经身份验证的用户可以是私有的或公开的。然后,您可以在每个主题中输入多个条目,以应用于该主题。现在,我试图在我的new_topic.html中选中一个复选框,如果选中该复选框,它将计算为True,否则为False 但是如果没有登录我就看不到这个话题

我想要的

我想通过将视图中的公共属性更改为True来向尚未登录的用户显示公共主题,但是我不知道如何实现它们

我尝试过的事情

我玩过查询集topic.public == True 但我不知道该怎么用

代码

我的/learning_logs/modles.py看起来像这样:

from django.db import models
from django.contrib.auth.models import User

class Topic(models.Model):
    """topic은 사용자가 공부하고 있는 주제이다."""
    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

class Entry(models.Model):
    """주제에 관해 공부한 내용"""
    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):
        """모델에 관한 정보를 문자열 형태로 반환한다."""
        if self.text[:] > self.text[:50]:
            return self.text[:50] + "..."
        else:
            return self.text[:]

我的/learning_logs/views.py看起来像这样:

from django.shortcuts import render, get_object_or_404
from django.http import HttpResponseRedirect, Http404
from django.urls import reverse


from .models import Topic, Entry
from .forms import TopicForm, EntryForm
from django.contrib.auth.decorators import login_required


from .models import Topic, Entry
from .forms import TopicForm, EntryForm

def index(request):
    """학습 로그 홈페이지"""
    return render(request, 'learning_logs/index.html')

@login_required
def topics(request):
    """주제를 표시한다."""
    topics = Topic.objects.filter(owner=request.user).order_by('date_added')
    context = {'topics': topics}
    return render(request, 'learning_logs/topics.html', context)

@login_required
def topic(request, topic_id):
    """주제 하나와 연결된 모든 항목을 표시한다."""
    topic = get_object_or_404(Topic, id=topic_id)
    # 주제가 현재 사용자의 것인지 확인한다.
    check_user = check_topic_owner(request, topic)

    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):
    """새 주제 추가"""
    if request.method != 'POST':
        # 들어온 데이터가 없을 때는 새 폼을 만든다.
        form = TopicForm()
    else:
        # POST 데이터를 받아서 처리한다.
        form = TopicForm(request.POST)
        if form.is_valid():
            new_topic = form.save(commit=False)
            new_topic.owner = request.user
            new_topic.save()
            return HttpResponseRedirect(reverse('learning_logs:topics'))

    context = {'form': form}
    return render(request, 'learning_logs/new_topic.html', context)

@login_required
def new_entry(request, topic_id):
    """특정 주제에 관한 새 항목을 추가"""
    topic = get_object_or_404(Topic, id=topic_id)
    check_user = check_topic_owner(request, topic)

    if request.method != 'POST':
        # 전송된 데이터가 없으므로 빈 폼을 만든다.
        form = EntryForm()
    else:
        # 받은 POST 데이터를 처리한다.
        form = EntryForm(data=request.POST)
        if form.is_valid():
            new_entry = form.save(commit=False)
            new_entry.topic = topic
            new_entry.save()
            return HttpResponseRedirect(reverse('learning_logs:topic',
                                        args=[topic_id]))

    context = {'topic':topic, 'form':form}
    return render(request, 'learning_logs/new_entry.html', context)

@login_required
def edit_entry(request, entry_id):
    """기존 항목을 편집한다."""
    entry = get_object_or_404(Entry, id=entry_id)
    topic = entry.topic
    check_user = check_topic_owner(request, topic)

    if request.method != 'POST':
        # 첫 요청이므로 폼을 현재 텍스트로 채운다.
        form = EntryForm(instance=entry)
    else:
        # POST 데이터를 받았으므로 받은 데이터를 처리한다.
        form = EntryForm(instance=entry, data=request.POST)
        return HttpResponseRedirect(reverse('learning_logs:topic',
                                    args=[topic.id]))

    context = {'entry': entry, 'topic':topic, 'form': form}
    return render(request, 'learning_logs/edit_entry.html', context)


def check_topic_owner(request, topic):
    """현재 유저가 올바른 유저인지 체크한다"""
    if topic.owner != request.user:
        raise Http404

我的/learning_logs/forms.py看起来像这样

from django import forms

from .models import Topic, Entry


class TopicForm(forms. ModelForm):
    class Meta:
        model = Topic
        fields = ['text', 'public']
        lavels = {'text' : '', 'public' : 'lavel for public'}

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})}
        labels = {'text':''}
        widgets = {'text': forms.Textarea(attrs={'cols':80})}

我的/learning_logs/templates/learning_logs/new_topic.html

{% extends "learning_logs/base.html" %}
{% load bootstrap3 %}

{% block header %}
  <h2>Add a new topic:</h2>
{% endblock %}

{% block content %}

  <form action="{% url 'learning_logs:new_topic' %}" method='post'
     class="form">

    {% csrf_token %}
    {% bootstrap_form form %}

    <div class="form-check">
      <input type="checkbox" class="form-check-input" value=True id="public" />
      <label class="form-check-label">
        Make it public?
      </label>
    </div>

    {% buttons %}
      <button name="submit" class="btn btn-primary">add topic</button>
    {% endbuttons %}
  </form>

{% endblock %}

另一个错误:

如果我删除@login_required,则会出现以下错误:

Traceback:

File "/mnt/c/Users/heoje/Desktop/linked/choco/lib/python3.6/site-packages/django/core/handlers/exception.py" in inner
  34.             response = get_response(request)

File "/mnt/c/Users/heoje/Desktop/linked/choco/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
  126.                 response = self.process_exception_by_middleware(e, request)

File "/mnt/c/Users/heoje/Desktop/linked/choco/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
  124.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "/mnt/c/Users/heoje/Desktop/linked/learning_log/learning_logs/views.py" in topics
  31.     topics = Topic.objects.filter(owner=request.user).order_by('date_added')

File "/mnt/c/Users/heoje/Desktop/linked/choco/lib/python3.6/site-packages/django/db/models/manager.py" in manager_method
  82.                 return getattr(self.get_queryset(), name)(*args, **kwargs)

File "/mnt/c/Users/heoje/Desktop/linked/choco/lib/python3.6/site-packages/django/db/models/query.py" in filter
  844.         return self._filter_or_exclude(False, *args, **kwargs)

File "/mnt/c/Users/heoje/Desktop/linked/choco/lib/python3.6/site-packages/django/db/models/query.py" in _filter_or_exclude
  862.             clone.query.add_q(Q(*args, **kwargs))

File "/mnt/c/Users/heoje/Desktop/linked/choco/lib/python3.6/site-packages/django/db/models/sql/query.py" in add_q
  1263.         clause, _ = self._add_q(q_object, self.used_aliases)

File "/mnt/c/Users/heoje/Desktop/linked/choco/lib/python3.6/site-packages/django/db/models/sql/query.py" in _add_q
  1287.                     split_subq=split_subq,

File "/mnt/c/Users/heoje/Desktop/linked/choco/lib/python3.6/site-packages/django/db/models/sql/query.py" in build_filter
  1198.             self.check_related_objects(join_info.final_field, value, join_info.opts)

File "/mnt/c/Users/heoje/Desktop/linked/choco/lib/python3.6/site-packages/django/db/models/sql/query.py" in check_related_objects
  1065.                 for v in value:

File "/mnt/c/Users/heoje/Desktop/linked/choco/lib/python3.6/site-packages/django/utils/functional.py" in inner
  214.         return func(self._wrapped, *args)

Exception Type: TypeError at /topics/
Exception Value: 'AnonymousUser' object is not iterable

第二次错误

我使用了以下代码:

# this should really be a method on a custom ModelManager
def _get_topics_for_user(user):
    " returns a queryset of topics the user can access "
    q = Q(public=True)
    # if django < 1.10 you want "user.is_authenticated()" (with parens)
    if user.is_authenticated:
       # adds user's own private topics to the query
       q = q | Q(private=True, owner=user)

    return Topic.objects.filter(q)


def topics(request):
    topics = _get_topics_for_user(request.user).order_by('date_added')
    context = {'topics': topics}
    return render(request, 'learning_logs/topics.html', context)

def topic(request, topic_id):
    topics = _get_topics_for_user(request.user)
    # here we're passing the filtered queryset, so
    # if the topic "topic_id" is private and the user is either
    # anonymous or not the topic owner, it will raise a 404
    topic = get_object_or_404(topics, id=topic_id)
    entries = topic.entry_set.order_by('-date_added')
    context = {'topic': topic, 'entries': entries}
    return render(request, 'learning_logs/topic.html', context)

Traceback:

File "/mnt/c/Users/heoje/Desktop/linked/choco/lib/python3.6/site-packages/django/core/handlers/exception.py" in inner
  34.             response = get_response(request)

File "/mnt/c/Users/heoje/Desktop/linked/choco/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
  126.                 response = self.process_exception_by_middleware(e, request)

File "/mnt/c/Users/heoje/Desktop/linked/choco/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
  124.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "/mnt/c/Users/heoje/Desktop/linked/learning_log/learning_logs/views.py" in topics
  31.     topics = _get_topics_for_user(request.user).order_by('date_added')

File "/mnt/c/Users/heoje/Desktop/linked/learning_log/learning_logs/views.py" in _get_topics_for_user
  27.     return Topic.objects.filter(q)

File "/mnt/c/Users/heoje/Desktop/linked/choco/lib/python3.6/site-packages/django/db/models/manager.py" in manager_method
  82.                 return getattr(self.get_queryset(), name)(*args, **kwargs)

File "/mnt/c/Users/heoje/Desktop/linked/choco/lib/python3.6/site-packages/django/db/models/query.py" in filter
  844.         return self._filter_or_exclude(False, *args, **kwargs)

File "/mnt/c/Users/heoje/Desktop/linked/choco/lib/python3.6/site-packages/django/db/models/query.py" in _filter_or_exclude
  862.             clone.query.add_q(Q(*args, **kwargs))

File "/mnt/c/Users/heoje/Desktop/linked/choco/lib/python3.6/site-packages/django/db/models/sql/query.py" in add_q
  1263.         clause, _ = self._add_q(q_object, self.used_aliases)

File "/mnt/c/Users/heoje/Desktop/linked/choco/lib/python3.6/site-packages/django/db/models/sql/query.py" in _add_q
  1281.                     current_negated, allow_joins, split_subq)

File "/mnt/c/Users/heoje/Desktop/linked/choco/lib/python3.6/site-packages/django/db/models/sql/query.py" in _add_q
  1281.                     current_negated, allow_joins, split_subq)

File "/mnt/c/Users/heoje/Desktop/linked/choco/lib/python3.6/site-packages/django/db/models/sql/query.py" in _add_q
  1287.                     split_subq=split_subq,

File "/mnt/c/Users/heoje/Desktop/linked/choco/lib/python3.6/site-packages/django/db/models/sql/query.py" in build_filter
  1164.         lookups, parts, reffed_expression = self.solve_lookup_type(arg)

File "/mnt/c/Users/heoje/Desktop/linked/choco/lib/python3.6/site-packages/django/db/models/sql/query.py" in solve_lookup_type
  1028.         _, field, _, lookup_parts = self.names_to_path(lookup_splitted, self.get_meta())

File "/mnt/c/Users/heoje/Desktop/linked/choco/lib/python3.6/site-packages/django/db/models/sql/query.py" in names_to_path
  1389.                                      "Choices are: %s" % (name, ", ".join(available)))

Exception Type: FieldError at /topics/
Exception Value: Cannot resolve keyword 'private' into field. Choices are: date_added, entry, id, owner, owner_id, public, text

2 个答案:

答案 0 :(得分:0)

请勿使用login_required装饰器,将要公开访问的视图上方的行@login_required删除。

login_required装饰器用于确保只有经过身份验证的用户才能访问视图。

仅当您希望视图由已认证用户使用时才使用。

您会收到此错误,因为在Topic.objects.filter(owner=request.user)行中,request.userAnonymousUser

如果仅当主题公开时才进行渲染,则可以使用topic.public对其进行检查,如果它返回true或false,则代码可能类似于-

def topic(request, topic_id):
    """주제 하나와 연결된 모든 항목을 표시한다."""
    topic = get_object_or_404(Topic, id=topic_id)
    # 주제가 현재 사용자의 것인지 확인한다.
    if topic.public:   
        check_user = check_topic_owner(request, topic)
        entries = topic.entry_set.order_by('-date_added')
        context = {'topic': topic, 'entries': entries}
        return render(request, 'learning_logs/topic.html', context)
    else:
        return HttpResponseRedirect(reverse('access_dennined'))

根据需要使用@login_required

答案 1 :(得分:0)

首先,您必须从login_requiredtopics视图中删除topic装饰器,显然-顾名思义,该装饰器的目标是强制用户登录

然后,您必须更改视图代码以处理两种情况-匿名用户和登录用户。假设您希望每个人都可以看到公共主题,而只有主题所有者可以访问私有主题,则如下所示:

from django.db.models import Q

# this should really be a method on a custom ModelManager
def _get_topics_for_user(user):
    " returns a queryset of topics the user can access "
    q = Q(public=True)
    # if django < 1.10 you want "user.is_authenticated()" (with parens)
    if user.is_authenticated:
       # adds user's own private topics to the query
       q = q | Q(public=False, owner=user)

    return Topic.objects.filter(q)


def topics(request):
    topics = _get_topics_for_user(request.user).order_by('date_added')
    context = {'topics': topics}
    return render(request, 'learning_logs/topics.html', context)

def topic(request, topic_id):
    topics = _get_topics_for_user(request.user)
    # here we're passing the filtered queryset, so
    # if the topic "topic_id" is private and the user is either
    # anonymous or not the topic owner, it will raise a 404 
    topic = get_object_or_404(topics, id=topic_id)
    entries = topic.entry_set.order_by('-date_added')
    context = {'topic': topic, 'entries': entries}
    return render(request, 'learning_logs/topic.html', context)