Created
December 4, 2015 14:35
-
-
Save AmirTugi/52ac9f4cce3f21fae569 to your computer and use it in GitHub Desktop.
Default values not showing the the browsable api
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager | |
from django.db import models | |
class AccountManager(BaseUserManager): | |
def create_user(self, username, password=None, **kwargs): | |
if not username: | |
raise ValueError('Users must have a valid username.') | |
if not kwargs.get('email'): | |
raise ValueError('Users must have a valid email address.') | |
# Create a dictionary for all values but email and confirm_password (username & password are already extracted) | |
attr_dict = {} | |
for attr, value in kwargs.items(): | |
if attr in ['email', 'confirm_password']: | |
continue | |
attr_dict[attr] = value | |
# Create the new Account instance. | |
account = self.model( | |
email=self.normalize_email(kwargs.get('email')), | |
username=username, | |
**attr_dict | |
) | |
account.set_password(password) | |
account.save() | |
return account | |
def create_superuser(self, username, password, **kwargs): | |
account = self.create_user(username, password, **kwargs) | |
account.is_staff = True | |
account.save() | |
return account | |
class Account(AbstractBaseUser): | |
GENDER_CHOICES = (('Male', 'Male'), | |
('Female', 'Female')) | |
DEFAULT_AVATAR = 'avatar1' | |
email = models.EmailField() | |
username = models.CharField(max_length=40, unique=True) | |
first_name = models.CharField(max_length=40, blank=True) | |
last_name = models.CharField(max_length=40, blank=True) | |
# Default gender is Male | |
gender = models.CharField(max_length=40, choices=GENDER_CHOICES, default=GENDER_CHOICES[0][0]) | |
avatar = models.CharField(max_length=100, default=DEFAULT_AVATAR) | |
# Administrator | |
is_staff = models.BooleanField(default=False) | |
created_at = models.DateTimeField(auto_now_add=True) | |
updated_at = models.DateTimeField(auto_now=True) | |
objects = AccountManager() | |
USERNAME_FIELD = 'username' | |
REQUIRED_FIELDS = ['email'] | |
def get_full_name(self): | |
return " ".join([self.first_name, self.last_name]) | |
def get_short_name(self): | |
return self.first_name | |
def __unicode__(self): | |
return self.username |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from rest_framework import permissions | |
__author__ = 'Amir' | |
class IsAccountOwner(permissions.BasePermission): | |
def has_object_permission(self, request, view, account): | |
return request.user and account == request.user |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from rest_framework.serializers import raise_errors_on_nested_writes | |
from django.contrib.auth import update_session_auth_hash | |
from rest_framework import serializers | |
from authentication.models import Account | |
__author__ = 'Amir' | |
class AccountSerializer(serializers.ModelSerializer): | |
password = serializers.CharField(write_only=True, required=False) | |
confirm_password = serializers.CharField(write_only=True, required=False, default='asd') | |
# TODO: Give related information | |
# items = serializers.StringRelatedField(many=True) | |
class Meta: | |
model = Account | |
fields = ('id', 'email', 'username', 'created_at', 'updated_at', | |
'first_name', 'last_name', 'gender', 'avatar', 'is_staff', 'password', | |
'confirm_password') | |
read_only_fields = ('created_at', 'updated_at',) | |
def create(self, validated_data): | |
return Account.objects.create_user(**validated_data) | |
def update(self, instance, validated_data): | |
# First, update passwords | |
password = validated_data.get('password', None) | |
confirm_password = validated_data.get('confirm_password', None) | |
if password and confirm_password and password == confirm_password: | |
instance.set_password(password) | |
instance.save() | |
update_session_auth_hash(self.context.get('request'), instance) | |
# This is from the original update, with a small monkey patch - Skip updating password | |
raise_errors_on_nested_writes('update', self, validated_data) | |
# Update all attributes but passwords. | |
for attr, value in validated_data.items(): | |
if attr in ['password', 'confirm_password']: | |
continue | |
setattr(instance, attr, value) | |
instance.save() | |
return instance |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import json | |
from traceback import format_exc | |
from django.contrib.auth import authenticate, login, logout | |
from rest_framework.response import Response | |
from authentication.models import Account | |
from authentication.permissions import IsAccountOwner | |
from authentication.serializers import AccountSerializer | |
from rest_framework import viewsets, permissions, views, status | |
class AccountViewSet(viewsets.ModelViewSet): | |
queryset = Account.objects.all() | |
serializer_class = AccountSerializer | |
def get_permissions(self): | |
# TODO: See how to to make OR operator with permission classes | |
# If read-only request | |
if self.request.method in permissions.SAFE_METHODS: | |
return permissions.AllowAny(), | |
# If POST request (To create a new account) | |
if self.request.method == "POST": | |
return permissions.AllowAny(), | |
# If admin | |
if self.request.user.is_staff: | |
return permissions.AllowAny(), | |
return IsAccountOwner(), | |
def create(self, request, *args, **kwargs): | |
serializer = self.serializer_class(data=request.data) | |
if serializer.is_valid(): | |
Account.objects.create_user(**serializer.validated_data) | |
return Response(serializer.validated_data, status=status.HTTP_201_CREATED) | |
if 'username' in serializer.errors: | |
bad_request_message = 'That username already exists.' | |
else: | |
bad_request_message = 'Account could not be created with received data.' | |
return Response({ | |
'status': 'Bad request', | |
'message': bad_request_message | |
}, status=status.HTTP_400_BAD_REQUEST) | |
class LoginView(views.APIView): | |
def post(self, request): | |
try: | |
data = json.loads(request.body) | |
username = data.get('username', None) | |
password = data.get('password', None) | |
account = authenticate(username=username, password=password) | |
# If no account was found | |
if account is None: | |
return Response({ | |
'status': 'Unauthorized', | |
'message': 'Username/ password combination invalid.' | |
}, status=status.HTTP_401_UNAUTHORIZED) | |
# Or if the account is inactive | |
if not account.is_active: | |
return Response({ | |
'status': 'Unauthorized', | |
'message': 'This account has been disabled.' | |
}, status=status.HTTP_401_UNAUTHORIZED) | |
# Else, login and return the account | |
login(request, account) | |
serialized = AccountSerializer(account) | |
return Response(serialized.data, status=status.HTTP_200_OK) | |
except Exception: | |
print format_exc() | |
class LogoutView(views.APIView): | |
# permission_classes = (permissions.IsAuthenticated, ) | |
def post(self, request, format=None): | |
logout(request) | |
return Response({ | |
'message': 'Logged-out successfully.' | |
}, status=status.HTTP_200_OK) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"""Arihav URL Configuration | |
The `urlpatterns` list routes URLs to views. For more information please see: | |
https://docs.djangoproject.com/en/1.9/topics/http/urls/ | |
Examples: | |
Function views | |
1. Add an import: from my_app import views | |
2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') | |
Class-based views | |
1. Add an import: from other_app.views import Home | |
2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') | |
Including another URLconf | |
1. Add an import: from blog import urls as blog_urls | |
2. Import the include() function: from django.conf.urls import url, include | |
3. Add a URL to urlpatterns: url(r'^blog/', include(blog_urls)) | |
""" | |
from django.conf.urls import url, include | |
from authentication.views import AccountViewSet, LoginView, LogoutView | |
from rest_framework.routers import DefaultRouter | |
router = DefaultRouter() | |
router.register(r'users', AccountViewSet) | |
urlpatterns = [ | |
url(r'^', include(router.urls)), | |
url(r'^login', LoginView.as_view(), name='login'), | |
url(r'^logout', LogoutView.as_view(), name='logout'), | |
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')) | |
] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment