Django-MPTT如何生成子页面的完整路径?

9
我开始使用Django-MPTT应用程序来使我的Django站点页面基于树形结构进行排列。
例如,我有带子页面的页面:
Trance:
- Vocal Trance(子页面) - Hard Trance(子页面)
Breaks:
- Atmo Breaks(子页面) - Progressive Breaks(子页面)
我该如何从urls.py中访问它们? 哪种模式会有所帮助? 我需要在模型中存储Full_path还是可以通过url模式完成?
4个回答

10

我假设你的意思是你想要像这样的URL:

/trance/
/trance/vocal-trance/
/trance/hard-trace/
/breaks/
/breaks/atmo-breaks/
/breaks/progressive-breaks/
如果是这样的话,最好将URL片段存储在您的模型中。可以像这样:
from mptt.models import MPTTModel
from django.db import models
from django.template.defaultfilters import slugify

class Page(MPTTModel):
    name = models.CharField(max_length=50)
    slug = models.CharField(max_length=50,null=True)
    url = models.CharField(max_length=255,null=True)

    def save(self, *args, **kwargs)
        if self.slug is None:
            # create a slug that's unique to siblings
            slug = slugify(self.name)
            self.slug = slug
            siblings = self.get_siblings()
            i = 1
            while siblings.filter(slug=self.slug).exists():
                i += 1
                self.slug = slug + '-%d' % i

            # now create a URL based on parent's url + slug
            if self.parent:
                self.url = '%s/%s' % (self.parent.url, self.slug)
            else:
                self.url = self.slug
        super(Page, self).save(*args, **kwargs)
然后添加一个URL模式:
(r'^pages/(?P<page_url>[\w\d_/-]+)/$', 'pages.views.show_page'),

在你的视图中,你只需要获取正确的页面:

def show_page(request, page_url=None):
    page = get_object_or_404(Page, url=page_url)
    ...

2
当您修改根/分支的slug并需要更新后代URL时怎么办? - jozxyqk

7
感谢您对我的问题的关注。 看,这是我最终完成的方法。

models.py

class WebPage(MPTTModel):

    slug=RuSlugField(max_length=20,unique=True)
    title=models.CharField(max_length=50)
    content=models.TextField()
    parent=TreeForeignKey('self',null=True,blank=True,related_name='children')

    class MPTTMeta:
        order_insertion_by=['slug']

    def get_absolute_url(self):#TODO:: replace with get_ancestors
        url = "/%s/" % self.slug
        page = self
        while page.parent:
            url = "/%s%s" % (page.parent.slug,url)
            page = page.parent
        return url

urls.py

urlpatterns = patterns('website.views',
    url(r"^add/$", "add_page",name="add"),
    url(r"^(?P<full_slug>.*)/add/$", "add_page",name="add"),
    url(r"^(?P<full_slug>.*)/edit/$", "edit_page",name="edit"),
    url(r'^$', ListView.as_view(model=WebPage,template_name='index.html',context_object_name="webpages_list",),name='index'),
    url(r"^(?P<full_slug>.*)/$", "page", name="page"),
)

views.py

def page(request, full_slug):

    # Make a list from full_slug.
    # For ex. /trance/progressive_trance/fonarev -> ['trance','progressive_trance','fonarev']
    slugs=full_slug.split('/')

    page=None

    # Get a page by it's slug
    if len(slugs)>1:
        page=get_object_or_404(WebPage,slug=slugs[-1])#slugs=['trance','vocal_trance'] -> 'vocal_trance'
    elif len(slugs)==1:
        page=get_object_or_404(WebPage,slug=slugs[0])#slugs=['trance'] -> 'trance'

    # Check if page url matches requested full_slug
    if page.get_absolute_url().strip('/') == full_slug:
        return render_to_response('page.html', {'page': page},context_instance=RequestContext(request))
    else:
        raise Http404

def edit_page(request,full_slug):
    slugs=full_slug.split('/')
    page=None

    if len(slugs)>1:
        page=get_object_or_404(WebPage,slug=slugs[-1])
    elif len(slugs)==1:
        page=get_object_or_404(WebPage,slug=slugs[0])

    if not page.get_absolute_url().strip('/') == full_slug:
        raise Http404

    # Send POST data for update an existing page.Update a page.
    if request.method=='POST':
        form=WebPageForm(request.POST, instance=page)
        if form.is_valid():
            form.save()
        return HttpResponseRedirect(page.get_absolute_url())

    # Render a form to edit data for existing page
    else:
        form=WebPageForm(instance=page)

    return render_to_response('edit_page.html',{'form':form,},context_instance=RequestContext(request))

def add_page(request,full_slug=None):
    parent_page=None
    slug=None

    if full_slug:
        slug=full_slug.split('/')

    # If there is a slug in REQUEST(ex.'trance')->we need to add a new_page to her parent_page.
    # So get a parent page.
    if slug:
        if len(slug)>1:
            parent_page=get_object_or_404(WebPage,slug=slug[-1])
        elif len(slug)==1:
            parent_page=get_object_or_404(WebPage,slug=slug[0])

    # Create a new_page
    if request.method=='POST':
        form=WebPageForm(request.POST)
        if form.is_valid():
            new_page=form.save(commit=False)
            if parent_page:
                new_page.parent=parent_page
            new_page.save()
            return HttpResponseRedirect(new_page.get_absolute_url())

    # Return an unbounded form
    else:
        form=WebPageForm()

return render_to_response('add_page.html',{'form':form,},context_instance=RequestContext(request))

关键在于我们必须通过full_slug访问页面来检查页面是否真的存在:
if not page.get_absolute_url().strip('/') == full_slug:
            raise Http404

否则,仅通过 slug 进行检查可能是错误的。

2

是的,将“一个应用程序”替换为“Django应用程序”真的非常值得编辑! Anatoly Techtonik,现在我会为您和@Forethinker祈祷。 - MrKsn

0
def get_absolute_url(self):
    return '/'.join([x['slug'] for x in self.get_ancestors(include_self=True).values()])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接