简体   繁体   中英

Django Models - How to store fields in a dict

I have a fairly simple user-model perfectly working. In order to reduce code redundancy, I try to store fields inside a dictory for reasons you can easily guess.

Example:

def get_social_token(self,social_net=""):
   return self.social_dict[social_net]["token"]

If I don't do such a structure I must do some "if/then ... elif... else". And of course I need to modify my code whenever I decide to add a new social network to my app.

I have tried two different approaches, both of them give me the same result:

  • No error
  • No field is actually detected and created in the DB

I'd like to mention that if I use a "conventional manner" to implement this behaviour such as:

  • twitter_social_token = EncryptedCharField(max_length=500, default='', blank=True, null=True)

It perfectly works, so it comes from the use of a dictionary.

Any idea to solve this ? Btw. I would prefer avoiding using a new model and a foreign key... Only a One-to-One association, I would prefer not having to perform any "join" or select in another table...

Bellow, you'll find the two attempts I made which doesn't work (and I don't know why):

First attempt:

social_fields = {
    'twitter' : {
        'token'  : EncryptedCharField(max_length=500, default='', blank=True, null=True),
        'secret' : EncryptedCharField(max_length=500, default='', blank=True, null=True)
    },
    'facebook' : {
        'token'  : EncryptedCharField(max_length=500, default='', blank=True, null=True),
        'secret' : EncryptedCharField(max_length=500, default='', blank=True, null=True)
    },
    'gplus' : {
        'token'  : EncryptedCharField(max_length=500, default='', blank=True, null=True),
        'secret' : EncryptedCharField(max_length=500, default='', blank=True, null=True)
    },
    'linkedin' : {
        'token'  : EncryptedCharField(max_length=500, default='', blank=True, null=True),
        'secret' : EncryptedCharField(max_length=500, default='', blank=True, null=True)
    },
}

Second attempt:

social_tokens = dict()

social_tokens["twitter"] = dict()
social_tokens["facebook"] = dict()
social_tokens["linkedin"] = dict()
social_tokens["gplus"] = dict()

social_tokens["twitter"]["token"] = EncryptedCharField(max_length=500, default='', blank=True, null=True)
social_tokens["twitter"]["secret"] = EncryptedCharField(max_length=500, default='', blank=True, null=True)

social_tokens["facebook"]["token"] = EncryptedCharField(max_length=500, default='', blank=True, null=True)
social_tokens["facebook"]["secret"] = EncryptedCharField(max_length=500, default='', blank=True, null=True)

social_tokens["linkedin"]["token"] = EncryptedCharField(max_length=500, default='', blank=True, null=True)
social_tokens["linkedin"]["secret"] = EncryptedCharField(max_length=500, default='', blank=True, null=True)

social_tokens["gplus"]["token"] = EncryptedCharField(max_length=500, default='', blank=True, null=True)
social_tokens["gplus"]["secret"] = EncryptedCharField(max_length=500, default='', blank=True, null=True)

Thanks for the help dear friends,

Jonathan

As far as I know, without using join you have 3 different way:

django-picklefield provides an implementation of a pickled object field. Such fields can contain any picklable objects.

From their documentation, to use; just define a field in your model:

>>> from picklefield.fields import PickledObjectField
... class SomeObject(models.Model):
...     args = PickledObjectField()

and assign whatever you like (as long as it's picklable) to the field:

>>> obj = SomeObject()
>>> obj.args = ['fancy', {'objects': 'inside'}]
>>> obj.save()

django-jsonfield is a reusable Django field that allows you to store validated JSON in your model. It silently takes care of serialization. To use, simply add the field to one of your models.

To use, just install the package, and then use the field:

from django.db import models
import jsonfield

class MyModel(models.Model):
    the_json = jsonfield.JSONField()

A field for storing mappings of strings to strings. The Python data type used is a dict.

from django.contrib.postgres.fields import HStoreField
from django.db import models

class Dog(models.Model):
    name = models.CharField(max_length=200)
    data = HStoreField()

Dog.objects.create(name='Rufus', data={'breed': 'labrador'})

It would definetely works, however as you seen I use Encrypted Fields in order to keep secure my user's tokens and secret_tokens.

I hope this not a bad thing to do or some kind of anti-pattern. Feel free to share a better way doing this.

I just found a workaround which actually works exactely the way I wanted, even if it's not super efficiant from my point of view.

Here is you access the data:

from application.models import *
tmp_user = CustomUser.objects.get(username="random_username")

print (getattr(tmp_user, tmp_user.social_fields["twitter"]["token"]))
>>> e72e16c7e42f292c6912e7710c838347ae178b4a ### This token is a fake !

Here is how managed to do this:

twitter_token          = EncryptedCharField(max_length=500, default='', blank=True, null=True)
twitter_token_secret   = EncryptedCharField(max_length=500, default='', blank=True, null=True)

facebook_token         = EncryptedCharField(max_length=500, default='', blank=True, null=True)
facebook_token_secret  = EncryptedCharField(max_length=500, default='', blank=True, null=True)

gplus_token            = EncryptedCharField(max_length=500, default='', blank=True, null=True)
gplus_token_secret     = EncryptedCharField(max_length=500, default='', blank=True, null=True)

linkedin_token         = EncryptedCharField(max_length=500, default='', blank=True, null=True)
linkedin_token_secret  = EncryptedCharField(max_length=500, default='', blank=True, null=True)

social_fields = {
    'twitter' : {
        'token'  : "twitter_token",
        'secret' : "twitter_token_secret"
    },
    'facebook' : {
        'token'  : "facebook_token",
        'secret' : "facebook_token_secret"
    },
    'gplus' : {
        'token'  : "gplus_token",
        'secret' : "gplus_token_secret"
    },
    'linkedin' : {
        'token'  : "linkedin_token",
        'secret' : "linkedin_token_secret"
    },
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM