Repository: flask-admin/flask-admin

Issue:
[peewee] Using a model with a pre-populated primary key will not save in flask-admin
Consider this simple example, based on [examples/peewee/app.py](https://github.com/flask-admin/flask-admin/blob/master/examples/peewee/app.py):

```
class Post(BaseModel):
    id = peewee.UUIDField(primary_key=True, default=uuid.uuid4)
    title = peewee.CharField(max_length=120)
    text = peewee.TextField(null=False)
    date = peewee.DateTimeField()

    user = peewee.ForeignKeyField(User)

    def __unicode__(self):
        return self.title
```

**Note the UUIIDField** has a primary key with a default value; the default value being a Python function. That means that a primary key exists before the object.

If you attempt to use this model class with the current implementation of flask-admin's peewee functionality, when you create a new row, it will not persist in the database. The reason is this:

`create_model` in [contrib/peewee/view.py](https://github.com/flask-admin/flask-admin/blob/master/flask_admin/contrib/peewee/view.py#L451) does this:

```
            model = self.model()
            form.populate_obj(model)
            self._on_model_change(form, model, True)
            model.save()
```

Usually with Peewee, to explicitly create a new record, you would call self.model.create() or pass `force_insert=True` to model.save(). That's because model.save will see if the foreign key value exists, and attempt to *update* (not insert) a value based on the existence of a value:

```
        if pk_value is not None and not force_insert:
            ...
            rows = self.update(**field_dict).where(self._pk_expr()).execute()
        elif pk_field is None or not self._meta.auto_increment:
            self.insert(**field_dict).execute()
            ...
        else:
            pk_from_cursor = self.insert(**field_dict).execute()
```

So, in other words, if a primary key value has a default value provided by a Python function, when you try to create a *new* record, flask-admin will attempt to *update* a record that doesn't exist.

The simple solution is to add `force_insert` to `model.save` in `create_model()`. Pull request forthcoming.


Discussion:

Resolving patch:
diff --git a/examples/peewee/app.py b/examples/peewee/app.py
--- a/examples/peewee/app.py
+++ b/examples/peewee/app.py
@@ -1,11 +1,11 @@
-from flask import Flask
+import uuid
 
 import peewee
+from flask import Flask
 
 import flask_admin as admin
 from flask_admin.contrib.peewee import ModelView
 
-
 app = Flask(__name__)
 app.config['SECRET_KEY'] = '123456790'
 
@@ -36,6 +36,7 @@ def __unicode__(self):
 
 
 class Post(BaseModel):
+    id = peewee.UUIDField(primary_key=True, default=uuid.uuid4)
     title = peewee.CharField(max_length=120)
     text = peewee.TextField(null=False)
     date = peewee.DateTimeField()
@@ -80,6 +81,7 @@ def index():
 
 if __name__ == '__main__':
     import logging
+
     logging.basicConfig()
     logging.getLogger().setLevel(logging.DEBUG)
 
diff --git a/flask_admin/contrib/peewee/view.py b/flask_admin/contrib/peewee/view.py
--- a/flask_admin/contrib/peewee/view.py
+++ b/flask_admin/contrib/peewee/view.py
@@ -453,7 +453,7 @@ def create_model(self, form):
             model = self.model()
             form.populate_obj(model)
             self._on_model_change(form, model, True)
-            model.save()
+            model.save(force_insert=True)
 
             # For peewee have to save inline forms after model was saved
             save_inline(form, model)


Test patch: