Search code examples
mysqldjangodjango-modelsdjango-settingsdjango-database

Mapping entire app to a different database in Django


I have many apps in my django_project. One of them is user_interaction. I am also using 2 databases.(Sqlite and MySQL) I want my user_interaction app to complete work on MySQL database.whereas other apps should work on sqlite3. The things is i want all the reading,writing,saving,authenticating,etc of user_interaction to happen in MYSQL Database.

And reading,writing,saving,authenticating,etc of other apps to happen in Sqlite.

This is not working. So What should i Do?

settings.py file(database part)

DATABASE_APPS_MAPPING = {'user_interaction': 'user_interaction_db',
                        }


DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    },


    'user_interaction_db' :{
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'FMS_Database',
        'USER': '#####',
        'PASSWORD': '#####',
        'HOST': 'localhost',
        'PORT': '3306',
        'OPTIONS': {
            # Tell MySQLdb to connect with 'utf8mb4' character set
            'charset': 'utf8mb4',
        },
    },
    
}

Models.py of user_interaction:

class StudentAccountManager(BaseUserManager):
 

    def create_user(self,username,password=None):
        # if not email:
        #     raise ValueError("Users must have an email address")
        
        if not username:
            raise ValueError("Users must have an username")

        user = self.model(
            username = username,
        )

        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_superuser(self,username,password):
        
        user = self.create_user(
            password=password,
            username = username,

        )

        user.is_admin = True
        user.is_staff = True
        user.is_superuser = True
        user.save(using=self._db)
        return user   



class StudentAccount(AbstractBaseUser):
    username    =  models.CharField(max_length=50,unique=True)
    email       =  models.EmailField(max_length=254,unique=True)
    joined_date =  models.DateTimeField(auto_now_add=True)
    last_login  =  models.DateTimeField(auto_now=True)
    is_admin    =  models.BooleanField(default=False)
    is_active   =  models.BooleanField(default=True)
    is_superuser = models.BooleanField(default=False)
    is_staff    =  models.BooleanField(default=False)
    

    management_name = models.CharField(max_length=254)
    full_name = models.CharField(max_length=254,null=True)
    contact_no = models.CharField(max_length=10)
    department = models.CharField(max_length=254)
    residential_status = models.CharField(max_length=254)
    batch_year = models.CharField(max_length=4,default='Null')
    entry_qrcode = models.ImageField(upload_to = qrcode_directory_path,null=True)  
    

    USERNAME_FIELD = 'username'

    #specifying manager
    objects = StudentAccountManager()


    def __str__(self):
        return self.username
    
    def has_perm(self,perm,obj=None):
        return self.is_admin
    
    def has_module_perms(self,app_label):
        return True

Views.py of user_interaction:

    def student_registration(request):
        
        if request.user.is_authenticated:
            return redirect('/useraccount/studentuser/')
        else:
        
            form = raw_user_form()
            if request.method == "POST" :
                form = raw_user_form(request.POST)
    
    
                if form.is_valid():
                    save_obj = StudentAccount()
                    save_obj.full_name = form.cleaned_data['full_name']
                    save_obj.username = form.cleaned_data['roll_no']
                    save_obj.management_name = form.cleaned_data['management_name']
                    save_obj.contact_no = form.cleaned_data['contact_no']
                    save_obj.department = form.cleaned_data['department']
                    save_obj.residential_status = form.cleaned_data['residential_status']
                    save_obj.email = form.cleaned_data['email']
                    save_obj.batch_year = form.cleaned_data['batch_year']
                    save_obj.set_password(form.cleaned_data['password'])
                    save_obj.save()
                    return redirect('/useraccount/thankyoupage/')
        
        return render(request,'user_interaction/student_registration_page.html',{'user_form': form })

def student_login(request):
    incorrect = ''
    if request.user.is_authenticated:
        return redirect('/useraccount/studentuser/')
    else:
        if request.method =='POST':
            username = request.POST.get('username')
            password = request.POST.get('pass')

            user = authenticate(request, username=username,password=password)
        
            if user is not None:
                login(request,user)
                return redirect('/useraccount/studentuser/')
            else:
                incorrect = 'Incorrect username or password'

    return render(request,'user_interaction/student_login_form.html',{ 'message' : incorrect })

Solution

  • What you need — is a Django database router. Check out the examples here.

    Assuming you have your DATABASES like this:

    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
        },
    
    
        'user_interaction_db' :{
            'ENGINE': 'django.db.backends.mysql',
            'NAME': 'FMS_Database',
            'USER': '#####',
            'PASSWORD': '#####',
            'HOST': 'localhost',
            'PORT': '3306',
            'OPTIONS': {
                # Tell MySQLdb to connect with 'utf8mb4' character set
                'charset': 'utf8mb4',
            },
        },
        
    }
    

    Create a database router first:

    # db_routers.py
    class AuthRouter:
        """
        A router to control all database operations on models in the
        auth and contenttypes applications.
        """
        route_app_labels = {'user_interaction',}
    
        def db_for_read(self, model, **hints):
            """
            Attempts to read auth and contenttypes models go to auth_db.
            """
            if model._meta.app_label in self.route_app_labels:
                return 'user_interaction_db'
            return None
    
        def db_for_write(self, model, **hints):
            """
            Attempts to write auth and contenttypes models go to auth_db.
            """
            if model._meta.app_label in self.route_app_labels:
                return 'user_interaction_db'
            return None
    
        def allow_relation(self, obj1, obj2, **hints):
            """
            Allow relations if a model in the auth or contenttypes apps is
            involved.
            """
            if (
                obj1._meta.app_label in self.route_app_labels or
                obj2._meta.app_label in self.route_app_labels
            ):
               return True
            return None
    
        def allow_migrate(self, db, app_label, model_name=None, **hints):
            """
            Make sure the auth and contenttypes apps only appear in the
            'auth_db' database.
            """
            if app_label in self.route_app_labels:
                return db == 'user_interaction_db'
            return None
    

    That way, all the operations with user_interaction models with be done through user_interaction_db

    Next, add your router to settings.py

    DATABASE_ROUTERS = ['path.to.AuthRouter',]