Python 第8章-添加页面问题
我目前正在学习Django探戈教程,完成第8章: 最后一个问题是add_页面表单处理的url不是以“http://”开头的,我不太清楚为什么。实际的web应用程序不会出现错误,如果我没有将“请输入URL”工具提示窗口包含在URL中,我只需获取该窗口,并在我自己添加“http://”后正确处理 这些是我的文件:Python 第8章-添加页面问题,python,django,Python,Django,我目前正在学习Django探戈教程,完成第8章: 最后一个问题是add_页面表单处理的url不是以“http://”开头的,我不太清楚为什么。实际的web应用程序不会出现错误,如果我没有将“请输入URL”工具提示窗口包含在URL中,我只需获取该窗口,并在我自己添加“http://”后正确处理 这些是我的文件: #VIEWS.PY from django.http import HttpResponse from django.shortcuts import render from rang
#VIEWS.PY
from django.http import HttpResponse
from django.shortcuts import render
from rango.models import Category
from rango.models import Page
from rango.forms import CategoryForm
from rango.forms import 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 and dictionary which will be passed to the template engine.
category_list = Category.objects.order_by('-likes')[:5]
page_list = Page.objects.order_by('-views')[: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 about(request):
context_dict = {'italicmessage': "I am italicised font from the context"}
return render(request, 'rango/about.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
# Retrieve all 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
context_dict['category_name_slug'] = category_name_slug
except Category.DoesNotExist:
# We get here if we didn't find the specified category.
# Don't do anything - the template displayes the "no category message for us."
pass
# Go render the response and return it to the client.
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()
return category(request, category_name_slug)
else:
form = PageForm()
context_dict = {'form': form, 'category': cat, 'category_name_slug': category_name_slug}
return render(request, 'rango/add_page.html', context_dict)
而且
# 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:
model = Page
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
我怀疑这与forms.py中的PageForm类有关,但我似乎刚刚复制了教程中所示的代码
提前感谢您的帮助 快速查看一下Django源代码,就会发现为什么会发生这种情况: 在core/validators.py中
class URLField(CharField):
default_validators = [validators.URLValidator()]
description = _("URL")
您可以看到URLField
的默认验证器是urlvalidater
,它可以在core/validators.py中找到:
@deconstructible
class URLValidator(RegexValidator):
regex = re.compile(
r'^(?:[a-z0-9\.\-]*)://' # scheme is validated separately
r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}(?<!-)\.?)|' # domain...
r'localhost|' # localhost...
r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|' # ...or ipv4
r'\[?[A-F0-9]*:[A-F0-9:]+\]?)' # ...or ipv6
r'(?::\d+)?' # optional port
r'(?:/?|[/?]\S+)$', re.IGNORECASE)
message = _('Enter a valid URL.')
schemes = ['http', 'https', 'ftp', 'ftps']
def __init__(self, schemes=None, **kwargs):
super(URLValidator, self).__init__(**kwargs)
if schemes is not None:
self.schemes = schemes
def __call__(self, value):
value = force_text(value)
# Check first if the scheme is valid
scheme = value.split('://')[0].lower()
if scheme not in self.schemes:
raise ValidationError(self.message, code=self.code)
# Then check full URL
try:
super(URLValidator, self).__call__(value)
except ValidationError as e:
# Trivial case failed. Try for possible IDN domain
if value:
scheme, netloc, path, query, fragment = urlsplit(value)
try:
netloc = netloc.encode('idna').decode('ascii') # IDN -> ACE
except UnicodeError: # invalid domain part
raise e
url = urlunsplit((scheme, netloc, path, query, fragment))
super(URLValidator, self).__call__(url)
else:
raise
else:
url = value
@deconstructable
类URLValidator(RegexValidator):
regex=re.compile(
r'^(?[a-z0-9\.\-]*):/'#方案单独验证
r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\+(?:[A-Z]{2,6}.?;[A-Z0-9-]{2,}(?u调用
它用方案=值分割提供的输入。分割('://')[0]。下()
获取前缀。如果不想使用此前缀,最好是创建自己的自定义验证。您可能需要阅读:以了解更多信息。快速查看Django源代码,了解发生这种情况的原因:
在core/validators.py中
class URLField(CharField):
default_validators = [validators.URLValidator()]
description = _("URL")
您可以看到URLField
的默认验证器是urlvalidater
,它可以在core/validators.py中找到:
@deconstructible
class URLValidator(RegexValidator):
regex = re.compile(
r'^(?:[a-z0-9\.\-]*)://' # scheme is validated separately
r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}(?<!-)\.?)|' # domain...
r'localhost|' # localhost...
r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}|' # ...or ipv4
r'\[?[A-F0-9]*:[A-F0-9:]+\]?)' # ...or ipv6
r'(?::\d+)?' # optional port
r'(?:/?|[/?]\S+)$', re.IGNORECASE)
message = _('Enter a valid URL.')
schemes = ['http', 'https', 'ftp', 'ftps']
def __init__(self, schemes=None, **kwargs):
super(URLValidator, self).__init__(**kwargs)
if schemes is not None:
self.schemes = schemes
def __call__(self, value):
value = force_text(value)
# Check first if the scheme is valid
scheme = value.split('://')[0].lower()
if scheme not in self.schemes:
raise ValidationError(self.message, code=self.code)
# Then check full URL
try:
super(URLValidator, self).__call__(value)
except ValidationError as e:
# Trivial case failed. Try for possible IDN domain
if value:
scheme, netloc, path, query, fragment = urlsplit(value)
try:
netloc = netloc.encode('idna').decode('ascii') # IDN -> ACE
except UnicodeError: # invalid domain part
raise e
url = urlunsplit((scheme, netloc, path, query, fragment))
super(URLValidator, self).__call__(url)
else:
raise
else:
url = value
@deconstructable
类URLValidator(RegexValidator):
regex=re.compile(
r'^(?[a-z0-9\.\-]*):/'#方案单独验证
r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\+(?:[A-Z]{2,6}.?;[A-Z0-9-]{2,}(?u调用
它用方案=值分割提供的输入。分割('://')[0]。下()
获取前缀。如果您不想使用此前缀,最好是创建自己的自定义验证。您可能需要阅读:了解更多信息。URL字段使用URLValidator
进行验证。
来源:
scheme = value.split('://')[0].lower()
if scheme not in self.schemes:
raise ValidationError(self.message, code=self.code)
默认情况下:
schemes = ['http', 'https', 'ftp', 'ftps']
所以很明显,只允许绝对URL
另请参见。URLField使用
URLValidator
进行验证。
来源:
scheme = value.split('://')[0].lower()
if scheme not in self.schemes:
raise ValidationError(self.message, code=self.code)
默认情况下:
schemes = ['http', 'https', 'ftp', 'ftps']
所以很明显,只允许绝对URL
另请参见。这是因为您使用的是url表单字段……如果您希望在不使用http://的情况下传递url,则可以使用普通的字符表单字段 URL字段后面是一个验证,当您想要使用URL字段时,可以更改该验证
希望这对您有所帮助,因为您使用的是url表单字段……如果您希望在不使用http://的情况下传递url,那么您可以使用普通的字符表单字段 URL字段后面是一个验证,当您想要使用URL字段时,可以更改该验证
希望这能有所帮助感谢您的回复Se shuttle87-那么您是否建议此url验证代码不起任何作用?我不太明白,如果它实际上不起作用,为什么他们会将其包含在教程中。我又来不及了;)-与主题相关:@ch3ka,事实上,我正打算更新你的答案,只是因为与此相关的票证链接,但我看到你删除了它。@shuttle87取消了删除,因为你认为它是相关的。感谢你的回复。shuttle87-那么你是在建议url验证的代码没有任何作用吗?我不太明白他们为什么会这么做如果这样做行不通,请将其包含在教程中。我又迟到了;)-与主题相关:@ch3ka,事实上,我正打算更新你的答案,只是因为这张罚单的链接,但我看到你删除了它。@shuttle87取消了删除,因为你认为它是相关的。好吧,这就是我要做的来解决这个问题-谢谢!好吧,这就是我要做的来解决这个问题-谢谢!