django rest_framework caches sql queries - django

I am new to Django and React. I am taking over a Django / React project and have an issue where an api url is called:
GET /api/admin/parents/
but the underlying sql statement:
from django.http import HttpResponseRedirect
from django.db.models import Q
from .models import *
from rest_framework import permissions, status
from rest_framework.decorators import api_view, permission_classes
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.generics import ListAPIView, ListCreateAPIView, CreateAPIView, RetrieveUpdateAPIView, DestroyAPIView
from .serializers import *
from twilio.rest import Client
class AdminAllParentsView(ListAPIView):
serializer_class = UserSerializer
queryset = User.objects.filter(is_staff=False, is_parent=True, is_active=True)
does not get re-executed each time the GET /api/admin/parents/ call is performed.
Say for instance.. a sql record is changed so that there are fewer records matching the is_parent=True part of the api call / query... the results returned by the api call don't reflect the real / current status of the query. The GET /api/admin/parents/ still returns the data from a previous, sql query ( a cached version I assume ) and does not re-execute the query.
The urls.py part of this is:
from django.urls import path
from rest_framework_jwt.views import obtain_jwt_token
from .views import *
urlpatterns = [
path('admin/parents/', AdminAllParentsView.as_view())
So how to I get current sql data from this each time I do a api call?
jack
... I see in the browser that the /api/admin/parents/ request goes out and returns the old data via json data. It's not a cached browser html thing.
and
... here is the user serializer code... someone said that this might be important too.
from rest_framework import serializers
from rest_framework_jwt.settings import api_settings
from .models import *
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = (
'id',
'email',
'first_name',
'last_name',
'is_parent',
'phone',
'mobile_phone',
'address',
'city',
'zip',
'county',
'agency_name',
'caseworker_name',
'caseworker_email',
'caseworker_phone',
'caseworker_ext',
'is_active',
'agency_approved',
)
class UserSerializerWithToken(serializers.ModelSerializer):
token = serializers.SerializerMethodField()
password = serializers.CharField(write_only=True)
def get_token(self, obj):
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
payload = jwt_payload_handler(obj)
token = jwt_encode_handler(payload)
return token
def create(self, validated_data):
password = validated_data.pop('password', None)
instance = self.Meta.model(**validated_data)
if password is not None:
instance.set_password(password)
instance.save()
return instance
class Meta:
model = User
fields = '__all__'

Related

Django create user Direct assignment to the forward side of a many-to-many set is prohibited. Use groups.set() instead

I am using the Django default User model to do user registration. When I was trying to create a user I got this error message. Direct assignment to the forward side of a many-to-many set is prohibited. Use groups.set() instead.
# views.py
from django.contrib.auth.models import User
from rest_framework import viewsets
from app.serializers import UserSerializer
# Create your views here.
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
# serializers.py
from django.contrib.auth.models import User
from rest_framework import serializers
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = '__all__'
extra_kwargs = {'password': {'write_only': True, 'required': False}}
def create(self, validated_data):
print(validated_data)
user = User.objects.create_user(**validated_data)
return user
# urls.py
from django.urls import path, include
from rest_framework import routers
from app import views
from rest_framework.authtoken.views import obtain_auth_token
router = routers.SimpleRouter()
router.register(r'users', views.UserViewSet)
urlpatterns = [
path('auth/', obtain_auth_token),
]
urlpatterns += router.urls
I only insert the user record, there is no foreign table or many-to-many relationship. Not sure why the system throws this error.
Attached with the postman screenshot.

Django unit testing authentication token not accepted

I've checked the DRF official documentation, have read the below posts and copy-pasted code from some answers to avoid any typo, but I still can't authenticate in my unit tests. I always get a 401 response code.
I have a custom User model that just has a couple of none required fields so far.
Can anyone see any logic issue, or error in the code?
Could the issue originate from having a proper local DB and a testing DB and the authentication mixing both up somehow?
I've had to use self.client.force_authenticate(user=self.user, token=None) to bypass the authentication issue. But that defeats the purpose of the tests.
Checked posts that did not solve the problem:
DRF documentation
SO post 1
SO post 2
SO post 3
So here's my code.
Unit test
from django.test.testcases import SimpleTestCase
from django.urls import reverse, resolve
from rest_framework import status
from rest_framework.test import APITestCase
from rest_framework.authtoken.models import Token
from test_project.models.user import *
from test_project.views import UserViewSet
# from django.contrib.auth.models import User
from test_project.models import *
class UserAPIViewTests(APITestCase):
def setUp(self) -> None:
self.users_list_url = reverse('user-list')
self.users_detail_url = reverse('user-detail', args=[1])
self.user =User.objects.create(
username="admin",
password="admin",
email="test#necktie.com",
first_name="test first name",
last_name="test last name",
is_superuser=True,
is_staff=True,
is_active=True
)
self.token = Token.objects.create(user=user)
self.client.credentials(HTTP_AUTHORIZATION='Bearer ' + self.token.key)
# The testing DB is automatically torn down, no implementation required for those tests
def tearDown(self) -> None:
pass
def test_get_users_authenticated(self):
"""
Test that an authenticated user can get the users' list
"""
response = self.client.get(self.users_list_url)
self.assertEquals(response.status_code, status.HTTP_200_OK)
User model
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.utils.translation import gettext_lazy as _
class User(AbstractUser):
"""auth/login-related fields"""
gender = models.CharField(_('gender'), max_length=50, null=True)
nationality = models.CharField(_('nationality'), max_length=50, null=True)
def __str__(self):
return "{} {}".format(self.first_name, self.last_name)
User View
from rest_framework import viewsets
from rest_framework.response import Response
from rest_framework import permissions
from ..models.user import User
from ..serializers.user import *
from ..permissions import *
class UserViewSet(viewsets.ModelViewSet):
"""
This viewset automatically provides `list`, `create`, `retrieve`,
`update` and `destroy` actions.
"""
queryset = User.objects.all()
serializer_class = UserSerializer
def get_permissions(self):
"""
Method to apply permissions depending on request type (GET, PUT etc.)
"""
if self.request.method == 'GET':
return [permissions.IsAuthenticated(), IsStaff()]
else:
return [permissions.IsAuthenticated(), IsSuperuser()]
User serializers
from rest_framework import serializers
from ..models.user import User
class UserSerializer(serializers.ModelSerializer):
"""
Serializer for all actions on User model
"""
class Meta:
model = User
fields = [
'id',
'username',
'first_name',
'last_name',
'is_staff',
'is_superuser',
'is_active',
'date_joined'
]
Thanks for the help!

How to integrate mixpanel to django backend

I am new with integrating mixpanel to Django backend to track events,As i try to track, it gives me empty brackets anyone with ideas or resources please help me am quite stack
views.py
from django.shortcuts import render
from django.views import View
from rest_framework.generics import ListCreateAPIView
from rest_framework.views import APIView
from rest_framework.response import Response
from .serialize import UserSerializer, TweakSerializer, ChannelSerializer, SubscriberSerializer
from tweaks.models import Tweak
from accounts.models import User
from channels.models import Channel, Subscriber
from mixpanel import Mixpanel
import json
# Create your views here.
mp = Mixpanel('TOKEN')
class userApi(ListCreateAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
def get(self, request):
queryset = self.get_queryset()
serializer = UserSerializer(queryset, many=True)
return Response(serializer.data)
apiuser=userApi()
point = json.dumps(apiuser.__dict__)
mp.track(point, 'users')
serializers.py
from rest_framework import routers, serializers, viewsets
from django.urls import path, include
from accounts.models import User
from tweaks.models import Tweak
from channels.models import Channel, Subscriber
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = 'username', 'email', 'first_name', 'last_name', 'date_joined'

Retrieve data from Django API and store it in database

I created an API with django
What I want to do is to fetch data from my django API and store it in my database.
serializers.py
from rest_framework import serializers, generics
from Usersapi.models import Userdata
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Userdata
fields = '__all__'
viewsets.py
from Usersapi.models import Userdata
from .serializers import UserSerializer
from rest_framework import viewsets
class UserViewSet(viewsets.ModelViewSet):
queryset = Userdata.objects.all()
serializer_class = UserSerializer
main--> urls.py
from django.contrib import admin
from django.urls import include, path
from rest_framework.urlpatterns import format_suffix_patterns
from .router import router
urlpatterns = [
path('admin/', admin.site.urls),
# path('',include('Usersapi.urls')),
path('client/',include('clientside.urls')),
path('api/', include(router.urls))
]
This is where I am trying to retrieve data from API
clientside--> views.py
from django.shortcuts import render
import coreapi
import json
from django.views import generic
import io
from rest_framework.parsers import JSONParser
def home(request):
client = coreapi.Client()
response = client.get('http://127.0.0.1:8000/api/Usersapi/1/')
stream = io.BytesIO(response)
data = JSONParser().parse(stream)
name = data.get("name")
age = data.get("age")
gender = data.get("gender")
user = UserReceived.objects.create( name = name, age= age, gender = gender)
user.save()
return render(request, 'books.html')
This code is not working. How do I retrieve the data from ('http://127.0.0.1:8000/api/Usersapi/1/')
and store it in my models.py i.e database
clientside --> models.py
from django.db import models
class UserReceived(models.Model):
name = models.CharField(max_length=100)
age = models.PositiveIntegerField()
gender = models.CharField(max_length=50)
Your problem is that the corapi client already returns an ordered dict.
This will work:
def home(request):
client = coreapi.Client()
data = client.get('http://127.0.0.1:8000/api/usersapi/1/')
name = data.get("name")
age = data.get("age")
gender = data.get("gender")
user = UserReceived.objects.create(name=name, age=age, gender=gender)
user.save()
return HttpResponse(f"OKAY, got and saved user {name}")
I created a minimal working example here:
https://github.com/CarliJoy/MWE_SO_59668515

How I can show http 404 with djangofilterbackend?

django rest framework is showing http 202 ok when I set a wrong value and I want to show http 404 on the api django rest framework, when set a wrong value in djangofilterbackend but I don't know how to implement it.
my views.py:
from rest_framework import viewsets
from .models import Producto
from .serializers import ProductoSerializer
from django_filters.rest_framework import DjangoFilterBackend
class ProductoViewSet(viewsets.ModelViewSet):
filter_backends = [DjangoFilterBackend]
filterset_fields = ['Codigo_Producto']
queryset = Producto.objects.all()
serializer_class = ProductoSerializer
my serializers.py:
from .models import Producto
from rest_framework import serializers, viewsets
class ProductoSerializer(serializers.ModelSerializer):
Nombre_Producto = serializers.SerializerMethodField
class Meta:
model = Producto
fields = [
'id',
'Nombre_Producto',
'Codigo_Producto',
'Precio_sugerido',
'stock',
]
def get_Producto_name(self,obj:Producto):
return obj.Producto.get_full_name()
urls.py
from django.contrib import admin
from django.urls import path
from django.conf.urls import include
from rest_framework import routers
from GestionadorApp.views import ProductoViewSet
# Routers provide an easy way of automatically determining the URL conf.
router = routers.DefaultRouter()
router.register('Producto', ProductoViewSet)
# Wire up our API using automatic URL routing.
# Additionally, we include login URLs for the browsable API.
urlpatterns = [
path('api/', include(router.urls)),
path('admin/', admin.site.urls),
]
The way I found is overriding the filter backend to ensure that the parameters are what I want else raise a error Http404.
to show a solution I had to take part of code from Django Filter Backend
from rest_framework import filters
from django.http import Http404
class ObjektFilterBackend(filters.BaseFilterBackend):
allowed_fields = ['username', 'email']
def filter_queryset(self, request, queryset, view):
flt = {}
for param in request.query_params:
#put your logic here
if request.query_params[param] is None:
raise Http404
for fld in self.allowed_fields:
if param.startswith(fld):
flt[param] = request.query_params[param]
return queryset.filter(**flt)
class UserListView(generics.ListAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
filter_backends = [ObjektFilterBackend]
search_fields = ['username', 'email']
In another hand you may override the get_queryset method to ensure data too.
class UserListView(generics.ListAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
filter_backends = [DjangoFilterBackend]
search_fields = ['username', 'email']
def get_queryset(self):
username = self.request.query_params.get('username', None)
if username is None:
raise http404
return self.queryset
django rest framework filtering