* _set属性在Django模型 [英] *_set attributes on Django Models

查看:89
本文介绍了* _set属性在Django模型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个关于 django.db.models 的非常基本的问题。



在此官方django教程中,如果搜索单词 choice_set ,您将看到该变量 choice_set 不是在任何地方声明,虽然神奇地,我们可以开始在代码中使用它。



我不知道,什么是$ $ $ $ $ django.db.models.Model 做神奇地创建了* _set变量,以及它创建了什么其他变量?

解决方案

您可以获得一个类的属性的完整列表,您定义的属性和为其定义的属性,使用 dir 函数,只需执行

  dir(Poll)

你会得到一些看起来有点像(虽然不完全正在构建它)以迂回的方式):

  ['DoesNotExist','MultipleObjectsReturned','__class__','__delattr__',$ b $ _ _,__,__,__,__,__,__, __ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ ,'_deferred','_get_FIELD_display',
'_get __ext_or_previous_by_FIELD','_get_next_or_previous_in_order','_get_pk_val',
'_get_unique_checks','_meta','_perform_date_checks','_perform_unique_checks','_set_pk_val',
'clean','clean_fields' ,'date_error_message','delete','full_clean','objects',
'pk','prepare_database_save','save','save_base','choice_set',
'serializable_value' unique_error_message','validate_unique']

这很有价值!我们可以看到例如 DoesNotExist MultipleObjectsReturned 以及最重要的一个对象。但是Django没有添加其中的一些属性。如果您执行 dir(object()),您将在所有对象中找到属性列表:


$ _
$ $ $ $ $ $'$'$'$','__,__,_ _,__ __reduce__','__reduce_ex__','__repr__','__setattr__','__sizeof__','__str__','__subclasshook__']

大多数情况下,您可以忽略以两个 __ 开头和结尾的那些。大多数其他的都是由Django添加的。






至于它实际设置的方式和位置:Django设置大部分新模型的属性动态地使用 models.Model 元类。首先要知道的是,您可以使用 setattr 函数动态添加成员或方法到一个类中:

  class X:
pass
setattr(X,q,12)
打印Xq#打印12

这是如何根据您的属性名称创建新属性。



在教程中,允许它开始定义这些额外属性的重要线条是:

  class Poll(models.Model ):

这意味着投票类继承 models.Model class(属于Django)。继承有许多有用的属性 - 基本上, Poll 类继承了 models.Model 类已经设置的一些行为但是它定义了大部分这些新属性的位置在模型元类。元类是一个棘手的概念,但基本上它们是创建新类的方法,通过定义一个,Django可以在 models.py 元类被定义和定义任何新的。



可以找到Model metaclass的代码这里(从第55行开始) - 这是一组代码,实际上是一步一步地从地面创建一个类向上。看起来很复杂,你可以通过查看变量名称得到很多东西。例如,看看有希望命名的 add_to_class 方法:

  def add_to_class (cls,name,value):
如果hasattr(value,'contribut_to_class'):
value.contribute_to_class(cls,name)
else:
setattr(cls,name,价值)

的一个特殊情况之外,contribut_to_class (对您的兴趣不重要),这是一种向类添加新属性(如方法或成员)的方法。它被称为的地方给我们提示它的添加内容:

  class.add_to_class('DoesNotExist',subclass_exception ('DoesNotExist')...< truncated> ... 

这里添加 DoesNotExist 异常,如果您要求不存在的投票,则返回什么(请参阅运行 Poll.objects.get(pk = 1337),或直接输入 Poll.DoesNotExist )。 p>

但是,Django实际上比这更复杂,特定的 _set 属性询问是不是为每个模型构建 - 它是通过一个 ForeignKey (如同您的投票选择)。被分配的各个地方非常复杂,但基本上都是回到这个 get_accessor_name function in related.py

  def get_accessor_name(self):
#这个方法封装了决定什么名字给出一个
#accessor描述符的逻辑,它检索相关的多对一或
#多对多对象。它使用较低级的object_name +_set,
#,但可以使用related_name选项覆盖。
如果self.field.rel.multiple:
#如果这是对自己的对称m2m关系,则没有反向访问器。
如果getattr(self.field.rel,'symmetry',False)和self.model == self.parent_model:
返回无
返回self.field.rel.related_name或(self .opts.object_name.lower()+'_set')
else:
返回self.field.rel.related_name或(self.opts.object_name.lower())

这只是一个名字 - 跟踪它,以确定如何添加到该类是不小的壮举。但是我希望你能看到,Django有很多机会添加这样的属性。


I have a very basic question about django.db.models.

In this official django tutorial, if you search for word "choice_set", you will see that variable "choice_set" is not declared anywhere, though magically, we can start using it in the code.

I wonder, what does django.db.models.Model do that magically created the *_set variable, and what other variables does it create?

解决方案

You can get a full list of the attributes of a class, both those you defined and the ones that are defined for it, using the dir function, just do

 dir(Poll)

You'll end up with something that looks a little like (though not exactly- I'm constructing it in a roundabout way):

['DoesNotExist', 'MultipleObjectsReturned', '__class__', '__delattr__',
'__dict__', '__doc__', '__eq__', '__format__', '__getattribute__', '__hash__',
'__init__', '__metaclass__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', 
'__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__unicode__',
 '__weakref__', '_base_manager', '_default_manager', '_deferred', '_get_FIELD_display', 
'_get_next_or_previous_by_FIELD', '_get_next_or_previous_in_order', '_get_pk_val', 
'_get_unique_checks', '_meta', '_perform_date_checks', '_perform_unique_checks', '_set_pk_val', 
'clean', 'clean_fields', 'curve_set', 'date_error_message', 'delete', 'full_clean', 'objects', 
'pk', 'prepare_database_save', 'save', 'save_base', 'choice_set',
'serializable_value', 'unique_error_message', 'validate_unique']

That's a lot of values! We can see exceptions like DoesNotExist and MultipleObjectsReturned, along with the most important one, objects. But some of these attributes weren't added by Django. If you do dir(object()) you'll find a list of the attributes in all objects:

['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']

Mostly you can ignore the ones that start and end with two __. Most of the others were added by Django.


As for how and where it actually sets these: Django sets most of each new model's attributes dynamically using the models.Model metaclass. The first thing to know is that you can add a member or method to a class dynamically, using the setattr function:

class X:
    pass
setattr(X, "q", 12)
print X.q  # prints 12

That's how it can create new attributes just based on the name of your attribute.

In the tutorial, the important line that allows it to start defining these extra attributes is:

class Poll(models.Model):

This means that the Poll class inherits the models.Model class (which belongs to Django). Inheritance has many useful properties- basically, the Poll class inherits some of the behavior that the models.Model class has set up- but the place it defines most of these new attributes is in the Model metaclass. Metaclasses are a tricky concept, but basically they serve as a recipe for creating new classes, and by defining one, Django gets to step in right when the models.py metaclass is being defined, and define any new .

The code for the Model metaclass can be found here (starting at line 55)- it's a set of code that is actually step-by-step creating a class from the ground up. As complicated as it looks, you can get a lot out of it just by looking at the variable names. For instance, look at the promisingly named add_to_class method:

def add_to_class(cls, name, value):
    if hasattr(value, 'contribute_to_class'):
        value.contribute_to_class(cls, name)
    else:
        setattr(cls, name, value)

Outside of the one special case of 'contribute_to_class (not important for your interest), this is a method for adding a new attribute (such as a method or a member) to a class. The places where it is called give us hints of what it is adding:

 class.add_to_class('DoesNotExist', subclass_exception(str('DoesNotExist') ...<truncated>...

Here it is adding the DoesNotExist exception, which is what is returned if you ask for a Poll that doesn't exist. (See for yourself by running Poll.objects.get(pk=1337), or directly by typing in Poll.DoesNotExist).

But Django is actually even more complicated than that. The specific _set attribute you're asking about isn't constructed for every model- it's created when a field is related to another by a ForeignKey (as are your Poll and Choice). The various places where it gets assigned are very complicated, but it basically all comes back to this get_accessor_name function in related.py

def get_accessor_name(self):
    # This method encapsulates the logic that decides what name to give an
    # accessor descriptor that retrieves related many-to-one or
    # many-to-many objects. It uses the lower-cased object_name + "_set",
    # but this can be overridden with the "related_name" option.
    if self.field.rel.multiple:
        # If this is a symmetrical m2m relation on self, there is no reverse accessor.
        if getattr(self.field.rel, 'symmetrical', False) and self.model == self.parent_model:
            return None
        return self.field.rel.related_name or (self.opts.object_name.lower() + '_set')
    else:
        return self.field.rel.related_name or (self.opts.object_name.lower())

That's just coming up with the name- tracing it back to figure out how it gets added to the class is no small feat. But I hope you see from this that Django has many chances to add attributes like this.

这篇关于* _set属性在Django模型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆