Django session with angular.js - angularjs

I have set a view Index(View) to load a view for angular and it works fine. Angular communicates with Django and maintains session (Token base).
class Index(TemplateView):
context = {}
permanent = False # docs.djangoproject.com/en/1.9/ref/class-based-views/base/
template_name = 'index.html'
def __init__(self):
self.context = _.default_context()
self.response = _.default_response()
def get(self,request, *args, **kwargs):
return _.render_view(request, self.template_name, self.context)
def post(self, request, *args, **kwargs):
_.process_request(request)
print request.POST
username = request.POST['username']
password = request.POST['password']
print password
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
auth_token,_ignore = Token.objects.get_or_create(user=user)
self.response['status']=True
self.response['statusCode']=200
self.response['data'] = {'token':auth_token.key}
self.response['user'] = {'email' : user.email,
'first_name' : user.first_name,
'last_name' : user.last_name}
else:
self.response['status']=False
self.response['statusCode']=203
self.response['data']=[]
else:
self.response['status']=False
self.response['statusCode']=404
self.response['data']=[]
return _.serialize_response(self.response)
Now anyone can access this page. I want to restrict user to access dashboard without login (in the case a user tries to hack by adding cookie or something).
If I create separate pages for login and angular:
How can I handle different pages in one angular app?
Do I have to create angular app intent?
Something in Django?

Related

How to alter AbstractUser Modelfields with POST request?

I have a custom AbstractUser model that I'm using with couple of model fields, and I am trying to figure out how to alter those values from outside such as frontend or another APIView.
I'm not quite sure how to tackle this, please read below:
React Frontend
This is how I want to set user fields from frontend. For example, I would set user's birthday to certain date from frontend
axios
.post(`${process.env.NEXT_PUBLIC_API_URL}/auth/users/me/`, userData, {
withCredentials: true,
})
.then(function (response) {
alert(response.data);
console.log(response.data);
});
Currently, making this request will return a 405 Method Not Allowed error.
I am also looking for ways to alter user fields in outside from outer APIViews, so I can only take the information from frontend and do the actual work inside APIView.
users/api.py
class UserMeApi(ApiAuthMixin, ApiErrorsMixin, APIView):
def get(self, request, *args, **kwargs):
return Response(user_get_me(user=request.user))
# returns logged in user fields such as name, email, tokens, etc currently.
def post(self, request):
"""
Don't know what should go here
"""
users/models.py
class User(AbstractUser):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
username = None
first_name = models.CharField(max_length=100, default="unknown")
last_name = models.CharField(max_length=100, default="unknown", blank=True)
profile_pic = models.CharField(max_length=200, default="unknown")
premium = models.BooleanField(default=False)
tokens = models.IntegerField(default=0)
email = models.EmailField(unique=True, db_index=True)
secret_key = models.CharField(max_length=255, default=get_random_secret_key)
USERNAME_FIELD = "email"
REQUIRED_FIELDS = []
objects = UserManager()
class Meta:
swappable = "AUTH_USER_MODEL"

How can I automaticall add the currently logged in user to django models in react [duplicate]

I have the following code working perfectly. I can create a Post object from DRF panel by selecting an image and a user. However I want DRF to populate the user field by the currently logged in user.
models.py
class Post(TimeStamped):
user = models.ForeignKey(User)
photo = models.ImageField(upload_to='upload/')
hidden = models.BooleanField(default=False)
upvotes = models.PositiveIntegerField(default=0)
downvotes = models.PositiveIntegerField(default=0)
comments = models.PositiveIntegerField(default=0)
serializers.py
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = ['id', 'user', 'photo']
views.py
class PhotoListAPIView(generics.ListCreateAPIView):
queryset = Post.objects.filter(hidden=False)
serializer_class = PostSerializer
authentication_classes = (SessionAuthentication, BasicAuthentication)
permission_classes = (IsAuthenticated,)
How can I do this?
Off the top of my head, you can just override the perform_create() method:
class PhotoListAPIView(generics.ListCreateAPIView):
...
def perform_create(self, serializer):
serializer.save(user=self.request.user)
Give that a shot and let me know if it works
You can use CurrentUserDefault:
user = serializers.PrimaryKeyRelatedField(
read_only=True,
default=serializers.CurrentUserDefault()
)
It depends on your use case. If you want it to be "write-only", meaning DRF automatically populates the field on write and doesn't return the User on read, the most straight-forward implementation according to the docs would be with a HiddenField:
class PhotoListAPIView(generics.ListCreateAPIView):
user = serializers.HiddenField(
default=serializers.CurrentUserDefault(),
)
If you want want it to be readable, you could use a PrimaryKeyRelatedField while being careful that your serializer pre-populates the field on write - otherwise a user could set the user field pointing to some other random User.
class PhotoListAPIView(generics.ListCreateAPIView):
user = serializers.PrimaryKeyRelatedField(
# set it to read_only as we're handling the writing part ourselves
read_only=True,
)
def perform_create(self, serializer):
serializer.save(user=self.request.user)
Finally, note that if you're using the more verbose APIView instead of generics.ListCreateAPIView, you have to overwrite create instead of perform_create like so:
class PhotoListAPIView(generics.ListCreateAPIView):
user = serializers.PrimaryKeyRelatedField(
read_only=True,
)
def create(self, validated_data):
# add the current User to the validated_data dict and call
# the super method which basically only creates a model
# instance with that data
validated_data['user'] = self.request.user
return super(PhotoListAPIView, self).create(validated_data)
You can avoid passing the user in your request and you won't see it in the output but DRF will populate it automatically:
from rest_framework import serializers
class MyModelSerializer(serializers.ModelSerializer):
user = serializers.HiddenField(default=serializers.CurrentUserDefault())
class Meta:
model = models.MyModel
fields = (
'user',
'other',
'fields',
)
As of DRF version 3.8.0 (Pull Request discussion), you can override save() in serializer.
from rest_framework import serializers
...
class PostSerializer(serializers.ModelSerializer):
user = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault())
class Meta:
model = Post
fields = ['id', 'user', 'photo']
def save(self, **kwargs):
"""Include default for read_only `user` field"""
kwargs["user"] = self.fields["user"].get_default()
return super().save(**kwargs)
#DaveBensonPhillips's answer might work in your particular case for some time, but it is not very generic since it breaks OOP inheritance chain.
ListCreateAPIView inherits from CreateModelMixin which saves the serializer already. You should always strive to get the full chain of overridden methods executed unless you have a very good reason not to. This way your code stays DRY and robust against changes:
class PhotoListAPIView(generics.ListCreateAPIView):
...
def perform_create(self, serializer):
serializer.validated_data['user'] = self.request.user
return super(PhotoListAPIView, self).perform_create(serializer)
You will have to override the default behavior of how generics.ListCreateAPIView creates an object.
class PhotoListAPIView(generics.ListCreateAPIView):
queryset = Post.objects.filter(hidden=False)
authentication_classes = (SessionAuthentication, BasicAuthentication)
permission_classes = (IsAuthenticated,)
def get_serializer_class(self):
if self.request.method == 'POST':
return CreatePostSerializer
else:
return ListPostSerializer
def create(self, request, *args, **kwargs):
# Copy parsed content from HTTP request
data = request.data.copy()
# Add id of currently logged user
data['user'] = request.user.id
# Default behavior but pass our modified data instead
serializer = self.get_serializer(data=data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
The .get_serializer_class() is not necessary as you can specify which fields are read-only from your serializer, but based on the projects I have worked on, I usually end up with 'asymmetric' serializers, i.e. different serializers depending on the intended operation.
Try this:
def post(self, request, format=None)
serializer = ProjectSerializer(data=request.data)
request.data['user'] = request.user.id
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST
This is what works for me in serializers.py, where I am also using nested data. I want to display created_by_username without having to lookup other users.
class ListSerializer(serializers.ModelSerializer):
"""
A list may be created with items
"""
items = ItemSerializer(many=True)
# automatically set created_by_id as the current user's id
created_by_id = serializers.PrimaryKeyRelatedField(
read_only=True,
)
created_by_username = serializers.PrimaryKeyRelatedField(
read_only=True
)
class Meta:
model = List
fields = ('id', 'name', 'description', 'is_public',
'slug', 'created_by_id', 'created_by_username', 'created_at',
'modified_by', 'modified_at', 'items')
def create(self, validated_data):
items_data = validated_data.pop('items', None)
validated_data['created_by_id'] = self.context['request'].user
validated_data['created_by_username'] = self.context['request'].user.username
newlist = List.objects.create(**validated_data)
for item_data in items_data:
Item.objects.create(list=newlist, **item_data)
return newlist
I wrote an extension to DRF's serializer below
from rest_framework import serializers
class AuditorBaseSerializer(serializers.Serializer):
created_by = serializers.StringRelatedField(default=serializers.CurrentUserDefault(), read_only=True)
updated_by = serializers.StringRelatedField(default=serializers.CurrentUserDefault(), read_only=True)
def save(self, **kwargs):
# if creating record.
if self.instance is None:
kwargs["created_by"] = self.fields["created_by"].get_default()
kwargs["updated_by"] = self.fields["updated_by"].get_default()
return super().save(**kwargs)
and it can be used as follows
class YourSerializer(serializers.ModelSerializer, AuditorBaseSerializer):
class Meta:
model = SelfEmployedBusiness
fields = (
'created_by',
'updated_by',
)

Backend Validation error message using django

While Giving Correct username and password in login page its working correctly,while giving wrong username and password,how to show the error message.
views.py
def user_login(request):
logout(request)
username = password = ''
username = request.POST.get('username')
print(username)
password = request.POST.get('password')
print(password)
if request.POST:
user = authenticate(username=username, password=password)
if user is not None:
if user.is_active:
auth_login(request, user)
return render(request, 'admin_pannel.html', { 'dept' : dt, 'ds' : ds })
return redirect('/dashboard/')
return render(request, 'registration/login.html', {'dt' : dt })
Error messages are usually handled by an instance of django.forms.forms.Form. For your view I would suggest something like this:
from django.contrib.auth.forms import AuthenticationForm
def user_login(request):
if request.method == 'POST':
logout(request)
form = AuthenticationForm(request.POST)
if form.is_valid():
user = form.get_user()
auth_login(request, user)
return render(request, 'admin_pannel.html', {...})
else:
form = AuthenticationForm()
return render(request, 'registration/login.html', {'form': form, ...})
A quick glance at AuthenticationForm.clean looks like it will accomplish the same thing that you are doing in your view.
The only other thing that comes to mind is Django's messages framework, but I don't think that would be your best option.

How can I do a manually login method with my own model? Django

I want to do a manual log in method with my own model I read the documentation but I don't understand how to use
this:
from django.contrib.auth import authenticate, login
def my_view(request):
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
login(request, user)
# Redirect to a success page.
...
else:
# Return an 'invalid login' error message.
...
this is my model Usuario:
class Usuario(models.Model):
id_usuario = models.AutoField(primary_key=True)
nombre = models.CharField(max_length=255)
correo_electronico = models.EmailField()
direccion = models.CharField(max_length=255)
telefono = models.CharField(max_length=50)
usuario = models.CharField(max_length=255)
contrasenia = models.CharField(max_length=255, null=True ,blank=True)
id_perfil = models.ForeignKey(Perfil, on_delete=models.CASCADE)
fecha_creacion = models.DateTimeField(auto_now_add=True)
fecha_modificacion = models.DateTimeField(null=True)
fecha_cancelacion = models.DateTimeField(null=True)
status = models.CharField(max_length=50)
def __str__(self):
return '{}'.format(self.nombre)
Your view is meant to be used for default authentication system. But, given your user model, I think you are looking for custom authentication system. It is best to see Django docs. In short, you need a custom model, forms, and backends. You should also make sure your settings.py specifies which backend Django is supposed to look for.

AngularJS + django REST api

I'm attempting to build an api with DRF.
Client is a cordova app backed with AngularJS.
When I try to post some user object using $resource I'm getting a 403 forbidden response from django.
Below is some code which I think is relevant for the issue:
The API Call:
$rootScope.user =
User.get({id: response.id}).$promise.then(angular.noop, function (e) {
if (e.status == 404) { //If not found, register the user.
$rootScope.user = new User();
Object.keys(response).forEach(function (key) {
$rootScope.user[key] = response[key];
});
$rootScope.user.$save(); //Fails here! 403.
}
else
console.log(JSON.stringify(e.msg));
});
The User factory:
.factory('User', function ($resource, serverConstants) {
return $resource(serverConstants.serverUrl + '/users/:id');
})
django view:
# Users
class UserSerializer(serializers.HyperlinkedModelSerializer):
id = serializers.CharField(max_length=100,required=True)
email = serializers.EmailField(required=False,allow_blank=True)
joined = serializers.DateField(required=False,default=datetime.date.today)
class Meta:
model = models.User
fields = ('joined', 'id', 'email')
def get_validation_exclusions(self):
exclusions = super(UserSerializer, self).get_validation_exclusions()
return exclusions + ['owner']
class UserViewSet(viewsets.ModelViewSet):
queryset = models.User.objects.all()
serializer_class = UserSerializer
PS: I've configured angular to use CSRF cookie and django to allow CORS
Thanks in advance!
Your /user/:id endpoint requires authenticated requests.
You need to authenticate your client's requests using one of the methods specified on the previous link.
Given your app runs in a WebView and then has a builtin cookies handling, SessionAuthentication is the more straightforward to implement.
If you want the endpoint to not require authentication, you can set its permission_classes attribute like so:
from rest_framework.permissions import AllowAny
class UserViewSet(viewsets.ModelViewSet):
queryset = models.User.objects.all()
serializer_class = UserSerializer
permission_classes = (AllowAny, )
I guess with DRF you mean the django-rest-framework.
If yes, have a look here:
http://www.django-rest-framework.org/api-guide/authentication/
You can make the view public but using AllowAny.
from rest_framework.permissions import AllowAny
from rest_framework import generics
restapi_permission_classes = (AllowAny,)
class MyListView(generics.ListCreateAPIView):
serializer_class = MyObjectSerializer
permission_classes = restapi_permission_classes
queryset = MyObject.objects.all()
However I'd recommend you to use proper authentication once you are done with testing. I've been using the token authentication.
Have a look at this post for more details:
Django Rest Framework Token Authentication

Resources