Python: ES DSL: How to define custom DocType properly

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?

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)

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