pythondjangomanytomanyfield

How to avoid the use of ManytoMany field in Django?


I have the Role model. Account model take the reference from Role model using ManytoMany Field. But, I don't want to use manytomany field. It's necessary to not use ManyToMany field. Is anyone can suggest something better. I don't want to use use ManyToMany field because, since many to many are a Django feature and not database

The given below model works fine with ManyToMany Field, I want the same with it.

from django.db import models
from django.db.models.fields import proxy
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser
from django.utils.translation import gettext_lazy as _
from django.core.validators import RegexValidator
import uuid
from django.utils import timezone
import math
from django.core.validators import MinValueValidator, MaxValueValidator


ADMIN = 0
CUSTOMER = 1
SELLER = 2
DELIVERY_PARTNER = 4
class Role(models.Model):
  '''
  The Role entries are managed by the system,
  automatically created via a Django data migration.
  '''

  ROLE_CHOICES = (
      (ADMIN, 'admin'),
      (CUSTOMER, 'customer'),
      (SELLER, 'seller'),
      (DELIVERY_PARTNER, 'delivery'),
  )

  id = models.PositiveSmallIntegerField(choices=ROLE_CHOICES, primary_key=True)

  def __str__(self):
      return self.get_id_display()
      
class UserManager(BaseUserManager):
    '''
    creating a manager for a custom user model
    https://docs.djangoproject.com/en/3.0/topics/auth/customizing/#writing-a-manager-for-a-custom-user-model
    https://docs.djangoproject.com/en/3.0/topics/auth/customizing/#a-full-example
    '''
    def create_user(self, mobile_number, password=None):
        """
        Create and return a `User` with an email, username and password.
        """
        if not mobile_number:
            raise ValueError('Users Must Have an email address')

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

    def create_superuser(self, mobile_number, password):
        """
        Create and return a `User` with superuser (admin) permissions.
        """
        if password is None:
            raise TypeError('Superusers must have a password.')

        user = self.create_user(mobile_number, password)
        user.is_superuser = True
        user.is_staff = True
        user.save()

        return user


class Account(AbstractBaseUser):
    '''Account Model to store mobile number and authentication'''
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    email = models.EmailField(
        verbose_name='email address',
        max_length=255,
        null = True,
        )
    type = models.ManyToManyField(Role,default=[1])
    phone_regex = RegexValidator(regex=r'^\+?1?\d{9,15}$', message="Phone number must be entered in the format: '+999999999'. Up to 15 digits allowed.")
    mobile_number = models.CharField(validators=[phone_regex], max_length=17, blank=False,null = False, unique=True) 

    otp = models.CharField(max_length=6, null = True, unique=True)
    user_registered_on = models.DateTimeField(default=timezone.now, blank=True)

    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)
    is_superuser = models.BooleanField(default=False)
    USERNAME_FIELD = 'mobile_number'
    REQUIRED_FIELDS = []

    # Tells Django that the UserManager class defined above should manage
    # objects of this type.
    objects = UserManager()

    def get_full_name(self):
        pass

    def get_short_name(self):
        pass

    # @property
    # def is_superuser(self):
    #     return self.is_superuser

    @property
    def is_staff(self):
       return self.is_superuser

    def has_perm(self, perm, obj=None):
       return self.is_superuser

    def has_module_perms(self, app_label):
       return self.is_superuser

    @is_staff.setter
    def is_staff(self, value):
        self._is_staff = value

    def __int__(self):
        return self.mobile_number
    
    def verify_user_type(self,type):
        for x in self.type.all():
            if x.id == type:
                return True
        return False
    class Meta:
        '''
        to set table name in database
        '''
        db_table = "login"

Solution

  • I don't want to use use ManyToManyField because, since many to many are a Django feature and not database

    There is nothing special about a ManyToManyField. Behind the curtains it creates a model (named appname_modename_m2mfieldname) with two ForeignKeys: one to the "source model" and one to the "target model". This is a pattern known as a junction table [wiki], which is how many-to-many relations are normally defined in a relational database.

    You can even work with the "hidden" model with Account.type.through, which will return a reference to a model class.

    While you can define an extra model for the junction table yourself, it makes no sense, and will only make the ORM more complicated. For more information, see the database representation section on the ManyToManyField [Django-doc].