[Django]-Django model form is_valid() in specific database

4👍

To enable the router just add it to DATABASE_ROUTERS in your setting.py, see detailes here: https://docs.djangoproject.com/en/1.9/topics/db/multi-db/#using-routers

Every router method gets hints dictionary, which should contain instance key representing the model instance being used. Depending on what information you want to get from the view, you might be good with the information from instance attributes. See here: https://docs.djangoproject.com/en/1.9/topics/db/multi-db/#topics-db-multi-db-hints.

I.e.:

def db_for_read(self, model, **hints):
    model_instance = hints.get('instance')   
    if model_instance is not None:
        pass
        #perform actions with model_instance attributes
    return None

Other then this I don’t think there’s other straight way to pass information from the active view to the router, as routers are supposed to work with models and make decisions based on models being used.

DB routers are used for automatic DB selection in models layer, but model methods allow to select the DB manually. See examples here: https://docs.djangoproject.com/en/1.9/topics/db/multi-db/#manually-selecting-a-database

So the other solution is to redefine methods of your form class, i.e. save() (see https://docs.djangoproject.com/en/1.9/topics/forms/modelforms/#the-save-method), and save the form data manually specifying the DB to use with using argument. I.e.:

class ProductForm(ModelForm):
    class Meta:
        ...

    def save(self, commit=True):
        product_to_save=super(ProductForm, self).save(commit=False)
        #the above creates product_to_save instance, but doesn't saves it to DB
        product_to_save.save(using=='banco1')
        return product_to_save

In the comments I suggested to subclass the field that needs to be validated against the other DB, but there’s probably even easier way… Since it’s FK field it’s probably the instance of ModelChoiceField which accepts the queryset argument in constructor, so you could provide it, i.e.:

class ProductForm(ModelForm):
   category_field = forms.ModelMultipleChoiceField(queryset=Category.objects.using('banco1'))
    ...

See: https://docs.djangoproject.com/en/1.9/ref/forms/fields/#fields-which-handle-relationships

Answer to EDIT2

The way you redefined the constructor your database argument gets request.POST and request.session['database'] is not mapped to anything, that’s why you get the error.

You should account for other arguments and also call superclass constructor or you’ll break the MRO, so something like this should do the job:

class ProductForm(ModelForm):
    ...

    def __init__(self, *args, db_to_use='default', **kwargs):
        super(ProductForm, self).__init__(*args, **kwargs)
        #category = forms.ModelChoiceField(queryset=Category.objects.using(db_to_use).all())
        #the below line suggested as improvement by Alasdair and confirmed as working by Pavarine, so I updated the answer here
        self.fields['category'].queryset = Category.objects.using(database).all()

and then as usual, but use named argument:

product_form = ProductForm(request.POST, db_to_use=request.session['database'])
👤Nikita

Leave a comment