I am using django restframework and want to handle multiple databases. I am using django function using(alias) and switch_db(alias) for manually switching between database whenever I want to Get, Post or update data.
I am facing problem while posting and updating data.i.e whenever serializer.is_valid() will be called.
serializer.is_valid() will go and first check for db_alias in model.py file. If I have not specified db_alias under meta it will select default database for validation. If I am specifying db_alias in model it will select that database for validation.
But I do not want to specify db_alias in model since my usecase is to store data on different database based on some logic in my view file. So dynamically I want to select database from view and want to store data in it.
Almost I have implemented but I am facing problem when my model is having Reference Field. In this case serializer.is_valid is going to default database for validating that reference field.
Required Details: I am using mongoengine(0.9.0), document, document serializer.
My files are as below:
model.py:
class ngroup(Document):
groupname = StringField(max_length=100, required=True)
description = StringField(max_length=100, required=False)
parent = ReferenceField('ngroup',null=True)
created_ts = DateTimeField(default=datetime.now())
modified_ts = DateTimeField(default=datetime.now())
is_deleted = BooleanField(default=False)
serializer.py:
from device_management.models import ngroup
from rest_framework_mongoengine.serializers import DocumentSerializer
from mongoengine import EmbeddedDocumentField, ReferenceField, StringField, ObjectIdField, IntField, BooleanField, FloatField, DateTimeField,ListField
class ngroupSerializer(DocumentSerializer):
class Meta:
model = ngroup
def setOrgId(self, orgid):
self.orgid = orgid
def create(self, validated_data):
ngroup_data = ngroup(**validated_data).switch_db(self.orgid)
ngroup_data.save()
return ngroup_data
def update(self, instance, validated_data):
ngroup_data = ngroup.objects.using(self.orgid).get(id = instance.id)
ngroup_data = ngroup_data.switch_db(self.orgid)
ngroup_data = ngroup_data.update(**validated_data)
return validated_data
def to_internal_value(self, data):
print "data:" , data
return super(DocumentSerializer, self).to_internal_value(data)
view.py:
def create(self, request, format=None):
orgid = str(request.user.orgid.id)
data=request.data
serializer = ngroupSerializer(data=data)
if serializer.is_valid():
try:
serializer.save()
except Exception as e:
log.error("create" , extra={'extra':{'error': str(e),'message' :strings.DATA_VALIDATION_ERROR }})
return response.errorResponse(message=strings.SERIALIZATION_ERROR_MSG,error=str(e),rstatus=status.HTTP_400_BAD_REQUEST)
return response.successResponse(res_data=serializer.data, message=strings.POST_SUCCESS_MSG, rstatus=status.HTTP_201_CREATED)
log.error("create" , extra={'extra':{'error': serializer.errors,'message' :strings.DATA_VALIDATION_ERROR }})
return response.errorResponse(message=strings.DATA_VALIDATION_ERROR,error=serializer.errors,rstatus=status.HTTP_400_BAD_REQUEST)
settings.py:
DATABASES = {
'default': {
'ENGINE': 'django_mongodb_engine',
'NAME': 'mydb',
'USER': 'admin',
'PASSWORD':'admin123',
'HOST': '127.0.0.1',
'PORT': 27017,
'DBTYPE' : "mongo",
},
'586e47c784413825f2b5bc49': {
'ENGINE': 'django_mongodb_engine',
'NAME': 'mydb1',
'USER': 'admin',
'PASSWORD':'admin123',
'HOST': '127.0.0.1',
'PORT': 27017,
'DBTYPE' : "mongo",
},
# Enter super_user organisation here. This DB will be same as default db only always
'58996fb28441384430dc8ae6': {
'ENGINE': 'django_mongodb_engine',
'NAME': 'mydb',
'USER': 'admin',
'PASSWORD':'admin123',
'HOST': '127.0.0.1',
'PORT': 27017,
'DBTYPE' : "mongo",
},
}
pip freeze(Installation versions):
Django==1.5.11
django-browserid==2.0.2
django-classy-tags==0.8.0
django-missing==0.1.18
django-mongo-auth==0.1.3
django-mongodb-engine==0.6.0
django-mongoengine==0.2.1
django-redis-sessions==0.5.6
django-rest-framework-mongoengine==3.3.0
django-sekizai==0.10.0
django-websocket-redis==0.4.7
djangorestframework==3.1.2
djangorestframework-jwt==1.9.0
djangotoolbox==1.8.0
gevent==1.1.2
greenlet==0.4.10
httplib2==0.9.2
mongoengine==0.9.0
oauthlib==2.0.1
pika==0.10.0
Pygments==2.1.3
PyJWT==1.4.2
pymongo==2.8
python-dateutil==2.6.0
python-openid==2.2.5
pytz==2016.10
redis==2.10.5
requests==2.12.3
requests-oauthlib==0.7.0
rest-condition==1.0.3
six==1.10.0
tweepy==3.5.0
twilio==5.7.0
I have overide create in serializer to take care of database while calling serializer.save() but how to handle serializer.is_valid().
My project has been stuck at this point. Any help will be greatly appreciated...
The .is_valid() method takes an optional raise_exception flag that will cause it to raise a serializers.ValidationError exception if there are validation errors.
Validation in Django REST framework serializers is handled a little differently to how validation works in Django's ModelForm class. With ModelForm the validation is performed partially on the form, and partially on the model instance. With REST framework the validation is performed entirely on the serializer class.
We can validate the serializer by calling the method " is_valid() ". It will return the boolean(True/False) value. If the serializer is not valid then we can get errors by using the attribute "errors".
Django's serialization framework provides a mechanism for “translating” Django models into other formats. Usually these other formats will be text-based and used for sending Django data over a wire, but it's possible for a serializer to handle any format (text-based or not).
This is not the exact solution to above problem but we have 2 options.
1) Do not go for serializer.is_valid() or serializer.save(). Directly create ngroup:
def my_create(self, validated_data):
gateway = Gateway(**validated_data).switch_db(self.orgid)
gateway.save()
return gateway
2) Another solution is to use django-mogodb-engine and django models and modelserializers instead of documents and documents serializers.
I have tried following this with Django-mongodb-engine and are working well:
-> JWT authentication
-> custom user
-> foreign key
-> embedded model
-> list of embedded model
-> dict field
-> **Routers for switching between databases.(Manual switching DB is not required)**
I can also use middleware_classes to specify runtime in each request which database to use. Reference Link: Django Authenticate Backend Multiple Databases
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With