使用Django,我应该在我的REST API和web应用程序中实现两种不同的url映射逻辑吗?如何实现



我有一个Book模型,其中Chapter模型的几个实例可以通过外键链接

class Book(models.Model):
pass
class Chapter(models.Model):
book = models.ForeignKey(to=Book, ...)

class Meta:
order_with_respect_to = "book"

我决定将Django用于RESTful API,使用Django Rest Framework,并用于web应用程序,使用Dgango Template。我希望它们分开,因为应该为另一个潜在的应用程序打开使用API的方式。

出于包括管理目的在内的几个原因,API调用了这种url映射逻辑:

mylibrary.org/api/books/
mylibrary.org/api/books/<book_id>/
mylibrary.org/api/chapters/
mylibrary.org/api/chapters/<chapter_id>/

然而,对于我的web应用程序,我希望用户通过以下url映射逻辑访问书籍及其内容:

mylibrary.org/books/
mylibrary.org/books/<book_id>-esthetic-slug/
mylibrary.org/books/<book_id>-esthetic-slug/chapter_<chapter_order>/

这个想法是路由器从<book_id>,不管鼻涕虫可能是什么,章节根据它的顺序而不是它的ID。

现在,如果这是可取的,或者我一定会遇到障碍,我需要一些建议。例如,web应用程序的<book_id><章节顺序>是";翻译的";进入API的<chapter_id>?或者,如果我想让网络应用程序的书籍列表提供自动生成的书籍链接,这应该在API还是网络应用程序级别完成?

我对Django/DRF和一般的web开发都很陌生。

双URL根本不是问题。每当程序渲染视图时都会使用它,并且它还具有API(可能用于移动应用程序(。我通常所做的是让id字段也在"网页"的URL中,这对我来说更容易跟踪。然而,如果你想在URL中有一个"漂亮"的段塞,可以试试这个:

"""
models.py
"""
import uuid
from django.db import models

class Book(models.Model):
id = models.UUIDField(primary_key=True, null=False, editable=False, default=uuid.uuid4)
slug = models.SlugField(max_length=50)
class Chapter(models.Model):
id = models.UUIDField(primary_key=True, null=False, editable=False, default=uuid.uuid4)
book = models.ForeignKey(to=Book, ...)
sort = models.PositiveIntegerField()

class Meta:
order_with_respect_to = "book"
unique_together = [("book", "sort"), ]  # so that there is never two chapters with the same number
"""
urls.py
"""
from django.urls import path
from . import apiviews, views
urlpatterns = [
# 'web' URLs
path("books/", views.books, "book_list"),  # mylibrary.org/books/
path("books/<str:book_slug>", views.book, "book"),  # mylibrary.org/books/harry-potter-and-the-prisoner-of-azkaban
path("books/<str:book_slug>/chapter_<int:chapter>", views.chapter, "chapter"),  # mylibrary.org/books/harry-potter-and-the-prisoner-of-azkaban/chapter_2
# API URLs
path("api/books/", apiviews.books, "api_book_list"),  # mylibrary.org/api/books/
path("api/books/<uuid:id>", apiviews.book, "api_book"),  # mylibrary.org/api/books/b21a0af6-4e6c-4c67-b44d-50f8b52cd459
path("api/chapters/", apiviews.chapters, "api_chapters"),  # mylibrary.org/api/chapters/
path("api/chapters/<uuid:id>", apiviews.chapter, "api_chapter"),  # mylibrary.org/api/chapters/c76a89ae-ad73-4752-991c-8a82e47d3307
]
"""
views.py
"""
from .models import Book, Chapter

def books(request):
book_list = Book.objects.all()

def book(request, book_slug)
try:
book = Book.objects.get(slug=book_slug)
except Book.DoesNotExist:
pass

def chapter(request, book_slug, chapter)
try:
book = Book.objects.get(slug=book_slug)
chapter = book.chapter_set.get(sort=chapter)
except Book.DoesNotExist:
pass
except Chapter.DoesNotExist:
pass
"""
apiviews.py
"""
from .models import Book, Chapter

def books(request):
book_list = Book.objects.all()

def book(request, id)
try:
book = Book.objects.get(id=id)
except Book.DoesNotExist:
pass

def chapters(request):
chapter_list = Chapter.objects.all()

def chapter(request, id)
try:
chapter = Chapter.objects.get(id=id)
except Chapter.DoesNotExist:
pass

这些文件反映了您建议URL的方式。我个人(我不认为这是正确的方式(将API视图设置如下:

mylibrary.org/books/
mylibrary.org/books/b21a0af6-4e6c-4c67-b44d-50f8b52cd459
mylibrary.org/books/b21a0af6-4e6c-4c67-b44d-50f8b52cd459/chapters/
mylibrary.org/books/b21a0af6-4e6c-4c67-b44d-50f8b52cd459/chapters/3
# and then for example:
mylibrary.org/books/b21a0af6-4e6c-4c67-b44d-50f8b52cd459/comments/
mylibrary.org/books/b21a0af6-4e6c-4c67-b44d-50f8b52cd459/comments/295

我觉得这个结构更全面,但我看不出你的版本有任何优点或缺点。两者都很好,而且都有很好的理由。一个是";API只是访问数据库对象的一种方式,因此如果我知道ID">,另一个";我有书,书有章,所以章是书的一个子事物">

最新更新