Django:接受记录或记录片段进行输入的友好方式

Django:接受记录或记录片段进行输入的友好方式,django,duck-typing,Django,Duck Typing,我有这样一个函数: def foo(bar): ... 现在,bar可以是Django记录,也可以是指向记录的slug。我需要这种灵活性,这样当我手头有实际记录时,或者从一个更通用的函数调用这个函数时,我就可以调用这个函数,这个函数只有一个字符串(从数据库中提取)可用 我意识到我可以做如下事情: def foo(bar): try: bar.pk except AttributeError: bar = Bar.objects.get(s

我有这样一个函数:

def foo(bar):
    ...
现在,
bar
可以是Django记录,也可以是指向记录的slug。我需要这种灵活性,这样当我手头有实际记录时,或者从一个更通用的函数调用这个函数时,我就可以调用这个函数,这个函数只有一个字符串(从数据库中提取)可用

我意识到我可以做如下事情:

def foo(bar):
    try:
        bar.pk
    except AttributeError:
        bar = Bar.objects.get(slug=bar)
    ...
但这看起来一点也不优雅


如果可以,我希望避免使用iInstance。

我不确定这是一种糟糕的处理方式,但如果我想做类似的事情,我可能会使用
hasattr

def foo(bar):
    if hasattr(bar,"pk"):
        bar.pk
    else:
        # I include the str in case some other object with a __str__ happens
        # to come through.
        bar = Bar.objects.get(slug=str(bar))

我不确定这是一种糟糕的处理方式,但如果我想做类似的事情,我可能会使用
hasattr

def foo(bar):
    if hasattr(bar,"pk"):
        bar.pk
    else:
        # I include the str in case some other object with a __str__ happens
        # to come through.
        bar = Bar.objects.get(slug=str(bar))

根据定义,您不使用Duck类型。鸭子打字说:“如果它说话像鸭子,看起来像鸭子,那它就是鸭子。”

Duck类型意味着您可以将两个完全不同的类的对象传递给该方法并使其工作,因为它们都实现相同的方法/属性(或者优雅地处理缺少的方法/属性)。这意味着该方法从不关心它得到什么类型,只关心传递给它的任何对象都具有它期望使用的属性

在您的例子中,您希望有时传递一个对象,有时传递一个字符串,该字符串可用于查找所述对象。这与Duck类型无关

iInstance是解决这个问题的正确方法。在这种情况下,这是解决问题的最清晰的方法,其他任何事情都会更复杂,更难理解,没有任何好处。您可以在属性或hasattr上使用try/except,但这可能会让未来的开发人员比其他任何东西都更加困惑。Duck类型非常好,它取代了强制转换各种子类以匹配某些特定函数,但Duck类型不适用于这种情况


简而言之。使用iInstance即可。对于你的情况,这是正确的(蟒蛇式)方法

根据定义,您不使用Duck类型。鸭子打字说:“如果它说话像鸭子,看起来像鸭子,那它就是鸭子。”

Duck类型意味着您可以将两个完全不同的类的对象传递给该方法并使其工作,因为它们都实现相同的方法/属性(或者优雅地处理缺少的方法/属性)。这意味着该方法从不关心它得到什么类型,只关心传递给它的任何对象都具有它期望使用的属性

在您的例子中,您希望有时传递一个对象,有时传递一个字符串,该字符串可用于查找所述对象。这与Duck类型无关

iInstance是解决这个问题的正确方法。在这种情况下,这是解决问题的最清晰的方法,其他任何事情都会更复杂,更难理解,没有任何好处。您可以在属性或hasattr上使用try/except,但这可能会让未来的开发人员比其他任何东西都更加困惑。Duck类型非常好,它取代了强制转换各种子类以匹配某些特定函数,但Duck类型不适用于这种情况


简而言之。使用iInstance即可。对于你的情况,这是正确的(蟒蛇式)方法

这是另一种方法,它将有助于您执行其他功能。我将确定您使用的模型名称为“Item”

def slug_resilient_decorator(class_type):

    def slug_resilient_wrapper(obj):

            if obj.has_attr('pk'):
                    return obj
            else:
                    return class_type.objects.get(slug=obj)

    return wrapper

@slug_resilient_decorator(Item)
def slug_resilient_detail_view(obj):

    ...

这是另一种方法,它将有助于其他功能,你想做同样的事情。我将确定您使用的模型名称为“Item”

def slug_resilient_decorator(class_type):

    def slug_resilient_wrapper(obj):

            if obj.has_attr('pk'):
                    return obj
            else:
                    return class_type.objects.get(slug=obj)

    return wrapper

@slug_resilient_decorator(Item)
def slug_resilient_detail_view(obj):

    ...

如果可以的话,我想避免使用iInstance——有什么特别的原因吗?为什么不创建两个不同的函数呢。一个新的
foo\u with_slug
进行查找,然后调用你的
foo
方法。我想是习惯的力量吧?我真的只喜欢在我的函数被duck类型愚弄时使用它,例如,如果它可以接受字符串或字符串数组。@sdolan实际上,我想这可能是最简单的方法。如果我不必跟踪两个不同的函数来确定目标,那就容易多了。所以,概括一下,您希望避免
isinstance
,因为您喜欢避免isinstance。。。我想澄清一下。如果可以的话,我想避免使用iInstance——有什么特别的原因吗?为什么不创建两个不同的函数呢。一个新的
foo\u with_slug
进行查找,然后调用你的
foo
方法。我想是习惯的力量吧?我真的只喜欢在我的函数被duck类型愚弄时使用它,例如,如果它可以接受字符串或字符串数组。@sdolan实际上,我想这可能是最简单的方法。如果我不必跟踪两个不同的函数来确定目标,那就容易多了。所以,概括一下,您希望避免
isinstance
,因为您喜欢避免isinstance。。。我只是想说清楚。除非我遗漏了什么,否则你可以用
unicode(bar)替换
str(bar)
并获得与unicode支持相同的结果。据我所知,slug在定义上应该仅为ascii…事实上,我刚刚检查了django的slagify的源代码,它正在stipping unicode。除非我遗漏了什么,否则你可以用
unicode(bar)替换
str(bar)
并获得与unicode支持相同的结果。据我所知,slug在定义上应该仅为ascii…事实上,我刚刚检查了django的slagify的源代码,它正在stipping unicode。刚刚检查了
django.db.models.fields.related
,它使用
isinstance
验证外键分配。感谢John以这种方式解释Duck键入,它将帮助我区分
isinstance
-Avoider的类型。“我一直在努力想为什么这会对这种情况有利,而你已经澄清了这一点。”马特同意。我刚刚遇到了这么多“被认为是有害的”类型的文章,我认为