A pickled object field for Django

Overview

django-picklefield

License Latest Version Build Status Coverage Status Supported Python Versions Wheel Status

About

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

The implementation is taken and adopted from Django snippet #1694 by Taavi Taijala, which is in turn based on Django snippet #513 by Oliver Beattie.

django-picklefield is available under the MIT license.

Usage

First of all, you need to have django-picklefield installed; for your convenience, recent versions should be available from PyPI.

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()

Notes

If you need to serialize an object with a PickledObjectField for transmission to the browser, you may need to subclass the field and override the value_to_string() method. Currently pickle fields are serialized as base64-encoded pickles, which allows reliable deserialization, but such a format is not convenient for parsing in the browser. By overriding value_to_string() you can choose a more convenient serialization format.

Fields now accept the boolean key word argument copy, which defaults to True. The copy is necessary for lookups to work correctly. If you don't care about performing lookups on the picklefield, you can set copy=False to save on some memory usage. This an be especially beneficial for very large object trees.

Running tests

The full test suite can be run with Tox:

>>> pip install tox
>>> tox

Original notes

Here are the notes by taavi223, the original author:

Incredibly useful for storing just about anything in the database (provided it is Pickle-able, of course) when there isn't a 'proper' field for the job.

PickledObjectField is database-agnostic, and should work with any database backend you can throw at it. You can pass in any Python object and it will automagically be converted behind the scenes. You never have to manually pickle or unpickle anything. Also works fine when querying; supports exact, in, and isnull lookups. It should be noted, however, that calling QuerySet.values() will only return the encoded data, not the original Python object.

This PickledObjectField has a few improvements over the one in snippet #513.

This one solves the DjangoUnicodeDecodeError problem when saving an object containing non-ASCII data by base64 encoding the pickled output stream. This ensures that all stored data is ASCII, eliminating the problem.

PickledObjectField will now optionally use zlib to compress (and uncompress) pickled objects on the fly. This can be set per-field using the keyword argument "compress=True". For most items this is probably not worth the small performance penalty, but for Models with larger objects, it can be a real space saver.

You can also now specify the pickle protocol per-field, using the protocol keyword argument. The default of 2 should always work, unless you are trying to access the data from outside of the Django ORM.

Worked around a rare issue when using the cPickle and performing lookups of complex data types. In short, cPickle would sometimes output different streams for the same object depending on how it was referenced. This of course could cause lookups for complex objects to fail, even when a matching object exists. See the docstrings and tests for more information.

You can now use the isnull lookup and have it function as expected. A consequence of this is that by default, PickledObjectField has null=True set (you can of course pass null=False if you want to change that). If null=False is set (the default for fields), then you wouldn't be able to store a Python None value, since None values aren't pickled or encoded (this in turn is what makes the isnull lookup possible).

You can now pass in an object as the default argument for the field without it being converted to a unicode string first. If you pass in a callable though, the field will still call it. It will not try to pickle and encode it.

You can manually import dbsafe_encode and dbsafe_decode from fields.py if you want to encode and decode objects yourself. This is mostly useful for decoding values returned from calling QuerySet.values(), which are still encoded strings.

Note: If you are trying to store other django models in the PickledObjectField, please see the comments for a discussion on the problems associated with doing that. The easy solution is to put django models into a list or tuple before assigning them to the PickledObjectField.

Update 9/2/09: Fixed the value_to_string method so that serialization should now work as expected. Also added deepcopy back into dbsafe_encode, fixing #4 above, since deepcopy had somehow managed to remove itself. This means that lookups should once again work as expected in all situations. Also made the field editable=False by default (which I swear I already did once before!) since it is never a good idea to have a PickledObjectField be user editable.

Changes

Changes in version 3.0.0

  • Allowed default pickle protocol to be overriden using the PICKLEFIELD_DEFAULT_PROTOCOL setting.
  • Dropped support for Python 2.
  • Added testing against Django 3.0.
  • Dropped support for Django 1.11.

Changes in version 2.1.0

  • Added official support for Django 2.2 (thanks to joehybird).
  • Dropped support for Django 2.0 and 2.1 (thanks to joehybird).
  • Dropped support for Python 3.4 (thanks to joehybidd).

Changes in version 2.0.0

  • Silenced RemovedInDjango30Warning warnings on Django 2.0+ (thanks to canarduck).
  • Restructured project directories.
  • Disallowed the usage of empty strings for PickledObjectField. That makes .save(), .create(), etc. raise IntegrityError if null is not True and no default value was specified like built-in fields do (thanks to Attila-Mihaly Balazs).
  • Added a check for mutable default values to PickledObjectField.

Changes in version 1.1.0

  • Added support for Django 2.1 and dropped support for Django < 1.11.

Changes in version 1.0.0

  • Added a new option to prevent a copy of the object before pickling: copy=True
  • Dropped support for Django 1.4
  • Dropped support for Django 1.7
  • Dropped support for Python 3.2
  • Added support for Python 3.6

Changes in version 0.3.2

  • Dropped support for Django 1.3.
  • Dropped support for Python 2.5.
  • Silenced deprecation warnings on Django 1.8+.

Changes in version 0.3.1

  • Favor the built in json module (thanks to Simon Charette).

Changes in version 0.3.0

  • Python 3 support (thanks to Rafal Stozek).

Changes in version 0.2.0

  • Allow pickling of subclasses of django.db.models.Model (thanks to Simon Charette).

Changes in version 0.1.9

  • Added connection and prepared parameters to get_db_prep_value() too (thanks to Matthew Schinckel).

Changes in version 0.1.8

  • Updated link to code repository.

Changes in version 0.1.7

  • Added connection and prepared parameters to get_db_prep_lookup() to get rid of deprecation warnings in Django 1.2.

Changes in version 0.1.6

Changes in version 0.1.5

  • Added support for South.
  • Changed default to null=False, as is common throughout Django.

Changes in version 0.1.4

  • Updated copyright statements.

Changes in version 0.1.3

  • Updated serialization tests (thanks to Michael Fladischer).

Changes in version 0.1.2

  • Added Simplified BSD licence.

Changes in version 0.1.1

  • Added test for serialization.
  • Added note about JSON serialization for browser.
  • Added support for different pickle protocol versions (thanks to Michael Fladischer).

Changes in version 0.1

  • First public release.

Feedback

There is a home page <http://github.com/gintas/django-picklefield> with instructions on how to access the code repository.

Send feedback and suggestions to [email protected] .

Comments
  • Allow skipping the copy step of encoding

    Allow skipping the copy step of encoding

    I've also dropped tox testing for unsupported django and python versions, while adding in python 3.6 testing. I'm not terribly concerned about the supported versions, but figured I'd do some cleanup while I was there. I can remove that specific commit if you'd prefer to leave the versions alone.

    opened by jarshwah 14
  • v0.3.2 breaks Django 1.8.4

    v0.3.2 breaks Django 1.8.4

    Since release v0.3.2, tests for my own project with Django 1.8.4 on Python 2.7 and 3.4 fail. Tests with 1.7.10 seem unaffected.

    I will have to look at the code, but from my test log it looks like all results return the integer 1, instead of the actual field value.

    opened by Koed00 11
  • Updated DEFAULT_PROTOCOL to 3.

    Updated DEFAULT_PROTOCOL to 3.

    Protocol version 3 was added in Python 3.0. It has explicit support for bytes objects and cannot be unpickled by Python 2.x. This was the default protocol in Python 3.0–3.7.

    Not sure it dropping PY2 is on the cards now that it's EOL but, if so I think it would be fair to bump the default protocol version.

    WIP because they'll be lots that breaks on tox/travis. I will check back on that later.

    opened by carltongibson 10
  • Added Joblib pickle methods

    Added Joblib pickle methods

    Thank for this project.

    I needed to use the joblib pickle methods for numpy/pandas/scikit-learn. As explained here, this method is more efficient for this kind of object.

    So:

    • I added a JobLibPickledObjectField
    • I created BasePickledObjectFieldwhich is the parent class of PickledObjectField and JobLibPickledObjectField
    • I subclassed the existing PickledObjectFieldCheckTests to create JobLibPickledObjectFieldCheckTests

    In few words, the existing API isn't changed, and the new field has the same behavior than the old one.

    opened by ZuluPro 6
  • Default field value not working in Django 3

    Default field value not working in Django 3

    For some reason after this commit in Django 3 I can no longer use default values for PickledObjectField in MySQL, I get the following error:

    django.db.utils.OperationalError: (1101, "BLOB, TEXT, GEOMETRY or JSON column 'my_field' can't have a default value")
    

    The error only occurs in MySQL 8.0.13+ (as mentioned in the commit) but the thing is that defaults has worked for me in Django 1.11-2.2 with MySQL 5.6-8.0.19 so I'm not sure why it has been constrained in Django 3.

    Has anyone else had any experience with this or know a way around it?

    (Maybe this is an issue more suited for Django itself but I thought I would start here since this is what I'm using for the fields that fails)

    opened by OskarPersson 5
  • Removed dependence on `six` library

    Removed dependence on `six` library

    Currently, picklefield requires six for singe one-line function with_metaclass.

    I'm not sure whether such change is desirable, but I think removing nearly-unnecessary dependency might be convenient.

    opened by al42and 5
  • Queryset.query not pickled correctly when saving PickledObjectField since Django 3.0

    Queryset.query not pickled correctly when saving PickledObjectField since Django 3.0

    trying to pickle a Query object. it seems like the default values is not being serialized:

    DB is postgres 10.1 django 3.0.3 python 3.7.4

    eligible_team_query = PickledObjectField(default=Team.objects.all().query)

      File "/usr/local/lib/python3.7/site-packages/django/db/backends/utils.py", line 86, in _execute
        return self.cursor.execute(sql, params)
    psycopg2.errors.SyntaxError: subquery must return only one column
    LINE 1: ...query", "eligible_team_query") VALUES ('u17', '', (SELECT "p...
    

    Originally posted by @flokain in https://github.com/gintas/django-picklefield/issues/47#issuecomment-588190697

    opened by flokain 3
  • mutable default value causes issues

    mutable default value causes issues

    There seems to be issues if a mutable default value is used. I'm not sure the best way to handle this, though.

    Example:

    class MyModel(models.Model):
        pickle = PickledObjectField(default={})
    
    x = MyModel()
    x.pickle['a'] = 3
    x.pickle  #  {'a': 3}
    
    y = MyModel()
    y.pickle   # {'a': 3}
    
    opened by tisdall 3
  • django-picklefield slow compared to a naive solution using jsonpickle

    django-picklefield slow compared to a naive solution using jsonpickle

    Hi, i use django-picklefield in a project of mine and noticed that it's quite slow compared to pickling an object using jsonpickle (https://github.com/jsonpickle/jsonpickle), storing the result in a TextField, and unpickling the TextField back into a Python object. Do you know what's up with that?

    I don't have any benchmarks to show for at present, but i'll make some when i get a chance. Thought i'd raise the issue now, though.

    opened by araichev 3
  • Adding ppc64le architecture support on travis-ci

    Adding ppc64le architecture support on travis-ci

    Hi, I had added ppc64le(Linux on Power) architecture support on travis-ci in the branch and looks like its been successfully added. I believe it is ready for the final review and merge. The travis ci build logs can be verified from the link below. https://travis-ci.com/github/kishorkunal-raj/django-picklefield/builds/188998356

    Reason behind running tests on ppc64le: This package is included in the ppc64le versions of RHEL and Ubuntu - this allows the top of tree to be tested continuously as it is for Intel, making it easier to catch any possible regressions on ppc64le before the distros begin their clones and builds. This reduces the work in integrating this package into future versions of RHEL/Ubuntu.

    Please have a look.

    Regards, Kishor Kunal Raj

    opened by kishorkunal-raj 2
  • Remove compatiblity shims and allow default pickle override through a setting.

    Remove compatiblity shims and allow default pickle override through a setting.

    @carltongibson I replaced the DEFAULT_PROTOCOL bump by a new setting instead as this bump breaks backward compatibility of __exact lookups since the string representation of pickles changes.

    We could have documented it as a backward incompatible change but I feared some folks might blindly upgrade and end up with a database that is a mix of protocol 2 and 3 pickles which would break __exact and friends.

    By introducing this new PICKLEFIELD_DEFAULT_PROTOCOL setting it should be possible for users to upgrade to the version they seem for fit for their use case (even > 3) without breaking backward compatibility.

    opened by charettes 2
  • Django 3.2 test failure due to DEFAULT_AUTO_FIELD

    Django 3.2 test failure due to DEFAULT_AUTO_FIELD

    Django 3.2 is emitting additional warnings, which is causing two tests to fail.

    [   28s] ======================================================================
    [   28s] FAIL: test_mutable_default_check (tests.tests.PickledObjectFieldCheckTests)
    [   28s] ----------------------------------------------------------------------
    [   28s] Traceback (most recent call last):
    [   28s]   File "/home/abuild/rpmbuild/BUILD/django-picklefield-3.0.1/tests/tests.py", line 243, in test_mutable_default_check
    [   28s]     id='picklefield.E001',
    [   28s] AssertionError: Lists differ: [<War[905 chars]001'>, <Warning: level=30, msg="Auto-created p[378 chars]42'>] != [<War[905 chars]001'>]
    [   28s] 
    [   28s] First list contains 1 additional elements.
    [   28s] First extra element 3:
    [   28s] <Warning: level=30, msg="Auto-created primary key used when not defining a primary key type, by default 'django.db.models.AutoField'.", hint="Configure the DEFAULT_AUTO_FIELD setting or the AppConfig.default_auto_field attribute to point to a subclass of AutoField, e.g. 'django.db.models.BigAutoField'.", obj=<class 'tests.tests.PickledObjectFieldCheckTests.test_mutable_default_check.<locals>.Model'>, id='models.W042'>
    [   28s] 
    [   28s] Diff is 2280 characters long. Set self.maxDiff to None to see it.
    [   28s] 
    [   28s] ======================================================================
    [   28s] FAIL: test_non_mutable_default_check (tests.tests.PickledObjectFieldCheckTests)
    [   28s] ----------------------------------------------------------------------
    [   28s] Traceback (most recent call last):
    [   28s]   File "/home/abuild/rpmbuild/BUILD/django-picklefield-3.0.1/tests/tests.py", line 253, in test_non_mutable_default_check
    [   28s]     self.assertEqual(Model().check(), [])
    [   28s] AssertionError: Lists differ: [<Warning: level=30, msg="Auto-created pri[380 chars]42'>] != []
    [   28s] 
    [   28s] First list contains 1 additional elements.
    [   28s] First extra element 0:
    [   28s] <Warning: level=30, msg="Auto-created primary key used when not defining a primary key type, by default 'django.db.models.AutoField'.", hint="Configure the DEFAULT_AUTO_FIELD setting or the AppConfig.default_auto_field attribute to point to a subclass of AutoField, e.g. 'django.db.models.BigAutoField'.", obj=<class 'tests.tests.PickledObjectFieldCheckTests.test_non_mutable_default_check.<locals>.Model'>, id='models.W042'>
    [   28s] 
    [   28s] - [<Warning: level=30, msg="Auto-created primary key used when not defining a primary key type, by default 'django.db.models.AutoField'.", hint="Configure the DEFAULT_AUTO_FIELD setting or the AppConfig.default_auto_field attribute to point to a subclass of AutoField, e.g. 'django.db.models.BigAutoField'.", obj=<class 'tests.tests.PickledObjectFieldCheckTests.test_non_mutable_default_check.<locals>.Model'>, id='models.W042'>]
    [   28s] + []
    
    opened by jayvdb 0
  • Add custom loads and dumps settings

    Add custom loads and dumps settings

    This allows me to customize the loads and dumps via settings to use dill instead of the default pickle. If no setting exists, defaults to pickle.loads and pickle.dumps

    eg.

    # settings.py
    PICKLEFIELD_DUMPS = 'dill.dumps'
    PICKLEFIELD_LOADS = 'dill.loads'
    
    opened by massover 6
  • Package cannot be built from source without installing Django first

    Package cannot be built from source without installing Django first

    On systems where no binary build is available, django-picklefield cannot be installed in a clean virtualenv, because it relies on Django being installed at build time

    To reproduce:

    $ mkvirtualenv -p python3.8 test-django-picklefield-build
    $ workon test-django-picklefield-build
    $ pip install --no-binary django-picklefield django-picklefield
    Collecting django-picklefield
      Using cached django-picklefield-3.0.1.tar.gz (9.5 kB)
        ERROR: Command errored out with exit status 1:
         command: /Users/niklas/.virtualenvs/test-django-picklefield/bin/python -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/private/var/folders/zy/5k15xt89127ck1l3sk615l5m0000gn/T/pip-install-7k5uva3e/django-picklefield/setup.py'"'"'; __file__='"'"'/private/var/folders/zy/5k15xt89127ck1l3sk615l5m0000gn/T/pip-install-7k5uva3e/django-picklefield/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' egg_info --egg-base /private/var/folders/zy/5k15xt89127ck1l3sk615l5m0000gn/T/pip-pip-egg-info-m4z3m_ay
             cwd: /private/var/folders/zy/5k15xt89127ck1l3sk615l5m0000gn/T/pip-install-7k5uva3e/django-picklefield/
        Complete output (7 lines):
        Traceback (most recent call last):
          File "<string>", line 1, in <module>
          File "/private/var/folders/zy/5k15xt89127ck1l3sk615l5m0000gn/T/pip-install-7k5uva3e/django-picklefield/setup.py", line 5, in <module>
            import picklefield
          File "/private/var/folders/zy/5k15xt89127ck1l3sk615l5m0000gn/T/pip-install-7k5uva3e/django-picklefield/picklefield/__init__.py", line 3, in <module>
            import django.utils.version
        ModuleNotFoundError: No module named 'django'
        ----------------------------------------
    ERROR: Command errored out with exit status 1: python setup.py egg_info Check the logs for full command output.
    

    The obvious fix is to maintain the version differently, e.g. https://github.com/niklasb/django-picklefield/commit/dc2979840cdb0862ac22ca4b0ab3dc41684720f3

    opened by niklasb 11
  • Cannot use PickleField to save a QuerySet query

    Cannot use PickleField to save a QuerySet query

    This is such a particular case that I do not expect it to be solved... and actually one could argue that the bug is in the Django library.

    Django specifies that if you want to pickle a QuerySet, you must pickle the query https://docs.djangoproject.com/en/3.2/ref/models/querysets/#pickling-querysets

    The problem is that a query has a method "resolve_expression", and in that case, Django skip the call to get_db_prep_save. https://github.com/django/django/blob/3.0.14/django/db/models/sql/compiler.py#L1257

    get_db_prep_save in turn is supposed to call get_db_prep_value responsible for the pickling of the object https://github.com/django/django/blob/3.0.14/django/db/models/fields/init.py#L819

    As a result the query object is not pickled, and Django throws an error because it creates a sub select in the query, etc.

    opened by bmampaey 0
  • Make admin editable widget a TextArea

    Make admin editable widget a TextArea

    I edit PickledObjectField's in admin using editable=True flag where the assigned widget is a textbox. So I have to add the following line to my admin class: formfield_overrides = {PickledObjectField: {'widget': widgets.AdminTextareaWidget}, } I think it'd be nice if this was the default behaviour.

    opened by BarnabasSzabolcs 2
Owner
Gintautas Miliauskas
CTO / co-founder at Mavenoid
Gintautas Miliauskas
Django Pickled Model

Django Pickled Model Django pickled model provides you a model with dynamic data types. a field can store any value in any type. You can store Integer

Amir 3 Sep 14, 2022
MAC address Model Field & Form Field for Django apps

django-macaddress MAC Address model and form fields for Django We use netaddr to parse and validate the MAC address. The tests aren't complete yet. Pa

null 49 Sep 4, 2022
A reusable Django model field for storing ad-hoc JSON data

jsonfield jsonfield is a reusable model field that allows you to store validated JSON, automatically handling serialization to and from the database.

Ryan P Kilby 1.1k Jan 3, 2023
A Django application that provides country choices for use with forms, flag icons static files, and a country field for models.

Django Countries A Django application that provides country choices for use with forms, flag icons static files, and a country field for models. Insta

Chris Beaven 1.2k Jan 7, 2023
A django model and form field for normalised phone numbers using python-phonenumbers

django-phonenumber-field A Django library which interfaces with python-phonenumbers to validate, pretty print and convert phone numbers. python-phonen

Stefan Foulis 1.3k Dec 31, 2022
A Django application that provides country choices for use with forms, flag icons static files, and a country field for models.

Django Countries A Django application that provides country choices for use with forms, flag icons static files, and a country field for models. Insta

Chris Beaven 1.2k Dec 31, 2022
Custom Django field for using enumerations of named constants

django-enumfield Provides an enumeration Django model field (using IntegerField) with reusable enums and transition validation. Installation Currently

5 Monkeys 195 Dec 20, 2022
Location field and widget for Django. It supports Google Maps, OpenStreetMap and Mapbox

django-location-field Let users pick locations using a map widget and store its latitude and longitude. Stable version: django-location-field==2.1.0 D

Caio Ariede 481 Dec 29, 2022
A django model and form field for normalised phone numbers using python-phonenumbers

django-phonenumber-field A Django library which interfaces with python-phonenumbers to validate, pretty print and convert phone numbers. python-phonen

Stefan Foulis 1.3k Dec 31, 2022
A drop-in replacement for django's ImageField that provides a flexible, intuitive and easily-extensible interface for quickly creating new images from the one assigned to the field.

django-versatileimagefield A drop-in replacement for django's ImageField that provides a flexible, intuitive and easily-extensible interface for creat

Jonathan Ellenberger 490 Dec 13, 2022
Django URL Shortener is a Django app to to include URL Shortening feature in your Django Project

Django URL Shortener Django URL Shortener is a Django app to to include URL Shortening feature in your Django Project Install this package to your Dja

Rishav Sinha 4 Nov 18, 2021
Tweak the form field rendering in templates, not in python-level form definitions. CSS classes and HTML attributes can be altered.

django-widget-tweaks Tweak the form field rendering in templates, not in python-level form definitions. Altering CSS classes and HTML attributes is su

Jazzband 1.8k Jan 2, 2023
Resolve form field arguments dynamically when a form is instantiated

django-forms-dynamic Resolve form field arguments dynamically when a form is instantiated, not when it's declared. Tested against Django 2.2, 3.2 and

DabApps 108 Jan 3, 2023
Per object permissions for Django

django-guardian django-guardian is an implementation of per object permissions [1] on top of Django's authorization backend Documentation Online docum

null 3.3k Jan 4, 2023
Meta package to combine turbo-django and stimulus-django

Hotwire + Django This repository aims to help you integrate Hotwire with Django ?? Inspiration might be taken from @hotwired/hotwire-rails. We are sti

Hotwire for Django 31 Aug 9, 2022
django-reversion is an extension to the Django web framework that provides version control for model instances.

django-reversion django-reversion is an extension to the Django web framework that provides version control for model instances. Requirements Python 3

Dave Hall 2.8k Jan 2, 2023
Django-environ allows you to utilize 12factor inspired environment variables to configure your Django application.

Django-environ django-environ allows you to use Twelve-factor methodology to configure your Django application with environment variables. import envi

Daniele Faraglia 2.7k Jan 7, 2023
Rosetta is a Django application that eases the translation process of your Django projects

Rosetta Rosetta is a Django application that facilitates the translation process of your Django projects. Because it doesn't export any models, Rosett

Marco Bonetti 909 Dec 26, 2022
Cookiecutter Django is a framework for jumpstarting production-ready Django projects quickly.

Cookiecutter Django Powered by Cookiecutter, Cookiecutter Django is a framework for jumpstarting production-ready Django projects quickly. Documentati

Daniel Feldroy 10k Dec 31, 2022