Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django model choices make no effect on saved data

Following the django documentation I try to make a choices field in my models.py:

class MyModel(Model):

    ACTION_CHOICES = (
        ('d', 'delete'),
        ('c', 'create'),
        ('u', 'update'),
    )

    action = CharField(max_length=1, choices=ACTION_CHOICES)

But when I run it with

 action = MyModel(action='create')
 action.save()

and check the database the action is not c, but create. Furthermore even restriction to max_length doesn't affect on it. Ok, I moved on and tried to make it in this way:

models.py

class MyModel(Model):

    ACTION_CHOICES = (
        (1, 'delete'),
        (2, 'create'),
        (3, 'update'),
    )

    action = IntegerField(max_length=1, choices=ACTION_CHOICES)

code.py:

action = MyModel(action='create')
action.save()

But I got an error that str field can't be saved like int (database has the int field, but MyModel.action is str) What Do I miss here? Aren't choices supposed to convert value on save?

Best regards,

like image 433
deathangel908 Avatar asked Mar 05 '15 14:03

deathangel908


2 Answers

There are several questions in your post:

1) The choices can only restrict what can be entered through a Django form. When you manually instantiate your object you can insert any value. So

action = MyModel(action='create')

actually inserts the string create into the action column.

2) Normally max_length should stop you from inserting a string longer than 1 character into that column, but I guess you are using SQLite which has no restriction on VARCHAR lengths.

3) Django has no easy conversion from the display values to choice keys. You can have a look at django-model-utils for a wrapper on choices.

like image 66
Selcuk Avatar answered Sep 28 '22 21:09

Selcuk


When you define choices

ACTION_CHOICES = (
    (1, 'delete'),
    (2, 'create'),
    (3, 'update'),
)

the values stored in the db are 1, 2, 3, while 'delete', 'create' etc.. are just labels, just to explain, the prev choices results in such select input element:

<select>
    <option value="1">delete</option>
    <option value="2">create</option>
    <option value="3">update</option>
</select>

Choices are not supposed to convert value on save, are supposed to map db values with labels, and used when rendering the form widget and when retrieving the field representation (get_field_display). But if you set directly the value of a column it doesn't play a role.

If you want to use "talking keys" you can define them as class properties, like

class MyModel(models.Model):
    DELETE_ACTION = 1
    CREATE_ACTION = 2
    UPDATE_ACTION = 3

    ACTION_CHOICES = (
        (DELETE_ACTION, 'delete'),
        (CREATE_ACTION, 'create'),
        (UPDATE_ACTION, 'update'),
    )

Then you can do

action = MyModel(action=MyModel.CREATE_ACTION)

and it would be fine

like image 41
abidibo Avatar answered Sep 28 '22 22:09

abidibo