Eric Pauley
Eric Pauley

Reputation: 1779

Posting models with ForeignKeys results in integrityerror

I'm trying to add a comment model to another model on my site. Here's the Resource:

class CommentResource(ModelResource):

    user = fields.ForeignKey(UserResource, 'user', readonly=True)
    question = fields.ForeignKey(QuestionResource, 'question', readonly=True)

    def hydrate_user(self, bundle):
        return bundle.request.user

    class Meta:
        queryset = Comment.objects.all().order_by("-created")
        resource_name = 'comment'
        filtering = {
            "session": ALL_WITH_RELATIONS,
            "user": ALL_WITH_RELATIONS
        }
        authorization = CommentAuthorization()

Model:

class Comment(models.Model):

    question = models.ForeignKey(AMAQuestion, related_name = "comments")
    user = models.ForeignKey(User, related_name = "comments")

    created = models.DateTimeField(auto_now_add=True, editable=False)
    edited = models.DateTimeField(auto_now=True, editable=False)

    comment = models.TextField()

When trying to POST to this, it appears that tastypie isn't setting the question properly. (It might also be important that hydrate_FOO methods aren't being called for some reason.

Here's some sample data I sent:

{
    "comment": "test",
    "question": "/api/v1/question/1/"
}

Here's the error:

Traceback (most recent call last):

  File "C:\Python33\lib\site-packages\django\db\backends\sqlite3\base.py", line
362, in execute
    return Database.Cursor.execute(self, query, params)

sqlite3.IntegrityError: questions_comment.question_id may not be NULL


During handling of the above exception, another exception occurred:


Traceback (most recent call last):

  File "C:\Python33\lib\site-packages\tastypie\resources.py", line 195, in wrapp
er
    response = callback(request, *args, **kwargs)

  File "C:\Python33\lib\site-packages\tastypie\resources.py", line 426, in dispa
tch_list
    return self.dispatch('list', request, **kwargs)

  File "C:\Python33\lib\site-packages\tastypie\resources.py", line 458, in dispa
tch
    response = method(request, **kwargs)

  File "C:\Python33\lib\site-packages\tastypie\resources.py", line 1320, in post
_list
    updated_bundle = self.obj_create(bundle, **self.remove_api_resource_names(kw
args))

  File "C:\Python33\lib\site-packages\tastypie\resources.py", line 2084, in obj_
create
    return self.save(bundle)

  File "C:\Python33\lib\site-packages\tastypie\resources.py", line 2230, in save

    bundle.obj.save()

  File "C:\Python33\lib\site-packages\django\db\models\base.py", line 546, in sa
ve
    force_update=force_update, update_fields=update_fields)

  File "C:\Python33\lib\site-packages\django\db\models\base.py", line 650, in sa
ve_base
    result = manager._insert([self], fields=fields, return_id=update_pk, using=u
sing, raw=raw)

  File "C:\Python33\lib\site-packages\django\db\models\manager.py", line 215, in
 _insert
    return insert_query(self.model, objs, fields, **kwargs)

  File "C:\Python33\lib\site-packages\django\db\models\query.py", line 1675, in
insert_query
    return query.get_compiler(using=using).execute_sql(return_id)

  File "C:\Python33\lib\site-packages\django\db\models\sql\compiler.py", line 93
7, in execute_sql
    cursor.execute(sql, params)

  File "C:\Python33\lib\site-packages\django\db\backends\util.py", line 41, in e
xecute
    return self.cursor.execute(sql, params)

  File "C:\Python33\lib\site-packages\django\db\backends\sqlite3\base.py", line
364, in execute
    six.reraise(utils.IntegrityError, utils.IntegrityError(*tuple(e.args)), sys.
exc_info()[2])

  File "C:\Python33\lib\site-packages\django\utils\six.py", line 328, in reraise

    raise value.with_traceback(tb)

  File "C:\Python33\lib\site-packages\django\db\backends\sqlite3\base.py", line
362, in execute
    return Database.Cursor.execute(self, query, params)

django.db.utils.IntegrityError: questions_comment.question_id may not be NULL

Upvotes: 0

Views: 235

Answers (2)

Chesco Igual
Chesco Igual

Reputation: 71

As you point out, readonly is a property to manage the attribute in the hydrate cycle. It doesn't really have anything to do with preventing the field from being editable in the next requests. If I understand correctly, you want to prevent the question field to be edited in the future. You can do that either by deactivating modifications of the Resource, or by controlling those modifications.

If you want to prevent the Resource from being modified, just deactivate PUT calls to the Comment resource by adding the next line to your Meta:

allowed_methods = ['get', 'post',]

On the other hand, if you want to control how the PUTbehaves, you can control the hydrate and delete the new 'question' from the request, which will stop its modification:

def hydrate(self, bundle):
    if bundle.request.method == 'PUT':
        if 'question' in bundle.data:
            bundle.data.pop('question',None)
    return bundle

Upvotes: 1

Eric Pauley
Eric Pauley

Reputation: 1779

It turns out that tastypie doesn't even set readonly fields on the first POST. I guess this makes sense, but I still want fields that are only editable on initial POST.

Upvotes: 0

Related Questions