Hello, I need some assistance. I’m getting an error message when I run an automated test on my user profile api endpoint with DRF.
Maybe I set up the test incorrectly, but I tried creating the test similarly to my login/register api tests. Also, this problem is related to the UI issue I’m currently having with the frontend VueJS api call in my HomeownerDashboard
(profile page) when I register as a dummy user account and try to access or navigate to the homeowner dashboard page.
I inspected the network tab and that’s what revealed the UI error on the right side. But my main objective now, is to debug this error traceback. Here is the error
show_sunset_warning()
System check identified no issues (0 silenced).
.E.
======================================================================
ERROR: test_profile (arborfindr.test.test_profile.HomeownerProfileTest.test_profile)
----------------------------------------------------------------------
TypeError: HomeownerProfileTest.test_profile() missing 1 required positional argument: 'user_id'
----------------------------------------------------------------------
Ran 3 tests in 1.088s
FAILED (errors=1)
Destroying test database for alias 'default'...
test_register.py
from django.urls import reverse
from rest_framework import status
from rest_framework.test import APITestCase
from ..models import User
class UserRegisterTests(APITestCase):
def test_register_user(self):
url = reverse('arborfindr:register')
data = {'email': 'myemail@mail.com', 'username': 'jonedoe12', 'password': 'mypassword123'}
response = self.client.post(url, data, format='json')
self.assertTrue(User.objects.filter(username='jonedoe12').exists())
user = User.objects.get(username='jonedoe12')
self.assertEqual(user.email, 'myemail@mail.com')
self.assertTrue(user.check_password('mypassword123'))
serializer.py
from rest_framework import serializers
from django.contrib.auth import authenticate
from .models import User, HomeownerUser
from .search_indexes import ArboristCompanyIndex, ServiceTypeIndex
from drf_haystack.serializers import HaystackSerializer
class RegisterSerializer(serializers.ModelSerializer):
password = serializers.CharField(style={'input_type': 'password'}, write_only=True)
class Meta:
model = User
fields = ['email', 'username', 'password']
extra_kwargs = {
'password': {'write_only': True}
}
def validate(self, valid):
if valid['password'] != valid['password']:
raise serializers.ValidationError({"password": "Passwords do not match."})
return valid
def create(self, validated_data):
user = User.objects.create_user(
email=validated_data['email'],
username=validated_data['username'],
password=validated_data['password']
)
return user
class LoginSerializers(serializers.ModelSerializer):
email = serializers.CharField(max_length=255)
password = serializers.CharField(
label =("Password"),
style={'input_type': 'password'},
trim_whitespace=False,
max_length=128,
write_only=True
)
def validate(self, data):
email = data.get('email')
password = data.get('password')
if email and password:
user = authenticate(request=self.context.get('request'),
email=email, password=password)
if not user:
msg = ('Invalid email/password')
raise serializers.ValidationError(msg, code = 'Authorization')
else:
msg = ('Must include valid "email" and "password".')
raise serializers.ValidationError(msg, code = 'Authorization')
data['user'] = user
return data
class HomeownerProfileSerializer(serializers.ModelSerializer):
class Meta:
model = HomeownerUser
fields = ['profile_pic', 'street_address', 'homeowner_city', 'homeowner_state', 'homeowner_zip_code']
class ServiceTypeSerializer(HaystackSerializer):
class Meta:
index_class = [ServiceTypeIndex]
fields = ['text', 'name']
class CompanySerializer(HaystackSerializer):
class Meta:
index_class = [ArboristCompanyIndex]
fields = [
'text', 'company_name', 'company_city', 'company_state'
]
views.py
@authentication_classes([JWTAuthentication])
class LoginView(APIView):
authentication_classes = (JWTAuthentication,) # Keep as tuple if you prefer
def post(self, request, *args, **kwargs):
serializer = LoginSerializers(data=request.data, context={'request': request})
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']
login(request, user) # Corrected: Pass the request object
token = Token.objects.create(user=user) # Auth Token
if user is not None: # This block is now reachable
# Generate token
refresh = RefreshToken.for_user(user)
access_token = str(refresh.access_token)
return Response({
'message': 'Successful login',
'access_token': access_token,
'refresh_token': str(refresh),
"Token": token.key # Added auth token
}, status=status.HTTP_200_OK)
return Response({'error': 'Invalid email/password'}, status=status.HTTP_401_UNAUTHORIZED) # Now reachable
@authentication_classes([JWTAuthentication])
class RegisterView(APIView):
authentication_classes = (JWTAuthentication)
def post(self, request):
serializer = RegisterSerializer(data=request.data, context={'request': request})
if serializer.is_valid():
serializer.save()
return Response({
'message': 'successfully registered', }, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@authentication_classes([JWTAuthentication])
class PasswordUpdateView(APIView):
authentication_classes = (JWTAuthentication)
def update_password(request):
if request.method == 'POST':
form = PasswordChangeForm(request.user, request.POST)
if form.is_valid():
user = form.save()
update_session_auth_hash(request, user) # To keep the user logged in
return redirect('search_index/arborfindr/search_arborist.html')
else:
form = PasswordChangeForm(request.user)
return render(request, 'registration/update_password.html', {'form': form})
@authentication_classes([JWTAuthentication])
class HomeownerProfileView(APIView):
permission_classes = [DjangoModelPermissionsOrAnonReadOnly]
authentication_classes = (JWTAuthentication)
serializer_class = HomeownerProfileSerializer
def get(self):
username = self.kwargs['username']
obj = get_object_or_404(User, username=username)
return obj
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
@authentication_classes([JWTAuthentication])
class CompanySearchView(HaystackViewSet):
permission_classes = [DjangoModelPermissionsOrAnonReadOnly]
authentication_classes = (JWTAuthentication)
serializer_class = CompanySerializer
index_classes = [ArboristCompanyIndex]
def get_queryset(self):
query = self.request.GET.get('q', '')
queryset = SearchQuerySet().filter(text=query).facet('company_name', 'company_city', 'company_state', 'experience')
return queryset
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
facets = queryset.facets()
serializer = self.get_serializer(queryset, many=True)
return Response({'search_results': serializer.data, 'facets': facets}, status=status.HTTP_200_OK)
@authentication_classes([JWTAuthentication])
class ServicesTypeView(HaystackViewSet):
permission_classes = [DjangoModelPermissionsOrAnonReadOnly]
authentication_classes = (JWTAuthentication)
serializer_class = ServiceTypeSerializer
index_classes = [ServiceTypeIndex]
def get_queryset(self):
query = self.request.GET.get('q', '')
queryset = SearchQuerySet().filter(text=query)
service_type = self.request.GET.get('service_type')
if service_type:
queryset = queryset.filter(name=service_type)
facets = queryset.facets()
return Response({'facets': facets}, status=status.HTTP_200_OK)
urls.py
from django.urls import path
from .views import services_info
from . import views
from django.contrib.auth import views as auth_views
from django.conf import settings
from django.conf.urls.static import static
from .views import RegisterView, LoginView, HomeownerProfileView, CompanySearchView, PasswordUpdateView, ServicesTypeView
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
from rest_framework import routers
router = routers.DefaultRouter()
router.register(r'company/search', CompanySearchView, basename='company-search')
router.register(r'tree/services', ServicesTypeView, basename='tree-services')
app_name = 'arborfindr'
urlpatterns = [
path('register/', RegisterView.as_view(), name='register'), # Register API endpoint url
path('login/', LoginView.as_view(), name ='login'), # Login API endpoint url
path('logout/', auth_views.LogoutView.as_view(), name='logout'),
path('update/password', PasswordUpdateView.as_view(), name='update-password'),
path('homeowner/profile/', HomeownerProfileView.as_view(), name='homeowner'),
path('token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
So that’s all of my files. Also any suggestions on how to improve my api test/view for profile user would be great. I want to make the sure the frontend homeowner dashboard is able to retrieve data by communication with my backend profile page api endpoint properly.
Thank you. Anything else I can provide to clear this, please let me know