doableware / djongo

Django and MongoDB database connector
https://www.djongomapper.com
GNU Affero General Public License v3.0
1.88k stars 355 forks source link

Cannot find proper documentation for DictField #237

Open appunni-m opened 5 years ago

appunni-m commented 5 years ago

Documentation doesn't include use cases of DictField

I searched a lot, but even under https://djongo.readthedocs.io/docs/dict-field/, I couldn't find it's use cases and examples. As I have never used Djongo, but used a lot of Django I suggest for adding more example use cases for DictField. I came looking for Djongo for a specific use case of storing large amount of dynamically created data with dynamic schema according to configuration written using MySQL Django ORM. Based on the configuration the data could have dynamic schema, (JSON), and I would like to store it in mongodb.

robertour commented 5 years ago

I didn't find any documentation either, but in principle you can just use it as any other field, I have used just like this:

models.DictField(default=None, blank=True, null=True)

or

models.DictField(default={}, blank=True, null=True)

This will simply store a dictionary or a list of values in the field.

It is important to relate this to the EmbeddedModelField. It does kind of the same say, and it is documented. I found that one difference between EmbeddedModelField and DictField is that the EmbeddedModelField requires you to define the Django model with the respective fields, whereas the DictField is completely flexible, it is just a dictionary without any saying about the structure (potentially, all dictionaries could be different).

Nevertheless, I could not use DictField and ListField in the Django admin, so you probably want to exclude those fields (I ll be glad if somebody post a solution to it)

class MyModelAdmin(admin.ModelAdmin):
    exclude = ('my_dictfield')
appunni-m commented 5 years ago

@robertour exclude must be an iterable not a string, you forgot a comma. Okay. I had finally made it work. I am currently showing it in admin also as readonly field.

class VersionedData(models.Model):
    """Versioned Data contains versioning"""
    _id = models.ObjectIdField()
    data = models.DictField(default={})
    timestamp = models.DateTimeField(auto_now_add=True)
    hash_value = models.CharField(max_length=129, db_index=True, null=False)
    meta_data = models.EmbeddedModelField(
        model_container=MetaData
    )

This is how model looks like. admin.py


from .models import VersionedData
import json
from django.core.serializers.json import DjangoJSONEncoder
from django.contrib import admin
from pygments import highlight
from pygments.lexers import get_lexer_by_name
from pygments.formatters import get_formatter_by_name
from django.utils.html import mark_safe

json_lexer = get_lexer_by_name("json")
html_formatter = get_formatter_by_name("html")

class ReadOnlyAdmin(admin.ModelAdmin):
    """Provides a read-only view of a model in Django admin."""
    readonly_fields = []

    def change_view(self, request, object_id, extra_context=None, **kwargs):
        """ customize add/edit form to remove save / save and continue """
        extra_context = extra_context or {}
        extra_context['show_save_and_continue'] = False
        extra_context['show_save'] = False
        return super(ReadOnlyAdmin, self).change_view(
            request, object_id, extra_context=extra_context
        )

    def get_actions(self, request):
        actions = super(ReadOnlyAdmin, self).get_actions(request)
        if 'delete_selected' in actions:
            del actions['delete_selected']
        return actions

    def get_readonly_fields(self, request, obj=None):
        return list(self.readonly_fields) + \
           [field.name for field in obj._meta.fields] + \
           [field.name for field in obj._meta.many_to_many]

    def has_add_permission(self, request):
        return False

    def has_delete_permission(self, request, obj=None):
        return False

@admin.register(VersionedData)
class VersionedDataAdmin(ReadOnlyAdmin):

    formats = (JSON,)

    list_display = ("_id", "timestamp", "hash_value", "meta_data")

    fields = ('hash_value', 'view_meta_data', 'view_data', 'timestamp')

    def view_data(self, obj):
        output = json.dumps(obj.data, indent=4, cls=DjangoJSONEncoder)
        return mark_safe(
            highlight(output, json_lexer, html_formatter)
        )

    view_data.empty_value_display = 'Empty'
    view_data.short_description = "Main Data"

    def view_meta_data(self, obj):
        output = json.dumps(obj.meta_data.dict(), indent=4,
                            cls=DjangoJSONEncoder)
        return mark_safe(
            highlight(output, json_lexer, html_formatter)
        )

    view_meta_data.empty_value_display = 'Empty'
    view_meta_data.short_description = "Meta Data"

    def get_readonly_fields(self, request, obj=None):
        return list(self.readonly_fields) + \
           [field.name for field in obj._meta.fields] + \
           [field.name for field in obj._meta.many_to_many] + \
           ['view_meta_data', 'view_data']```
rjsnh1522 commented 4 years ago

Hi,

I am having some difficulty in using this dict field.

from djongo import models
class BillData(models.Model):
    registrar_info = models.DictField(default={}, blank=True, null=False)
    registrant_contacts = models.DictField(default={}, blank=True, null=False)
    billing_contacts = models.DictField(default={}, blank=True, null=False)

in mongodb data is Object filed with key value But when i try to get the data from my model it gives me an orderedDict but its in string like below

"OrderedDict([('email', 'manowaaxsdarrr@yahoo.co.jp'), ('name', 'Uo Mano'), ('organization', 'Uo Mano'), ('address', 'Jingumae'), ('city', 'Shibuya-ku'), ('state', 'Tokyo'), ('zip', '150-0001'), ('country', 'JAPAN'), ('fax', ''), ('fax_ext', ''), ('telephone', '810369692251.0'), ('telephone_ext', '')])"

class GetBillDetails(TemplateView):
    def get(self, request, *args, **kwargs):
        template_name = 'whois/bill-details.html'
        id = kwargs['pk']
        slug = kwargs['slug']
        bill = BillData.objects.get(pk=id)
        bill_detail = BillDataSerializer(bill).data
        ctx = dict()
        data = {}
        data['bill'] = bill_detail
        for i in bill_detail.keys():
            data[i] = bill_detail[i]
        data['tab_details'] = ['registrant_contacts', 'administrative_contacts',
                          'billing_contacts', 'technical_contacts', 'zone_contacts']
        ctx['data'] = data
        for k in data['tab_details']:
         # here if you check the data returned is orderedDict which is in string
            for g in data['bill'][k].items():
                print(g)

        return render_to_response(template_name, {'ctx': ctx})

I am not sure why it is happening .

Usama0121 commented 4 years ago

Hi, Is it possible to filter on dict key values

lets say the dictionary stored in db is

data={'key':'value'}

how can I filter it like this

model.objects.filter(data__key__icontains="val")
riyasm-mava commented 4 years ago

AttributeError: module 'djongo.models' has no attribute 'DictField'. I am using 'Djongo-1.3.2'.

skyshy0707 commented 4 years ago

If i use djongo library as my NOSQL database, when i discovered that DictField is not provide in djongo.models

from djongo import models as models 

p = models.DictField()

then i got a AttributeError: module 'djongo.models' has no attribute 'DictField'

But i find type field Aggregate, but don't find any examples, which describes it.

What for does the field type Aggregate use? (But i would prefer use dictionary as more dynamic type)

skyshy0707 commented 4 years ago

AttributeError: module 'djongo.models' has no attribute 'DictField'. I am using 'Djongo-1.3.2'.

it is not supported in djongo anymore, but you may try use another db, say: https://github.com/MongoEngine/django-mongoengine

Raznak commented 4 years ago

You can use the JSONField instead. JSONField will accept Array or Dict

skyshy0707 commented 4 years ago

Hi=) Thanks for your response!

You can use the JSONField instead. JSONField will accept Array or Dict

I.e. I don't need to perform a dict to json to use this type field (JSONField)?

Because for rendering html in

{% block content %}

{{ amodel.field }}

{% endblock %}

in {{ }} are placed only variable in accordance with template language