limpyd / redis-limpyd

Provide an easy way to store python objects in Redis, without losing the power and the control of the Redis API
https://redis-limpyd.readthedocs.org/
Do What The F*ck You Want To Public License
72 stars 11 forks source link

Easy to trip uniqeness error #95

Closed stuaxo closed 8 years ago

stuaxo commented 8 years ago

Run the mountainbike example from the github frontpage twice and this happens:

---------------------------------------------------------------------------
UniquenessError                           Traceback (most recent call last)
<ipython-input-11-d40abe4b45be> in <module>()
----> 1 mountainbike = Bike(name="arg")
      2 
      3 mountainbike.wheels.get()

/home/stu/projects/external/redis-limpyd/limpyd/model.py in __init__(self, *args, **kwargs)
    191                 if field.unique and self.exists(**{field_name: value}):
    192                     raise UniquenessError(u"Field `%s` must be unique. "
--> 193                                            "Value `%s` yet indexed." % (field.name, value))
    194                 self._init_fields.add(field_name)
    195 

UniquenessError: Field `name` must be unique. Value `arg` yet indexed.
stuaxo commented 8 years ago

Oooh - this is meant to happen, silly me :)

stuaxo commented 8 years ago

OK, maybe it isn't meant to happen, I'm definitely confused.

twidi commented 8 years ago

Hello

The name field for the Bike object is marked as unique=True, to you cannot create two objects with the same name, so, yes, it is meant to happen.

Why did you thought the opposite?

stuaxo commented 8 years ago

Unfamiliarity with the database, orm and tiredness :)

stuaxo commented 8 years ago

Ah, I remember: I didn't think that Bike(....) would actually save to redis - I assumed an actual .save() command would need to be issued, like some other ORMs.

twidi commented 8 years ago

Limpyd is different, it works at the field level. The model is just here to group fields together, and manage the base of the redis keys.

To confirm that this kind of call does create the "instance", here is the docstring of the RedisModel.__init__:

    def __init__(self, *args, **kwargs):
        """
        Init or retrieve an object storage in Redis.

        Here whats init manages:
        - no args, no kwargs: just instanciate in a python way, no connection to
          redis
        - some kwargs == instanciate, connect, and set the properties received
        - one arg == get from pk
        """

(wow, pretty bad english in there....)

stuaxo commented 8 years ago

This makes sense, I guess due to the nature of Redis. Is there a way to batch changes together ?

twidi commented 8 years ago

yep, limpyd has you covered :)

http://redis-limpyd.readthedocs.io/en/latest/contrib.html#pipelines

But don't forget this (from the doc):

It does not mean that you cannot set many fields in one time in a pipeline, but you must have values not depending of other fields, and, also very important, you cannot update indexable fields ! (so no related fields either, because they are all indexable)

Note that as for the pipeline method, you cannot update indexables fields in the transaction because read commands are used to update them.

stuaxo commented 8 years ago

Cool, cheers :)