Skip to content

mutable content of an Object field | index population from dynamic json #235

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
titovanton opened this issue Dec 21, 2019 · 1 comment
Closed

Comments

@titovanton
Copy link

Hello, may be I do not understand something, but hope there is a solution for my case. I have few fields, which I've specified in the Document. One of them I've set as data = fields.ObjectField(dynamic=True) with the purpose to store there scheema-less object data. If I POST such documents with Kibana, it works and _search lookup inside as well, giving me documents I'm searching. But doing the same via django-elasticsearch-dsl, I have data field like that:

 "data" : [
            { },
            { },
            { },
            { }
          ],

Firts, the "data" expected to be an object, not a list. Second, it is the list of empty(!) objects.
What is the best way to implement such functionality? I can not specify the list of properties for the Object field, while the content of data field is mutable.

# models.py

class Car(models.Model):
    TYPE_SEDAN = 1
    TYPE_TRUCK = 2
    TYPE_SUV = 4
    TYPE_CHOICES = [
        (TYPE_SEDAN, 'Sedan'),
        (TYPE_TRUCK, 'Truck'),
        (TYPE_SUV, 'SUV'),
    ]

    name = models.CharField(max_length=256)
    color = models.CharField(max_length=256)
    description = models.TextField()
    type = models.IntegerField(choices=TYPE_CHOICES, default=1)
    data = JSONField(default=dict)

    def type_to_string(self):
        return dict(self.TYPE_CHOICES)[self.type]
# documents.py

@registry.register_document
class CarDocument(Document):
    type = fields.TextField(attr='type_to_string')
    data = fields.ObjectField(dynamic=True)

    class Index:
        # Name of the Elasticsearch index
        name = 'cars'
        # See Elasticsearch Indices API reference for available settings
        settings = {'number_of_shards': 1,
                    'number_of_replicas': 0}

    class Django:
        model = Car

        fields = [
            'name',
            'color',
            'description',
        ]
# population management command

class Command(BaseCommand):
    def handle(self, *args, **options):
        fake = Faker()
        for x in range(10):
            Car.objects.create(
                name=fake.first_name,
                color=fake.safe_color_name(),
                description='with data dyn',
                type=random.choice(list(dict(Car.TYPE_CHOICES).keys())),
                data={
                    'country': fake.country(),
                    'contact_person': fake.first_name(),
                    'info': {'word': fake.word()},
                    'items': [{'name': fake.company(), 'address': fake.address()} for x in range(5)]
                }
            )
@safwanrahman
Copy link
Collaborator

You should use prepare_ method to generate the data.
Adding the following function in document should work. currently we are not supporting PostgreSQL specific fields, but we are in process to support them.

def prepare_data(self, instance):
    return dict(instance.data)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants