在django和django rest框架中增强了对自然键的支持

natural-keys的Python项目详细描述


django自然键

在django和Django REST Framework中增强了对natural keys的支持。从wq.db中提取,供一般使用。

django natural keys提供了许多有用的模型方法(例如get_or_create_by_natural_key()),这些方法可以加快django中使用自然键的速度。该模块还提供了两个序列化程序类,这些类简化了为具有自然键的模型创建rest api支持的过程。

Latest PyPI ReleaseRelease NotesLicenseGitHub StarsGitHub ForksGitHub Issues

Travis Build StatusPython SupportDjango Support

用法

django自然键可通过pypi获得:

# Recommended: create virtual environment# python3 -m venv venv# . venv/bin/activate
pip install natural-keys

型号API

要在vanilla django中使用natural keys,需要在模型类上定义一个natural_key()方法,在管理器类上定义一个get_natural_key()方法。使用django自然键,您可以扩展NaturalKeyModel,并在模型的Meta类上定义unique_together属性,或者使用带unique=True的字段。第一个unique_together条目或第一个unique字段(autofield除外)将被视为模型的自然键,使用自然键所需的所有函数都将自动工作。

fromnatural_keysimportNaturalKeyModelclassEvent(NaturalKeyModel):name=models.CharField(max_length=255)date=models.DateField()classMeta:unique_together=(('name','date'),)classNote(models.Model):event=models.ForeignKey(Event)note=models.TextField()

fromnatural_keysimportNaturalKeyModelclassEvent(NaturalKeyModel):name=models.CharField(unique=True)

然后,您的模型及其管理器将提供以下方法:

# Default Django methodsinstance=Event.objects.get_by_natural_key('ABC123',date(2016,1,1))instance.natural_key==('ABC123',date(2016,1,1))# get_or_create + natural keysinstance,is_new=Event.objects.get_or_create_by_natural_key('ABC123',date(2016,1,1))# Like get_or_create_by_natural_key, but discards is_new# Useful for quick lookup/creation when you don't care whether the object exists alreadyinstance=Event.objects.find('ABC123',date(2016,1,1))note=Note.objects.create(event=Event.objects.find('ABC123',date(2016,1,1)),note="This is a note")instance==note.event# Inspect natural key fields on a model without instantiating itEvent.get_natural_key_fields()==('name','date')

嵌套自然键

django natural key s的一个关键特性是它将自动遍历ForeignKey到相关模型(也应该是NaturalKeyModel类)。这使得用最少的努力定义复杂的、任意嵌套的自然键成为可能。

classPlace(NaturalKeyModel):name=models.CharField(max_length=255,unique=True)classEvent(NaturalKeyModel):place=models.ForeignKey(Place)date=models.DateField()classMeta:unique_together=(('place','date'),)
Event.get_natural_key_fields()==('place__name','date')instance=Event.find('ABC123',date(2016,1,1))instance.place.name=='ABC123'

rest框架支持

django natural keys主要通过自定义序列化程序类提供与Django REST Framework的多个集成。在大多数情况下,您需要使用以下任一选项:

  • NaturalKeyModelSerializer,或
  • natural_key_slug伪字段(见下文)

如果只有一个模型的自然键只有一个char字段,那么您可能不需要使用这两种集成。在您看来,您可以使用django rest框架的内置lookup_field直接指向您的自然键。

NaturalKeyModelSerializer

NaturalKeyModelSerializer有助于在rest api中处理复杂的自然键。它可以与NaturalKeyModel一起使用,或者(更常见地)具有NaturalKeyModel外键但不是NaturalKeyModel本身的模型一起使用。(一个具体的例子是vera.Report模型,它有一个到vera.Event的外键,这是一个NaturalKeyModel)。

NaturalKeyModelSerializer扩展了drf的ModelSerializer,但对指向NaturalKeyModel的每个外键使用NaturalKeySerializer。当{{CD24}}或^ {CD25}}对主模型时,嵌套^ ^ {CD22> }s将自动创建引用模型的实例(如果它们不存在)(通过上面所述的^ {CD27>}方法)。请注意,NaturalKeyModelSerializer不会覆盖drf对其他字段的默认行为,无论它们是否构成主模型自然键的一部分。

NaturalKeySerializer在技术上可以用作顶级序列化程序,但不建议这样做。NaturalKeySerializer设计用于处理嵌套的自然键,不支持更新或非自然键字段。即使在与{{CD12}}一起使用时,^ {< CD22> }也不会更新现有的相关模型实例。相反,它将把外键重新发布到相关模型的另一个(可能是新的)实例。把NaturalKeySerializer看作一个特殊的RelatedField类,而不是一个Serializer类本身可能会有帮助。

您可以将NaturalKeyModelSerializerDjango REST Framework和/或wq.db一起使用,就像任何其他序列化程序一样:

# Django REST Framework usage examplefromrest_frameworkimportviewsetsfromrest_frameworkimportroutersfromnatural_keysimportNaturalKeyModelSerializerfrom.modelsimportEvent,NoteclassEventSerializer(NaturalKeyModelSerializer):classMeta:model=EventclassNoteSerializer(NaturalKeyModelSerializer):classMeta:model=NoteclassEventViewSet(viewsets.ModelViewSet):queryset=Event.objects.all()serializer_class=EventSerializerclassNoteViewSet(viewsets.ModelViewSet):queryset=Note.objects.all()serializer_class=NoteSerializerrouter=routers.DefaultRouter()router.register(r'events',EventViewSet)router.register(r'notes',NoteViewSet)# wq.db usage examplefromwq.dbimportrestfromnatural_keysimportNaturalKeyModelSerializerfrom.modelsimportEvent,Noterest.router.register_model(Note,serializer=NaturalKeyModelSerializer)rest.router.register_model(Event,serializer=NaturalKeyModelSerializer)

一旦设置好,就可以使用rest api创建并查看NaturalKeyModel实例和相关数据。为了方便与常规html表单的集成,django natural keysHTML JSON Forms包集成,后者通过数组命名约定支持嵌套键,如下例所示。

<formaction="/events/"method="post"><inputname="place[name]"><inputtype="date"name="date"></form>
// /events.json[{"id":123,"place":{"name":"ABC123"},"date":"2016-01-01"}]
<formaction="/notes/"method="post"><inputname="event[place][name]"><inputtype="date"name="event[date]"><textareaname="note"></textarea></form>
// /notes.json[{"id":12345,"event":{"place":{"name":"ABC123"},"date":"2016-01-01"},"note":"This is a note"}]

天然钥匙弹头

作为使用NaturalKeyModelSerializer/NaturalKeySerializer的替代方法,您还可以使用单个slug-查找和序列化的like字段。NaturalKeyModel(及其相关的queryset)为此定义了一个伪字段natural_key_slug

classPlace(NaturalKeyModel):name=models.CharField(max_length=255,unique=True)classRoom(NaturalKeyModel)place=models.ForeignKey(Place,models.ON_DELETE)name=models.CharField(max_length=255)classMeta:unique_together=(('place','name'),)
room=Room.objects.find("ABC123","MainHall")assert(room.natural_key_slug=="ABC123-MainHall")assert(room==Room.objects.get(natural_key_slug="ABC123-MainHall"))

您可以在REST API中公开此功能,以公开自然密钥,而不是数据库生成的id为此,您可能需要执行以下操作:

  1. 使用id = serializers.ReadOnlyField(source='natural_key_slug')
  2. 创建常规序列化程序
  3. ModelViewSet(或类似的泛型类)上设置lookup_field = 'natural_key_slug',并相应地更新url注册
  4. 确保使用serializers.SlugRelatedField(slug_field='natural_key_slug')
  5. 序列化任何相关模型上的外键

wq.db中,在注册router

# myapp/rest.pyfromwq.dbimportrestfrom.modelsimportRoomrest.router.register_model(Room,fields='__all__',lookup='natural_key_slug',)

注意,如果任何组件值包含分隔符(-默认情况下),则natural_key_slug可能不会按预期工作。为了缓解这种情况,可以将模型类上的natural_key_separator设置为另一个字符。

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
java如何反射地迭代数组字段?   java NamedQuery错误“具有给定标识符的多行:1”   java无法使用单独类中的计时器更新TextView   兼容性什么时候可以很快使用新的Java功能?   java二叉树路径和   java矩形的性能   java我想从同一个子表在主表中添加两个外键   java如何获取基于特定日期的所有数据?   java javafx、OO编程规则和写入变量类型的选择   java使用带枚举的switch语句   java异步任务生成运行时异常   java为什么JLabel不显示下划线字符?   java如何解析具有可变参数号的函数?   带有按钮的java JavaFX自定义列表单元格:未调用处理程序   java Modelmapper无法映射整个模型?   传递给持久化的java分离实体,包含LatLng列表