While creating API'S I'm using queryset on my model and trying to get only the data owned by the logged in users, but I'm getting some errors.
Console Log
from . import views
File "F:\coding and stuff\finMSG\chatbot\chatbotapi\views.py", line 8, in <module>
class queryViewSet(viewsets.ModelViewSet):
File "F:\coding and stuff\finMSG\chatbot\chatbotapi\views.py", line 10, in queryViewSet
queryset = query.objects.filter(user=self.request.user)
NameError: name 'self' is not defined
Models.py
# Create your models here.
# models.py
from django.db import models
from django.contrib.auth.models import User
class query(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
referencetoken = models.CharField(max_length=60)
question = models.CharField(max_length=60)
def __str__(self):
return self.referencetoken
Views.py
from rest_framework import viewsets
from .serializers import querySerializer, BotSocialConfigSerializer, SkillsSerializer, BotsSerializer
from .models import query, BotSocialConfig, Intents, Skills, Bots
from rest_framework.permissions import IsAuthenticated
# Create your views here.
class queryViewSet(viewsets.ModelViewSet):
permission_classes = (IsAuthenticated,)
queryset = query.objects.filter(user=self.request.user)
serializer_class = querySerializer
How can I get data only for user that is currently logged in.
Remove the query-set attribute and overwrite the get_queryset method
def get_queryset(self):
queryset = query.objects.filter(user=self.request.user)
return queryset
Related
I was wondering what the correct way is to get the current email of the user by default in a different serializer based on the selected "userid".
I have tried many examples from the ModelSerializer docs but without success.
serializers.py
from rest_framework import serializers
from ticker.models import Ticker
from users.models import NewUser
from rest_framework.permissions import IsAuthenticated
from alerts.models import SectionAlerts
from users.serializers import UserlistSerializer
from rest_framework.fields import CurrentUserDefault
class TickerSerializer(serializers.ModelSerializer):
class Meta:
model = Ticker
fields = "__all__"
class UserlistSerializer(serializers.ModelSerializer):
class Meta:
model = NewUser
fields = "__all__"
class AlertsSerializer(serializers.ModelSerializer):
ticker = TickerSerializer(read_only=True)
email = UserlistSerializer(read_only=True)
ticker_id = serializers.SlugRelatedField(
queryset=Ticker.objects.all(), source="ticker", slug_field='crypto', write_only=True
)
class Meta:
model = SectionAlerts
fields = "__all__"
models.py
from django.db import models
from ticker.models import Ticker
from django.conf import settings
from import_export.resources import ModelResource
from import_export.fields import Field
from users.models import NewUser
from django.core.mail import EmailMessage
class SectionAlerts(models.Model):
id = models.AutoField(primary_key=True) # auto increment field
valuenow = models.FloatField(null=True, blank=True, default=None)
valuealarm = models.FloatField(null=True, blank=True, default=None)
user = models.CharField(max_length = 40,blank=True, null=True)
userid = models.ForeignKey(
NewUser, related_name='userid',
blank=True,
null=True,
on_delete=models.CASCADE,
)
email = models.ForeignKey(NewUser, blank=True, null=True, on_delete=models.CASCADE)
ticker = models.ForeignKey(Ticker, blank=True, null=True, on_delete=models.CASCADE)
The goal: anytime that the "Current Value" of a crypto is lower than the previously set "Value Alert", the backend is sending an email notification to the user.
The problem: at the moment all users receive that email notification, while just each individual logged in user that created
their own alerts should receive it.
Question: how can i add just the email of the user that created the individual alert?
views.py
from email import message
from rest_framework import generics
from rest_framework import status
from .serializers import AlertsSerializer, TickerSerializer, UserlistSerializer
from users.serializers import CustomUserSerializer
from .models import SectionAlerts, Ticker, NewUser
import requests
import logging
from itertools import chain
from importlib import reload
import sys
import csv
from django.http import HttpResponse
from django.shortcuts import render
from rest_framework.views import APIView
from rest_framework.settings import api_settings
from rest_framework.response import Response
from .utils import Util
from django.urls import reverse
from django.shortcuts import redirect
class CreateSectionAlerts(generics.CreateAPIView):
def perform_create(self, serializer):
serializer.save(user=self.request.user)
print("New alert is saved")
serializer_class = AlertsSerializer
class ListSectionAlerts(generics.ListAPIView):
queryset = SectionAlerts.objects.all()
serializer_class = AlertsSerializer
# ------- EMAIL STARTS HERE
def get_queryset(self):
print("****ALERTS START get_querysetdavid")
queryset = SectionAlerts.objects.filter(userid=self.kwargs["pk"])
for b in SectionAlerts.objects.filter(userid=self.kwargs["pk"]):
# print("b---Print just mail", b.email)
print("b---Print SectionAlerts", b.id, b.valuenow, b.userid, b.ticker.c_0)
for c in NewUser.objects.all():
if b.ticker.c_0 < b.valuealarm:
print("Alert is achieved and must be sent")
email_body = 'Hi ' + c.user_name + ', you received this message because the value of the crypto ' + str(b.ticker) + ' is now ' + str(b.ticker.c_0) +'€.' + ' and reached the alert value of ' + str(b.valuealarm) +'€.' + '\n'+ 'This email confirms this event. \n' + 'Click here https://www.cryptothlon.com to signin in your account and know more. \n' +'\n'+ 'Your Cryptothlon Team'
data={'email_body': email_body, 'to_email': c.email,
'email_subject': 'Crypto alert'}
Util.send_email(data)
print("Email sent")
try:
record = SectionAlerts.objects.get(id = b.id )
record.delete()
print("Record deleted successfully!")
except:
print("Record doesn't exists")
# email method ends here
return queryset
# ------- EMAIL ENDS HERE
class DeleteSectionAlerts(generics.RetrieveDestroyAPIView):
queryset = SectionAlerts.objects.all()
serializer_class = AlertsSerializer
You can use SerializerMethodField. It will allow you to create a custom field in the serializer. By default SerializerMethodField looks for a method get_<field name>, and performs the according logic:
from users.models import NewUser
class AlertsSerializer(serializers.ModelSerializer):
...
email = serializers.SerializerMethodField()
class Meta:
model = SectionAlerts
fields = "__all__"
def get_email(self, obj):
user_id = self.initial_data['userid'] # get the `userid` from the request body
user = NewUser.objects.get(pk=user_id) # fetch the user from DB
return UserlistSerializer(instance=user).data
You don't show the NewUser model so not sure exactly what field you need, but you can use dot notation for the source of a serializer field.
From DRF docs:
The name of the attribute that will be used to populate the field. May be a method that only takes a self argument, such as URLField(source='get_absolute_url'), or may use dotted notation to traverse attributes, such as EmailField(source='user.email').
See this section of the docs: https://www.django-rest-framework.org/api-guide/fields/#core-arguments
Django 2.2 and Rest Framework 3.11
I have an Alarm model. Every alarm instance can optionally have an owner (the standard django User model).
I want to be able to partially update (PATCH) an alarm by setting its owner just using his/her username (string) instead of the pk.
Right now, I can update an alarm's owner only by using his/her pk.
I tried various things, like:
override the update() method in the AlarmSerializer class but whenever I use the owner's username string instead of the pk in the PATCH call, I get back:
{
"owner": [
"Incorrect type. Expected pk value, received str."
]
}
play with nested serializers and lookup_field but no luck so far.
The api call (PATCH) should look like this:
url: /api/alarms/{alarm_id}/
Payload:
{
"owner": "owner_username"
}
How can I do that? Thanks
models.py
from django.db import models
from django.conf import settings
class Alarm(models.Model):
"""
this class is meant to represent a network alarm (a.k.a. event or ticket)
coming from some monitoring system (Zabbix, Nagios, etc.)
"""
customer = models.CharField(max_length=50)
owner = models.ForeignKey(
settings.AUTH_USER_MODEL,
models.SET_NULL,
blank=True,
null=True,
)
managed = models.BooleanField(default=False, blank=False, verbose_name="Managed ?")
device_type = models.CharField(max_length=150)
...
serializers.py
from django.contrib.auth.models import User
from rest_framework import serializers
from .models import Alarm
class AlarmSerializer(serializers.ModelSerializer):
class Meta:
model = Alarm
fields = [
"customer",
"owner",
"device_type",
"device_name",
"ip_address",
"date",
]
views.py
from rest_framework import viewsets
from .models import Alarm
from .serializers import AlarmSerializer
# Create your views here.
class AlarmViewSet(viewsets.ModelViewSet):
queryset = Alarm.objects.all()
serializer_class = AlarmSerializer
I found a solution: convert the owner username string in pk inside the ModelViewSet.
You need to override the partial_update() method inside the ModelViewSet in views.py.
This view gets hit by the api PATCH call before serialization validation kicks in; hence this is the correct place to swap the username string with the username pk.
views.py
from django.contrib.auth.models import User
from django.shortcuts import get_object_or_404
from rest_framework import viewsets
from rest_framework.response import Response
from .models import Alarm
from .serializers import AlarmSerializer
class AlarmViewSet(viewsets.ModelViewSet):
queryset = Alarm.objects.all()
serializer_class = AlarmSerializer
def partial_update(self, request, *args, **kwargs):
instance = self.get_object()
# if the owner field is not a string, it should be
# a legit pk, so we don't do anything.
if isinstance(request.data["owner"], str):
owner_username = request.data.pop("owner")
owner = get_object_or_404(User, username=owner_username)
request.data["owner"] = owner.pk
serializer = self.serializer_class(instance, data=request.data, partial=True)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data)
This question seems to be asked before but none of the answers I came across solve my issue.
I'm getting the following error when I try running the server with python manage.py runserver:
django.core.exceptions.ImproperlyConfigured: The included URLconf 'tutorial.urls' does not appear to have any patterns in it. If you see valid patterns in the file then the issue is probably caused by a circular import.
The error goes away if I change models.py so that my Item class does not extend models.Model.
These are the relevant files:
models.py
from django.db import models
from django.contrib.auth.models import User
class Item(models.Model):
name = models.CharField(max_length=255)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
price = models.DecimalField(decimal_places=2)
def __str__(self):
return self.name
serializers.py
from rest_framework import serializers
from django.contrib.auth.models import User, Group
from .models import Item
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ('url', 'username', 'email', 'groups')
class GroupSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Group
fields = ('url', 'name')
class ItemSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Item
fields = ('url', 'name', 'owner', 'price')
views.py
from django.contrib.auth.models import User, Group
from rest_framework import viewsets
from .serializers import UserSerializer, GroupSerializer, ItemSerializer
from .models import Item
class UserViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows users to be viewed or edited.
"""
queryset = User.objects.all().order_by('-date_joined')
serializer_class = UserSerializer
class GroupViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows groups to be viewed or edited.
"""
queryset = Group.objects.all()
serializer_class = GroupSerializer
class ItemViewSet(viewsets.ModelViewSet):
"""
API endpoint that allows items to be viewed or edited.
"""
queryset = Item.objects.all()
serializer_class = ItemSerializer
urls.py
from django.urls import include, path
from rest_framework import routers
from tutorial.quickstart import views
router = routers.DefaultRouter()
router.register('users', views.UserViewSet)
router.register('groups', views.GroupViewSet)
router.register('items', views.ItemViewSet)
urlpatterns = [
path('', include(router.urls)),
path('api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]
The user is authenticated using allauth. I want to create a profile and set the authenticated user as the owner of the profile. How can I get the user?
Model class:
from django.db import models
from allauth.utils import get_user_model
from courses.models import Course
class Profile(models.Model):
owner = models.OneToOneField(get_user_model(), on_delete=models.CASCADE)
courses = models.ManyToManyField(Course, blank=True)
def get_courses_items(self):
return self.courses.all()
def __str__(self):
return self.owner.username
Views:
from rest_framework.generics import CreateAPIView
from profiles.models import Profile
from .serializers import ProfileSerializer
class ProfileCreateView(CreateAPIView):
queryset = Profile.objects.all()
serializer_class = ProfileSerializer
You can get the user from the request with request.user. Then probably you should override the def create method of the CreateAPIView to use that user and create the object.
set your user model in the settings file (base.py) and import it
AUTH_USER_MODEL = 'users.User' #(format is module.user model name)
from django.conf import settings
user = models. OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
method 2
Override the get_create method of the ProfileView. Every authenticated request has a request.user object in it which represents the user making the request. To get the user's id with this you just run request.user.id
class ProfileCreateView(CreateAPIView):
queryset = Profile.objects.all()
serializer_class = ProfileSerializer
def create(self, request, *args, **kwargs):
user = User.objects.get(id=request.user.id)
# create the profile and save it
...
in your serializers you can also get the current user this way
from rest_framework.serializers import CurrentUserDefault, PrimaryKeyRelatedField
class ProfileModelSerializer(ModelSerializer):
user = PrimaryKeyRelatedField(read_only=True, default=CurrentUserDefault())
class Meta:
...
I don't know how the remainder of your setup is but any or a combination of these works
I am new to Django and I am trying to learn by practicing with some project but I am stuck with this problem, I want to return the information of the History model to the authenticated user according to its id_user. The problem appears when the user gives the submit of the form.
The message that he gives me is this:
NOT NULL constraint failed: history.user_id
models.py
from django.db import models
from django.contrib.auth.models import User
class History(models.Model):
DAY35 = '35 days'
DAY45 = '45 days'
HISTORY_DAYS = (
(DAY35, '35 days'),
(DAY45, '45 days'),
)
user = models.ForeignKey(User, on_delete=models.CASCADE)
amount = models.FloatField(default=10)
days = models.CharField(
max_length=7,
choices=HISTORY_DAYS,
default=DAY35,
)
def is_upperclass(self):
return self.days in (self.DAY35, self.DAY45)
views.py
from django.utils.decorators import method_decorator
from django.contrib.auth.decorators import login_required
from django.views.generic.edit import CreateView
from .forms import HistoryForm
from .models import History
#method_decorator(login_required, name='dispatch')
class HistoryCreate(CreateView):
model = History
fields = ['amount', 'days']
success_url = reverse_lazy('history')
form_class = HistoryForm
forms.py
from django import forms
from .models import MiningHistory
class HistoryForm(forms.ModelForm):
class Meta:
model = History
fields = ['amount', 'days']
widgets = {
'amount': forms.NumberInput(attrs={'class':'x', 'placeholder':'0.00'}),
'days': forms.Select(attrs={'class':'x'}),
}
A History instance must have a non null user field. However you are not specifying the user related the History object you're creating.
In case you dont want to add the user, update you're model's user field :
user = models.ForeignKey(User, on_delete=models.CASCADE,blank=True,null=True)
If you want to associate the user field with the logged in user, update your views :
#method_decorator(login_required, name='dispatch')
class HistoryCreate(CreateView):
model = History
fields = ['amount', 'days']
success_url = reverse_lazy('history')
form_class = HistoryForm
def form_valid(self, form_class ):
form_class.instance.user= self.request.user
return super().form_valid(form)
Don't forget to add user to your form fields.
PS : Don't add user to your views modifiable fields. Check this for more details.