首页 > 解决方案 > Django - 如何在不重复自己的情况下将“None”从 url kwargs 转换为 None

问题描述

我有一个这样的模型:

#models.py
class Location(BaseArticle):
    name = models.CharField(max_length=200)
    parent_location = models.ForeignKey("self",
                                        blank=True,
                                        null=True,
                                        help_text="Fill in if this location is a smaller part of another location.",
                                        on_delete=models.SET_NULL)
    description = HTMLField(blank=True,
                            null=True,
                            help_text="A description of the location and important features about it")

    class Meta:
        unique_together = ('name', 'parent_location')

我决定在我的 url 中通过它自己的名称和它的父元素的名称来唯一标识每个位置。

# urls.py
urlpatterns = [
    path('locations/<str:parent_location_name>/<str:location_name>', wiki_views.LocationView.as_view(), name='location'),
]

# example url to location "Seedy Bar" located in "City"
# https://<DOMAIN>/locations/city/seedy bar
# example url to location "City" that does not have a parent_location
# https://<DOMAIN>/locations/none/city

正如您从示例中看到的那样,parent_location可能为 null/None 的位置。我决定为这些 url 转换None"None",尽管我还没有确定None转换为的内容。现在您可能会意识到,这意味着每当我对 Location 进行任何操作时,我都需要注意在必要时在视图中转换"None"None,这非常烦人。

为了遵循 DRY,我想知道处理这个问题的最佳方法是什么,还是我把自己设计成一个角落?

编辑:我相信最好的解决方案可能是在 Location 模型或其管理器中。修复它意味着为所有视图和查询处理此逻辑,而在视图级别解决此问题意味着需要为每个可能使用“无”查询 Location 的视图实施该解决方案。

到目前为止我想出了什么:

鉴于管理器是您与模型交互的接口,我检查了它们是否有任何东西,并偶然发现了修改 get_queryset。但是,由于我自己不调用 get_queryset,因此我不确定是否像 filter/exclude 之类的函数我什至可能不知道实际调用它。但是,我通常最喜欢这种方法,因为它保留了如何使用模型/管理器处理这些东西的逻辑,这在我看来是属于的。

另一种选择当然是编写我自己的 Mixin 来在视图级别解决这个问题,但这意味着我仍然需要记住每次这是一个问题。

标签: djangourlnonetype

解决方案


这是我将如何做到这一点:

创建两个 URL:

path('locations/<str:location_name>', wiki_views.LocationView.as_view(), name='location'),
path('locations/<str:parent_location_name>/<str:location_name>', wiki_views.LocationViewWithParent.as_view(), name='location'),

并像这样构造这两个视图:

class LocationView(generics.APIView):
    parent = None
    ... rest of your code ...

class LocationViewWithparent(LocationView):
    parent = #Your code to get the parent_location_name parameter

第二个视图将执行与父视图相同的所有操作,但会覆盖父变量


推荐阅读