TIL

Web Dev Bootcamp TIL Day-45(DRF CBV & Custom User Model)

frannyk 2022. 6. 17. 13:45

Class Based Views

  • When using DRF, we construct APIs as Class Based Views
  • Within the class, we define:
    • permission classes for authentication purposes
    • views that correspond to different http methods
# views.py
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import permissions

class UserView(APIView):
    permission_classes = [permissions.AllowAny] # anyone can access view
    # permission_classes = [permissions.IsAdminUser] # only admins can access view
    # permission_classes = [permissions.IsAuthenticated] # only logged in users can access view

    def get(self, request):
        return Response({'message': 'get method!!'})
        
    def post(self, request):
        return Response({'message': 'post method!!'})

    def put(self, request):
        return Response({'message': 'put method!!'})

    def delete(self, request):
        return Response({'message': 'delete method!!'})

Postman

  • When building a project, we can make use of Postman to test our APIs
    • Postman retains the login informaiton
    • for dealing w/ CSRF errors, we must include the following code to Tests
    • include key/value
var xsrfCookie = postman.getResponseCookie("csrftoken");
postman.setGlobalVariable('csrftoken', xsrfCookie.value);


  • Common query patterns
# using try/except block to prompt an event for DoesNotExist exception
try:
    Model.objects.get(id=obj_id)
except Model.DoesNotExist:
    # trigger an event
    return Response("Object does not exist.")

---------------------------------------------------------------------------------
# sorting querysets
Model.objects.all().order_by("join_date")
Model.objects.all().order_by("-join_date") #reverse order
Model.objects.all().order_by("?") #randomize

---------------------------------------------------------------------------------
# selecting first object of queryset
Model.objects.all().first()
Model.objects.all()[0]

---------------------------------------------------------------------------------
# selecting an object if it exists / creating if object does not exist
object, created = Model.objects.get_or_create(
    field1="value1",
    field2="value2",
)

if created: 
    # created event
else: 
    # already exists event

Custom User model and UserManager model

  • We can inherit Django's built-in UserManager and User model to create our own custom classes.
  • This allows us to tweak the required fields for superuser registration
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser

# to use our own custom user model, we must define our own custom usermanager model
# python manage.py createsuperuser ----> triggers create_superuser()
class UserManager(BaseUserManager):
	# parameters will need to be updated according to unique fields in our user class
    def create_user(self, username, password=None):
        if not username:
            raise ValueError('Users must have a username')
        user = self.model(
            username=username,
        )
        user.set_password(password)
        user.save(using=self._db)
        return user
    
    # parameters will need to be updated according to unique fields in our user class
    def create_superuser(self, username, password=None):
        # create_superuser view -----> triggers create_user()
        user = self.create_user(
        	# these fields will need to be updated according to required fields
            username=username,
            password=password
        )
        user.is_admin = True
        user.save(using=self._db)
        return user

class User(AbstractBaseUser):
	# when setting unique fields, we must update parameters in user creation
    username = models.CharField("username", max_length=20, unique=True) #username must be unique
    email = models.EmailField("email", max_length=100)
    password = models.CharField("password", max_length=128)
    realname = models.CharField("realname", max_length=20)
    join_date = models.DateTimeField("join_date", auto_now_add=True) #adds timestamp when user is created

    # is_active = False -----> user will be deactivated
    is_active = models.BooleanField(default=True) 

    # is_staff will set this value
    is_admin = models.BooleanField(default=False)
    
    # this field will be used as the ID field during login
    USERNAME_FIELD = 'username'

    # these fields will be required when creating a user
    REQUIRED_FIELDS = []
    
    # creating an instance of our custom user manager class
    objects = UserManager()
    
    def __str__(self):
        return self.username

    # Permission settings for table CRUD access and app access 
    # By default, for admin users ---> has_perm = True
    # for non-active users ---> has_perm = False
    def has_perm(self, perm, obj=None):
        return True
    
    def has_module_perms(self, app_label): 
        return True
    
    # setting admin property
    @property
    def is_staff(self): 
        return self.is_admin

Custom Admin page settings

from django.contrib import admin
from User.models import *
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.hashers import make_password

class UserAdmin(BaseUserAdmin):
    list_display = ('id', 'username', 'realname') # 사용자 목록에 보여질 필드 지정
    list_display_links = ('id', 'username') # 상세 페이지 눌러서 들어갈 필드 지정
    list_filter = ('realname', 'username')
    search_fields = ('realname','username', )
    readonly_fields = ('join_date', )
    fieldsets = (
        ("info", {'fields': ('username', 'password', 'email', 'realname', 'join_date')}),
        ('permissions', {'fields': ('is_admin', 'is_active', )}),
    )
   
    filter_horizontal = []

admin.site.register(CustomUser, UserAdmin)
admin.site.register(Dish)
admin.site.register(UserProfile)
  • When DB and models are out of sync run the following command:
python manage.py migrate --run-syncdb