I'm using Django/Python3 to make a simple API. I already made my models and views (also using serializers). Currently this is my login view:
class LoginView(generics.CreateAPIView):
queryset = User_Login.objects.all()
serializer_class = LoginUserSerializer
def post(self, request, *args, **kwargs):
id = request.data['id']
name = request.data['name']
password = request.data['password']
email = request.data['email']
User_Login.objects.create(id=id, name=name, password=password, email=email)
return HttpResponse({'message': 'User Created', 'id': id}, status=200)
All my views are basic like this, just to implement a database that I previously modeled.
I need to implement authentication (the one that generates simple tokens that the user need to add to their request's header) and I know It's easy, but I followed this tutorial and I got a lot of errors.
Any advice?
Related
I am writing a site for Flask, I have connected Flask-Security and I have a completely different template generated on the user authorization page, can it be connected to routes and how?
Here is the code for the view:
#app.route('/login', methods=['POST', 'GET'])
def login_page():
form = AuthorizationForm()
if form.validate_on_submit():
email = form.email.data
username = form.username.data
password = form.password.data
if email and username and password:
user = User.query.filter_by(email=email).first()
if check_password_hash(user.password, password):
login_user(user)
return redirect(url_for('index_page'))
else:
flash('Неправильний логін або пароль')
else:
flash('Будь ласка,завповніть всі поля')
return render_template('templates/security/login_user.html', title='Авторизація',
form=form, css_link=css_file)
But there is no effect
Help me please
There's a lot of unpack here!
First - you have defined a new form (is it derived from the flask-security LoginForm?); a new template, and a new view - and the view has the same URL as the default Flask-Security /login - not sure which one will take precedence.
Your code example actually has the 'render_template' outside the view code - a cut-n-paste error?
In Flask-Security you can independently override the template (still using the default Login form) or extend the Form (and do your validation in your form::validate method). It should be rare that you have to build your own view.
I'm using Django 3.2 and djangorestframework==3.12.2. I recently added this to my settings file because I want to add some secured endpoints to my application ...
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
'rest_framework.permissions.IsAdminUser',
],
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
)
}
JWT_AUTH = {
# how long the original token is valid for
'JWT_EXPIRATION_DELTA': datetime.timedelta(hours=1),
}
However, this seems to have caused all my endpoints to require authentication. For example, I had this view set up in my views.py file
class CoopList(APIView):
"""
List all coops, or create a new coop.
"""
def get(self, request, format=None):
contains = request.GET.get("contains", "")
if contains:
coops = Coop.objects.find(
partial_name=contains,
enabled=True
)
else:
partial_name = request.GET.get("name", "")
enabled_req_param = request.GET.get("enabled", None)
enabled = enabled_req_param.lower() == "true" if enabled_req_param else None
city = request.GET.get("city", None)
zip = request.GET.get("zip", None)
street = request.GET.get("street", None)
state = request.GET.get("state", None)
coop_types = request.GET.get("coop_type", None)
types_arr = coop_types.split(",") if coop_types else None
coops = Coop.objects.find(
partial_name=partial_name,
enabled=enabled,
street=street,
city=city,
zip=zip,
state_abbrev=state,
types_arr=types_arr
)
serializer = CoopSearchSerializer(coops, many=True)
return Response(serializer.data)
accessible in my urls.py file using
path('coops/', views.CoopList.as_view()),
But now when I try and call that I get the below response
{"detail":"Authentication credentials were not provided."}
I only want certain views/endpoints secured. How do I make the default that all views are accessible and only specify some views/endpoints to be validated using a provided JWT?
'DEFAULT_PERMISSION_CLASSES' is conventiently applied to all views, unless manually overridden. In your case both listed permissions require the user to be authenticated. FYI, the list is evaluated in an OR fashion.
If you want to allow everyone by default and only tighten down specific views, you want to set
'DEFAULT_PERMISSION_CLASSES': ['rest_framework.permissions.AllowAny']
which does not require the user to be authenticated. Then set more strict permissions explicitly on the view (e.g. permissions_classes = [IsAuthenticated]) The DEFAULT_AUTHENTICATION_CLASS can stay as is.
NOTE: It is generally advisable to do it the other way round. It's very easy to accidentally expose an unsecured endpoint like this and potentially create a security breach in your API. The default should be secure and then exceptions should be be manually lifted.
Set the below configuration in settings.py
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
]
For class based views you can set permission class to empty list.
class CoopList(APIView):
permission_classes = []
def get(self, request, format=None):
pass
For Function based views add the decorator #permission_classes
from rest_framework.decorators import permission_classes
#permission_classes([])
def CoopList(request, format=None):
pass
I am new to Django and am building a database-driven website using PyCharm.
I am having an issue with users registering/logging in. What is happening is, when a user registers, I check the "Database" tab to the right, and the information will be passed into a table named "SavBlock_user", which will have the users name, password, etc.. Then, when I try to log in, it won't allow me to login due to incorrect username/password. However, if I try to login using a username/password from a different table named "auth_user" (like username: admin / password: admin), then I can successfully login. I'm not sure how to fix this.
Ideally, what I would like to do is completely remove the "SavBlock_user" table and strictly use "auth_user" for all of my users, but I'm not sure how to do this. I may have created a 'custom' user model back when I was learning the system, but I can't remember.
My files:
Project\register\forms.py
from django import forms
from SavBlock.models import * # <--- Contains User
''' Form for users to register '''
class RegisterForm(forms.ModelForm):
email = forms.EmailField(
initial='myemail#savagez.com'
)
uso_validate = forms.BooleanField(
label='Are you a PSMC member? (Chief, Uso, Anak)',
initial=False
)
class Meta:
model = User
widgets = {
'password': forms.PasswordInput(),
}
fields = '__all__'
Project\register\views.py
from django.http import request
from django.shortcuts import render, redirect
from .forms import RegisterForm
# Create your views here.
def register(response):
if response.method == "POST":
form = RegisterForm(response.POST or None)
if form.is_valid():
form.save()
return redirect('/dashboard/')
else:
form = RegisterForm()
return render(response, 'register/register.html', {'form': form})
Project\SavBlock\models.py
from django.db import models
class User(models.Model):
username = models.CharField("user name", max_length=50, default='')
email = models.EmailField("email address", unique=True, default='DEFAULT VALUE')
first_name = models.CharField("first name", max_length=50)
last_name = models.CharField("last name", max_length=50)
password = models.CharField("password", unique=True, max_length=50, default='')
rank = {
0: 'Supporter',
1: 'Anak',
2: 'Uso',
3: 'Chief'
}
#TODO: FIT __INIT__
'''
def __init__(self, first_name, last_name, *args, **kwargs):
super().__init__(*args, **kwargs)
self.first_name = first_name.title()
self.last_name = last_name.title()
'''
# Magic method returns string of self
def __str__(self):
return f"User {self.first_name} {self.last_name} rank {self.rank}".strip()
#property
def get_full_name(self):
return f"{self.first_name} {self.last_name}".strip()
class Anak(User):
def __init__(self, first_name, last_name, tribe):
super().__init__(first_name, last_name)
self.tribe = tribe.title()
self.rank = User.rank[1]
class Uso(User):
def __init__(self, first_name, last_name, tribe):
super().__init__(first_name, last_name)
self.tribe = tribe.title()
self.rank = User.rank[2]
----EDIT----
I fixed the different user tables and basically reset the migrations. Now, all users are showing up under a single user table SavBlock_user. However, the login issue is still there.
Admin was created using the terminal manage.py createsuperuser command. I am able to login on the webpage using this account.
testing123 was created using the registration form. It pulls up a message that says "Please enter a correct username and password".
Anyone have any ideas?
I am using a custom user model:
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
username = models.CharField(max_length=120,
unique=True,
blank=False,
validators=[MinLengthValidator(6)])
email = models.EmailField('Email Address', unique=True, blank=False)
FCM_ID = models.CharField(max_length=300)
I was hoping that I won't be allowed to create a user with blank email field, but for some reason, I can do so without any errors.
User().save() successfully adds a user with all blank fields. The unique condition, however, is enforced as expected. Why is blank=False not enforced?
Here's the custom user manager:
from django.contrib.auth.base_user import BaseUserManager
class CustomUserManager(BaseUserManager):
def create_user(self, email, **kwargs):
if not email:
raise ValueError("The email must be set")
email = self.normalize_email(email)
user = self.model(email=email, **kwargs)
user.save()
return user
def create_superuser(self, email, password, **kwargs):
...
Edit: I made the email field blank=False as well; but to no avail.
Unfortunately, blank=False is not enforced on the database level, it is only checked when you're validating model in your code, which is not happening by itself when calling save() on it. You need to invoke clean_fields at least before saving the model.
Read about validating models in Django docs.
If you are using Django models through DRF serializers or Django forms, they may do some validation as well, so refer to their documentation to find out how it will be handled.
So What I've been trying to do is to have my API view only return objects that have their attributes post_user to the current id of the logged in user. These post_user attributes are populated as whenever I post it populates the variable with the current user's id through my serializer.
However, I am not successful as it says request is not defined. I just want to get the current user's id so that I can use it to filter my object returns
views.py
# To retrieve and list all posts with DRF
class ListPosts(generics.ListCreateAPIView):
queryset = Posts.objects.get(post_user=request.user.id)
serializer_class = PostsSerializer
permission_classes = (permissions.IsAuthenticated,)
serializers.py
# serializer for posts to be taken
class PostsSerializer(serializers.ModelSerializer):
class Meta:
model = Posts
fields = ('id','post_title','post_content',)
def create(self, validated_data):
posts = Posts.objects.create(
post_title=validated_data['post_title'],
post_content=validated_data['post_content'],
# gets the id of the current user
post_user=self.context['request'].user.id,
)
posts.save()
return posts
error is in line
queryset = Posts.objects.get(post_user=request.user.id)
here request is not define at class declaration time. Solution is you can override the get_queryset method.
class ListPosts(generics.ListCreateAPIView):
queryset = Posts.objects.all()
serializer_class = PostsSerializer
permission_classes = (permissions.IsAuthenticated,)
def get_queryset(self, *args, **kwargs):
return Posts.objects.filter(post_user=self.request.user)
Inherit CreateModelMixin's features inside PostsSerializer and try to define your create() method like def create(request, *args, **kwargs).
Finally, you can try to get user id using request.user.id.
For a better documentation, you can check https://www.django-rest-framework.org/api-guide/generic-views/.
Also check what are Mixins and why do we use it (if you do not know).
For a little and brief definition, Mixins are just class with methods that can be mostly inherited and used by our views.
If you have any doubt, please comment.