Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I am using Django with multiple databases. I have a 'preview' database that takes messages uploaded by the user and these have to be previewed by an admin and 'accepted', at which point they are committed to the 'default' production database. The following view is supposed to do that, but I'm getting an error. Each newSentenceModel has a Foreign Key to each newMessageSegment, and each newMessageSegment has a Foreign Key to each Message. I want to move each item to the new database if the admin accepts the content, and then delete the old entries in the preview database. Please help! Thanks -

Here is the error:

instance is on database "preview", value is on database "default"

The Error message occurs at this line:

newMessageSegment.msg = newMessage # Setup the foreign key to the msg itself

Here is the View function:

## This view is used when the admin approves content and clicks on the "accept content" button when reviewing 
## a recent upload - it saves the data to the production database
def accept_content(request, msg_id=None):
    if msg_id == None: # If for some reason we got a None, then it's not a valid page to accept so redirect home
        return HttpResponseRedirect("/") # Redirect home
    msgList = Message.objects.using('preview').all() # Get all Messages
    msgSegmentList = MessageSegment.objects.using('preview').all() # Get all MessageSegment Objects
    sentenceModels = SentenceModel.objects.using('preview').all() # Get all SentenceModels
    for msgs in msgList: # Iterate all msgs
        if int(msgs.id) != int(msg_id): # Don't care if it is not the msg needing review
            continue # Short Circuit
        msgPrimaryKey = msgs.pk # Extract the primary key from this msg to restore later
        msgs.pk = None # Erase the primary key so we can migrate databases properly
        newMessage = msgs # This is the msg to transfer to the new one
        newMessage.save(using='default') # Save the item to the production database
        for msgSegment in msgSegmentList: # Iterate all msg segments for this msg
            if msgSegment.msg_id == msgPrimaryKey: # Check the foreign keys on the msg segment to msg connection
                newMessageSegment = msgSegment # Define a new msg segment
                msgSegment.pk = None # Erase the primary key so we can assign it properly
                newMessageSegment.pk = None # Erase the primary key so we can assign it properly
                newMessageSegment.msg = newMessage # Setup the foreign key to the msg itself
                newMessageSegment.save(using='default') # Save the item to the production database
                for sentenceModel in sentenceModels: # Iterate all sentences for this msg segment
                    if sentenceModel.msg_segment_id == msgSegment.id: # Determine which sentences are for this msg segment
                        newSentenceModel = sentenceModel # Define the newSentenceModel
                        newSentenceModel.msg_segment = newMessageSegment # Setup the foreign key to the msg segment
                        newSentenceModel.save(using='default') # Save the item to the production database
                        sentenceModel.delete(using='preview') # Delete the item from the review database
                msgSegment.delete(using='preview') # Delete the item from the review database
        msgs.pk = msgPrimaryKey # Restore the key so we can delete it properly
        msgs.delete(using='preview') # Delete the item from the review database
    return HttpResponseRedirect("/")
share|improve this question
add comment

1 Answer

up vote 1 down vote accepted

Django remembers which database the object was saved with, so each newMessageSegment is still affiliated with the preview database until you save it to default and it correctly disallows the cross-database FK assignment. This is untested, but it might work to assign to the underlying msg_id field instead:

newMessageSegment.msg_id = newMessage.id

Failing that, you could create a new copy of newMessageSegment rather than just creating a new reference to it. I think you could automate that by iterating over msgSegment._meta.fields, but I might be overlooking a subtlety of inheritance or something. And any many-to-many fields would be a pain.

Or, if you just want to hack it, edit the internal object tracking it. I wouldn't generally recommend that but it's going to be changed when you save anyway.

newMessageSegment._state.db = "default"
newMessageSegment.msg = newMessage
newMessageSegment.save(using="default")
share|improve this answer
 
Thank you very much - changing the state worked great. –  PhilBot Nov 28 at 1:28
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.