使用 Django,我是否应该在我的 REST API 和 Web 应用程序中实现两种不同的 url 映射逻辑,以及如何实现?
Using Django, should I implement two different url mapping logics in my REST API and web application, and how?
我有一个 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 应用程序,使用 Django 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>/
这个想法是路由器从 获取书籍,无论是什么 slug 和章节,根据它的顺序而不是它的 ID。
现在我需要一些建议,如果这是可取的,或者我一定会遇到障碍。
例如,Web 应用程序的 / 应如何以及在何处“翻译”为 API 的 ?或者,如果我希望网络应用程序的图书列表提供自动生成的图书链接,应该在 API 还是网络应用程序级别完成?
我对 Django/DRF 和一般的 Web 开发还很陌生。
双URL完全不是问题。每当程序呈现视图并具有 API(可能用于移动应用程序)时都会使用它。我通常做的是让 id
字段也位于 'web' 页面的 URL 中,这对我来说更容易跟踪。但是,如果你想在 URL 中添加一个 'nice' slug,试试这个:
"""
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",我应该能够提取任意章节,另一个是 “我有书,书有章节,所以章节是书的子项”。
我有一个 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 应用程序,使用 Django 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>/
这个想法是路由器从
现在我需要一些建议,如果这是可取的,或者我一定会遇到障碍。
例如,Web 应用程序的
我对 Django/DRF 和一般的 Web 开发还很陌生。
双URL完全不是问题。每当程序呈现视图并具有 API(可能用于移动应用程序)时都会使用它。我通常做的是让 id
字段也位于 'web' 页面的 URL 中,这对我来说更容易跟踪。但是,如果你想在 URL 中添加一个 'nice' slug,试试这个:
"""
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",我应该能够提取任意章节,另一个是 “我有书,书有章节,所以章节是书的子项”。