# Python: ES DSL: How to define custom DocType properly

**URL:** <https://discuss.elastic.co/t/python-es-dsl-how-to-define-custom-doctype-properly/94411>\
**Category:** Elasticsearch\
**Created:** [July 25, 2017, 1:32am UTC](https://discuss.elastic.co/t/python-es-dsl-how-to-define-custom-doctype-properly/94411 "2017-07-25T01:32:19Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![smlbiobot](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/smlbiobot/32/29622_2.png) [@smlbiobot](https://discuss.elastic.co/u/smlbiobot)\
**Post date:** [July 25, 2017, 1:32am UTC](https://discuss.elastic.co/t/python-es-dsl-how-to-define-custom-doctype-properly/94411/1 "2017-07-25T01:32:19Z")

</div>

I am trying to define custom DocType in Python using the ElasticSearch DSL library but am having some trouble, specifically with Nested classes. In the example below, both the fields author and mentions have the same type of properties but I don’t know how to define those properties in a separate class. Any help would be appreciated!

```
class DiscordMessage(DocType):
    """Discord Message."""
    id = Integer()
    content = Text(
        fields={'raw': Keyword()}
    )

    author = Nested(
        properties={
            'id': Integer(),
            'name': Text(fields={'raw': Keyword()}),
            'username': Text(fields={'raw': Keyword()}),
            'display_name': Text(feidls={'raw': Keyword()}),
            'bot': Boolean(),
            'top_role': Nested(
                doc_class=DiscordRole,
                properties={
                    'id': Integer(),
                    'name': Text(fields={'raw': Keyword()})
                }
            ),
            'joined_at': Date(),
            'roles': Nested(
                doc_class=DiscordRole,
                properties={
                    'id': Integer(),
                    'name': Text(fields={'raw': Keyword()})
                }
            )
        }
    )

    server = Nested(
        properties={
            'id': Integer(),
            'name': Text(fields={'raw': Keyword()})
        }
    )

    channel = Nested(
        properties={
            'id': Integer(),
            'name': Text(fields={'raw': Keyword()}),
            'position': Integer(),
            'is_default': Boolean()
        }
    )

    mentions = Nested(
        properties={
            'id': Integer(),
            'name': Text(fields={'raw': Keyword()}),
            'username': Text(fields={'raw': Keyword()}),
            'display_name': Text(feidls={'raw': Keyword()}),
            'bot': Boolean(),
            'top_role': Nested(
                doc_class=DiscordRole,
                properties={
                    'id': Integer(),
                    'name': Text(fields={'raw': Keyword()})
                }
            ),
            'joined_at': Date(),
            'roles': Nested(
                doc_class=DiscordRole,
                properties={
                    'id': Integer(),
                    'name': Text(fields={'raw': Keyword()})
                }
            )
        }
    }

    timestamp = Date()

    class Meta:
        index = 'discord'

    def set_author(self, author):
        """Set author."""
        self.author = {
            'id': author.id,
            'name': author.display_name,
            'username': author.name,
            'display_name': author.display_name,
            'bot': author.bot,
            'roles': [
                {'id': r.id, 'name': r.name} for r in author.roles
            ],
            'top_role': {
                'id': author.top_role.id,
                'name': author.top_role.name
            },
            'joined_at': author.joined_at
        }

    def set_server(self, server):
        """Set server."""
        self.server = {
            'id': server.id,
            'name': server.name
        }

    def set_channel(self, channel):
        """Set channel."""
        self.channel = {
            'id': channel.id,
            'name': channel.name,
            'is_default': channel.is_default,
            'position': channel.position
        }

    def save(self, **kwargs):
        return super(DiscordMessage, self).save(**kwargs)

```

In particular, you see that I am setting properties using methods and I felt that I am setting them both in the definition and the method and it seems excessive. Or is that in fact necessary?

---

<div class="post-metadata">

**Author:** ![smlbiobot](https://sea2.discourse-cdn.com/elastic/user_avatar/discuss.elastic.co/smlbiobot/32/29622_2.png) [@smlbiobot](https://discuss.elastic.co/u/smlbiobot)\
**Post date:** [July 25, 2017, 9:37am UTC](https://discuss.elastic.co/t/python-es-dsl-how-to-define-custom-doctype-properly/94411/2 "2017-07-25T09:37:23Z")

</div>

I have rewritten above to the following, but I am still not entirely sure if this is the right way or not.

```
class ServerInnerObject(InnerObjectWrapper):
    """Server Inner Object."""
    id = Integer()
    name = Text(fields={'raw': Keyword()})

class ChannelInnerObject(InnerObjectWrapper):
    """Channel Inner Object."""
    id = Integer()
    name = Text(fields={'raw': Keyword()})

class RoleInnerObject(InnerObjectWrapper):
    """Role Inner Object."""
    id = Integer()
    name = Text(fields={'raw': Keyword()})

class MemberInnerObject(InnerObjectWrapper):
    """Member Inner Object."""
    id = Integer()
    name = Text(fields={'raw': Keyword()})
    display_name = Text(fields={'raw': Keyword()})
    bot = Boolean()
    top_role = Nested(doc_class=RoleInnerObject)
    roles = Nested(doc_class=RoleInnerObject)

class MessageDoc(DocType):
    """Discord Message."""
    id = Integer()
    content = Text(
        fields={'raw': Keyword()}
    )
    author = Nested(doc_class=MemberInnerObject)
    server = Nested(doc_class=ServerInnerObject)
    channel = Nested(doc_class=ChannelInnerObject)
    mentions = Nested(doc_class=MemberInnerObject)
    timestamp = Date()

    class Meta:
        doc_type = 'message'

    @classmethod
    def log(cls, message, **kwargs):
        """Log all."""
        doc = MessageDoc(
            content=message.content,
            embeds=message.embeds,
            attachments=message.attachments,
            id=message.id,
            timestamp=dt.datetime.utcnow()
        )
        doc.set_server(message.server)
        doc.set_channel(message.channel)
        doc.set_author(message.author)
        doc.set_mentions(message.mentions)
        doc.save(**kwargs)

    def member_dict(self, member):
        """Member dictionary."""
        return {
            'id': member.id,
            'name': member.display_name,
            'username': member.name,
            'display_name': member.display_name,
            'bot': member.bot,
            'roles': [
                {'id': r.id, 'name': r.name} for r in member.roles
            ],
            'top_role': {
                'id': member.top_role.id,
                'name': member.top_role.name
            },
            'joined_at': member.joined_at
        }

    def set_author(self, author):
        """Set author."""
        self.author = self.member_dict(author)

    def set_server(self, server):
        """Set server."""
        self.server = {
            'id': server.id,
            'name': server.name
        }

    def set_channel(self, channel):
        """Set channel."""
        self.channel = {
            'id': channel.id,
            'name': channel.name,
            'is_default': channel.is_default,
            'position': channel.position
        }

    def set_mentions(self, mentions):
        """Set mentions."""
        self.mentions = [self.member_dict(m) for m in mentions]

    def save(self, **kwargs):
        return super(MessageDoc, self).save(**kwargs)
```

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/elastic/original/3X/1/a/1ac57faf039f6b580b3f104ef42a2a89e41014de.png) [@system](https://discuss.elastic.co/u/system)\
**Post date:** [August 22, 2017, 9:37am UTC](https://discuss.elastic.co/t/python-es-dsl-how-to-define-custom-doctype-properly/94411/3 "2017-08-22T09:37:35Z")

</div>

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.
