0

我创建了一个自定义字段,允许用户传入字典。该字典在我的数据库中保存为字符串。这是我的 models.py 类的主要部分。

class OptionsField(models.Field):
    description = 'All options'
    #__metaclass__ = models.SubfieldBase

    def __init__(self, *args, **kwargs):
        kwargs['max_length'] = 2048
        kwargs['unique'] = False
        kwargs['null'] = True 
        super(OptionsField, self).__init__(*args, **kwargs) 

    def db_type(self, connection):
        return 'varchar(2048)'

    #Transforms database values to a python dictionary     
    def to_python(self, value): 
        if isinstance(value, dict):
            return value
        together = value.split(' \n')
        returnDictionary = {}
        for item in together:
            dictionaryField = item.split(' : ')
            returnDictionary[dictionaryField[0]] = dictionaryField[1]
        return returnDictionary

    #Transforms a python dictionary to database-compatible values (string)    
    def get_prep_value(self, dict): 
        databaseList = [] 
        print dict
        for key, value in dict.iteritems():
            listValue = ' : '.join([str(key), str(value)])
            databaseList.append(listValue)
        databaseList.sort()
        return ' \n'.join(databaseList) 
-------------------------------END OF CUSTOM FIELD---------------------

class MyModel(models.Model):
    options = OptionsField()

    class Meta:
        app_label = 'testingDB' 

在我的主要内容中,我可以执行以下操作

dictionary = {'a':'b', 'c':'d'}
example = MyModel(options = dictionary) 
example.save() 

example.options['ZZ'] = 'z'
example.options['a'] = 'grr'

example.save()

第一次保存将以下内容放入数据库:

+----+--------+
| id | options| 
+----+--------+
|  1 | a : b  |  
|    | c : d  | 
+----+--------+

第二次保存将上述内容更改为:

+----+--------+
| id | options| 
+----+--------+
|  1 | a : grr|  
|    | c : d  | 
|    | ZZ : z |
+----+--------+    

我如何在这个数据库中搜索呢?如果我做类似的事情 test=MyModel.objects.filter(options['a'] = 'b')

我得到了一个SyntaxError: Keyword can't be an expression 我假设我必须创建方法 get_prep_lookup,并且我已经尝试了很多东西,但它似乎不起作用。

文档:https ://docs.djangoproject.com/en/1.4/howto/custom-model-fields/

4

2 回答 2

2

我想我想通了。对于其他希望在 Django 的主程序中使用字典的人来说,这就是我必须做的。

首先,我必须取消注释

__metaclass__ = models.SubfieldBase

上面的行确保该to_python方法被自动调用。(我不完全理解,但在我附加的文档链接中进行了解释)。

get_prep_lookup之后我必须在 Field 类中完成该方法。这是出于搜索目的。这就是我所做的一切:

def get_prep_lookup(self, lookup_type, value):
    #value is a dictionary, eg: {'a': 'b', 'c':'d'}
    if lookup_type == 'exact':
        return self.get_prep_value(value) #this returns a 'database' string
    if lookup_type == 'contains':
        return self.get_prep_value(value) 
    if lookup_type == 'icontains':
        return self.get_prep_value(value) 
    else:
        raise TypeError('Lookup type %r not supported.' % lookup_type) 

def get_internal_type(self): 
#when creating the database, it'll make the columns CharFields
    return 'CharField'

为了使用该类,我必须在主程序的搜索过滤器中进行一些修改;我不得不通过一本字典。

#First find all objects that contain the following dictionary 
#Because it's icontains, I could also search with {'A':'b'}, 
#as it's case insensitive. __contains isn't case sensitive
test = MyModel.objects.filter(options__icontains = {'a':'b'})
#Note: could've used 'get' instead of filter above, 
#as I know that just one value has dict value {'a':'b'}

#Change as desired
test[0].options['a'] = 'grr'
test[0].options['ZZ'] = 'z'

#save
test[0].save() 

这就是我获得第二张桌子的方式。

请注意,如果您错过了 __icontains 并且只写filter(options = {'a':'b'})了这将搜索只有字典值{'a':'b'}而没有其他内容的条目。另一个注意事项是,当然,您可以使用更大的字典进行搜索,它会起作用。

希望这会帮助一些人:)

于 2012-07-20T15:12:52.243 回答
1

您无法使用数据库中的键进行搜索,因为数据库只保存一个字符串,您可以做的是为您的表构建一个管理器来帮助处理查询,也许使用正则表达式搜索可能会有所帮助,例如:

MyModel.objects.filter(options__regex=r'a : b')
MyModel.objects.filter(options__regex=r'.*c : d')

这些可以是您的正常查询,您可以通过经理获取并使用该信息。

现在有一个流行的库用于在 python 类中保存字典,它会腌制你的 dict,我建议使用它。

于 2012-07-19T03:05:49.563 回答