Tango with Django - 第 8 章 - 练习

Posted

技术标签:

【中文标题】Tango with Django - 第 8 章 - 练习【英文标题】:Tango with Django - Chapter 8 - Exercise 【发布时间】:2015-04-06 23:43:46 【问题描述】:

我需要一些帮助才能使 add_page 函数正常工作。我对 html 非常陌生,甚至对 Django 也很陌生。我正在编写的章节可以在这里找到:http://www.tangowithdjango.com/book17/chapters/forms.html。目前我的相关文件如下所示:

Forms.py

from django import forms
from rango.models import Page, Category

class CategoryForm(forms.ModelForm):
    name = forms.CharField(max_length=128, help_text="Please enter the category name.")
    views = forms.IntegerField(widget=forms.HiddenInput(), initial=0)
    likes = forms.IntegerField(widget=forms.HiddenInput(), initial=0)
    slug = forms.CharField(widget=forms.HiddenInput(), required=False)

    # An inline class to provide additional information on the form.
    class Meta:
        # Provide an association between the ModelForm and a model
        model = Category
        fields = ('name',)


class PageForm(forms.ModelForm):
    title = forms.CharField(max_length=128, help_text="Please enter the title of the page.")
    url = forms.URLField(max_length=200, help_text="Please enter the URL of the page.")
    views = forms.IntegerField(widget=forms.HiddenInput(), initial=0)

    class Meta:
        # Provide an association between the ModelForm and a model
        model = Page

        # What fields do we want to include in our form?
        # This way we don't need every field in the model present.
        # Some fields may allow NULL values, so we may not want to include them...
        # Here, we are hiding the foreign key.
        # we can either exclude the category field from the form,
        exclude = ('category',)
        #or specify the fields to include (i.e. not include the category field)
        #fields = ('title', 'url', 'views')

    def clean(self):
        cleaned_data = self.cleaned_data
        url = cleaned_data.get('url')

        # If url is not empty and doesn't start with 'http://', prepend 'http://'.
        if url and not url.startswith('http://'):
            url = 'http://' + url
            cleaned_data['url'] = url

        return cleaned_data

Views.py:

from django.shortcuts import render
from django.http import HttpResponse
from rango.models import Category, Page
from rango.forms import CategoryForm, PageForm

def index(request):
    # Query the database for a list of ALL categories currently stored.
    # Order the categories by no. likes in descending order.
    # Retrieve the top 5 only - or all if less than 5.
    # Place the list in our context_dict dictionary which will be passed to the template engine.
    category_list = Category.objects.order_by('-likes')[:5]
    page_list = Page.objects.order_by('-view')[:5]
    context_dict = 'categories': category_list,
                    'pages': page_list

    # Render the response and send it back!
    return render(request, 'rango/index.html', context_dict)

def category(request, category_name_slug):

    # Create a context dictionary which we can pass to the template rendering engine.
    context_dict = 

    try:
        # Can we find a category name slug with the given name?
        # If we can't, the .get() method raises a DoesNotExist exception.
        # So the .get() method returns one model instance or raises an exception.
        category = Category.objects.get(slug=category_name_slug)
        context_dict['category_name'] = category.name
        context_dict['category_name_slug'] = category_name_slug

        # Retrieve all of the associated pages.
        # Note that filter returns >= 1 model instance.
        pages = Page.objects.filter(category=category)

        # Adds our results list to the template context under name pages.
        context_dict['pages'] = pages
        # We also add the category object from the database to the context dictionary.
        # We'll use this in the template to verify that the category exists.
        context_dict['category'] = category
    except Category.DoesNotExist:
        # We get here if we didn't find the specified category.
        # Don't do anything - the template displays the "no category" message for us.
        pass

    # Go render the response and return it to the client.
    print context_dict
    return render(request, 'rango/category.html', context_dict)

def add_category(request):
    # A HTTP POST?
    if request.method == 'POST':
        form = CategoryForm(request.POST)

        # Have we been provided with a valid form?
        if form.is_valid():
            # Save the new category to the database.
            form.save(commit=True)

            # Now call the index() view.
            # The user will be shown the homepage.
            return index(request)
        else:
            # The supplied form contained errors - just print them to the terminal.
            print form.errors
    else:
        # If the request was not a POST, display the form to enter details.
        form = CategoryForm()

    # Bad form (or form details), no form supplied...
    # Render the form with error messages (if any).
    return render(request, 'rango/add_category.html', 'form': form)

def add_page(request, category_name_slug):

    try:
        cat = Category.objects.get(slug=category_name_slug)
    except Category.DoesNotExist:
                cat = None

    if request.method == 'POST':
        form = PageForm(request.POST)
        if form.is_valid():
            if cat:
                page = form.save(commit=False)
                page.category = cat
                page.views = 0
                page.save()
                # probably better to use a redirect here.
                return category(request, category_name_slug)
        else:
            print form.errors
    else:
        form = PageForm()

    context_dict = 'form':form, 'category': cat

    return render(request, 'rango/add_page.html', context_dict)

urls.py

from django.conf.urls import patterns, url
from rango import views

urlpatterns = patterns('',
        url(r'^$', views.index, name='index'),
#        url(r'^about/$', views.about, name='about'),
        url(r'^add_category/$', views.add_category, name='add_category'), 
        url(r'^category/(?P<category_name_slug>[\w\-]+)/add_page/$', views.add_page, name='add_page'),
        url(r'^category/(?P<category_name_slug>[\w\-]+)/$', views.category, name='category'),)

我认为这个 ^ 是我遇到问题的地方。我设法进入“添加页面”屏幕,但是当我尝试提交某些内容时,我收到一条错误消息,指出我只提供 1 个参数并且 add_page() 需要 2 个。我想我可能需要一个额外的 url类似于“add_category” URL,但这一定意味着其他 URL 指向错误的地方?

category.html

<!DOCTYPE html>
<html>
    <head>
        <title>Rango</title>
    </head>

    <body>
        <h1> category_name </h1>
        % if category %
            % if pages %
            <ul>
                % for page in pages %
                <li><a href=" page.url "> page.title </a></li>
                % endfor %
            </ul>

            % else %
                <strong>No pages currently in category.</strong>
            % endif %
            <li><a href="/rango/category/ category_name_slug /add_page/">Add a New Page</a></li>
        % else %
            The specified category  category_name  does not exist!
        % endif %
    </body>
</html>

add_page.html:

<!DOCTYPE html>
<html>
    <head>
        <title>Rango</title>
    </head>

    <body>
        <h1>Add a Page</h1>

        <form id="page_form" method="post" action="/rango/add_page/">

            % csrf_token %
            % for hidden in form.hidden_fields %
                 hidden 
            % endfor %

            % for field in form.visible_fields %
                 field.errors 
                 field.help_text 
                 field 
            % endfor %

            <input type="submit" name="submit" value="Create Page" />
        </form>
    </body>

</html>

【问题讨论】:

请把add_page.html模板贴出来,去掉不相关的category.html和除add_page之外的所有视图。 我认为 category.html 是相关的,因为我对其进行了更改。我添加了 add_page.html 您已经将表单发布到 /rango/add_page/,而不是 /category/whatever/add_page/,因此您必须有另一个 urls.py 条目来响应它:在哪里?可以发一下吗? 我明白这一点。我不明白的是我希望该网址将我带到哪里。我是否应该告诉按钮将我带到 /category/whatever/add_page/ 就像他们在下面的答案中暗示的那样?那不只会让我绕个圈子吗? 不,因为如果你 POST 到它,你的视图会做一些不同的事情:它处理表单并创建一个新页面。 【参考方案1】:

我编辑了 add_page 函数以包含 category_name_slug:

def add_page(request, category_name_slug):

    try:
        cat = Category.objects.get(slug=category_name_slug)
    except Category.DoesNotExist:
                cat = None

    if request.method == 'POST':
        form = PageForm(request.POST)
        if form.is_valid():
            if cat:
                page = form.save(commit=False)
                page.category = cat
                page.views = 0
                page.save()
                # probably better to use a redirect here.
                return category(request, category_name_slug)
        else:
            print form.errors
    else:
        form = PageForm()

    # made the change here
    context_dict = 'form':form, 'category': cat, 'category_name_slug': category_name_slug

    return render(request, 'rango/add_page.html', context_dict)

然后我将 add_page.html 编辑为如下所示:

<!DOCTYPE html>
<html>
    <head>
        <title>Rango</title>
    </head>

    <body>
        <h1>Add a Page</h1>

        <form id="page_form" method="post" action="/rango/category/ category_name_slug /add_page/">

            % csrf_token %
            % for hidden in form.hidden_fields %
                 hidden 
            % endfor %

            % for field in form.visible_fields %
                 field.errors 
                 field.help_text 
                 field 
            % endfor %

            <input type="submit" name="submit" value="Create Page" />
        </form>
    </body>

</html>

【讨论】:

感谢分享。 add_page.html模板的修改不是那么明显。【参考方案2】:

如果你不想编辑你的views.py

随便做

<!DOCTYPE html>
<html>
    <head>
        <title>Rango</title>
    </head>

    <body>
        <h1>Add a Page</h1>

        <form id="page_form" method="post" action="/rango/category/ category /add_page/">

            % csrf_token %
            % for hidden in form.hidden_fields %
                 hidden 
            % endfor %

            % for field in form.visible_fields %
                 field.errors 
                 field.help_text 
                 field 
            % endfor %

            <input type="submit" name="submit" value="Create Page" />
        </form>
    </body>

</html>

但我有问题,它仍然无法保存在数据库中。

【讨论】:

以上是关于Tango with Django - 第 8 章 - 练习的主要内容,如果未能解决你的问题,请参考以下文章

翻译How To Tango With Django 1.5.4 第一章

tango with django(第三章 Django基础)

翻译How To Tango With Django 1.5.4 第三章

翻译How To Tango With Django 1.5.4 第五章

Django第8章: 多级评论树

How to Find and Write VAG 7th Byte CS with Tango Key Programmer