i am new here in django python, I am learning 2 table relations, primary key foreign key scenario, for that i am using existing django user model and create another model userprofile, I want to list data of user and profile, so for that i have created rest api, when i do run api http://127.0.0.1:8000/api/v1/users/, it gives me this error : 'User' object has no attribute 'user'. here i have added my whole code, can anyone please look my code and help me to resolve this issue ?
models.py
from django.db import models
from django.contrib.auth.models import User
from django.contrib.auth import get_user_model
class Songs(models.Model):
# song title
title = models.CharField(max_length=255, null=False)
# name of artist or group/band
artist = models.CharField(max_length=255, null=False)
def __str__(self):
return "{} - {}".format(self.title, self.artist)
class UserProfile(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=255, null=False)
dob = models.CharField(max_length=255, null=False)
address = models.CharField(max_length=255, null=False)
country = models.CharField(max_length=255, null=False)
city = models.CharField(max_length=255, null=False)
zip = models.CharField(max_length=255, null=False)
photo = models.CharField(max_length=255, null=False)
def __str__(self):
return "{} - {}".format(self.title, self.dob, self.address, self.country, self.city, self.zip, self.photo,
self.user)
serializers.py
from rest_framework import serializers
from .models import Songs
from .models import UserProfile
from django.contrib.auth.models import User
class SongsSerializer(serializers.ModelSerializer):
class Meta:
model = Songs
fields = ("title", "artist")
class UserProfileSerializer(serializers.ModelSerializer):
class Meta:
model = UserProfile
fields = ('user', 'title', 'dob', 'address', 'country', 'city', 'zip', 'photo')
class UserSerializer(serializers.ModelSerializer):
user = UserProfileSerializer(required=True)
class Meta:
model = User
fields = ('url', 'email', 'first_name', 'last_name', 'password', 'user')
extra_kwargs = {'password': {'write_only': True}}
views.py
import rest_framework.generics
from rest_framework import generics
from .models import Songs
from .serializers import SongsSerializer
from .serializers import UserSerializer
from django.contrib.auth.models import User
from rest_framework import viewsets
class ListSongsView(generics.ListAPIView):
"""
Provides a get method handler.
"""
queryset = Songs.objects.all()
serializer_class = SongsSerializer
class UserViewSet(viewsets.ModelViewSet): #generics.ListAPIView, generics.RetrieveAPIView
# viewsets.ModelViewSet
queryset = User.objects.all()
#print(queryset.count());
#exit()
serializer_class = UserSerializer
First of all, I think you need to use a OneToOneField for the User - UserProfile relation. Otherwise, one user may have multiple profiles, which is not common practice.
Now regarding the problem, the User model doesn't have a user attribute. You need to use related_name to get access to the reverse related object.
To fix this problem, you can refactor your code to this:
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="user_profile")
class UserSerializer(serializers.ModelSerializer):
user_profile = UserProfileSerializer(required=True) # rename this field
class Meta:
model = User
fields = ('url', 'email', 'first_name', 'last_name', 'password', 'user_profile')
extra_kwargs = {'password': {'write_only': True}}
Related
I am trying to create an announcement website (All) that can be visible to others (the Users, for which I added an Account). For this I wanted to modify a little the user profile to add fields like telephone, email address...
So I modified admin.py:
from django.contrib import admin
from .models import Todo, Account
from django.contrib.auth.models import User
class AccountInline(admin.StackedInline):
model = Account
can_delete = False
verbose_name_plural = 'Accounts'
class TodoAdmin(admin.ModelAdmin):
readonly_fields = ('created',)
inlines = (AccountInline, )
admin.site.unregister(User)
admin.site.register(Todo, TodoAdmin)
But got back:
<class 'todo.admin.AccountInline'>: (admin.E202) 'todo.Account' has no ForeignKey to 'todo.Todo'.
So I added a ForeignKey to Todo with account = models.ForeignKey(Account, on_delete=models.CASCADE):
from django.db import models
from django.contrib.auth.models import User
class Account(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
email = models.CharField(max_length=100)
firstname = models.CharField(max_length=30)
lastname = models.CharField(max_length=50)
company = models.CharField(max_length=5)
def __str__(self):
return self.user.username
class Todo(models.Model):
title = models.CharField(max_length=100)
datetime = models.DateTimeField()
memo = models.TextField(blank=True)
created = models.DateTimeField(auto_now_add=True)
datecompleted = models.DateTimeField(null=True, blank=True)
important = models.BooleanField(default=False)
user = models.ForeignKey(User, on_delete=models.CASCADE)
account = models.ForeignKey(Account, on_delete=models.CASCADE)
def __str__(self):
return self.title
But I still have the error, and I don't have any Users in the admin panel anymore
You accidentally wrote unregister for Users in your admin.py file. It should be admin.site.register(User)
You misinterpretted the error: the error states that you don't have a foreign key in your Account model to Todo.
This means your inline admin code isn't correct as it's expecting the other way around.
I am creating a custom user class and then I am inheritance this user class to another two classes called Customer and Agent.
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.db.models.deletion import CASCADE
class User(AbstractUser):
username = models.CharField(max_length=50, blank=False, null=False, unique=True)
email = models.EmailField(('email address'), blank=False, null=False, unique=True)
phone_no = models.CharField(max_length=10)
isAgent = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username', 'first_name', 'phone_no']
def __str__(self):
return self.username
class Customer(User):
pass
class Agent(User):
company_name = models.CharField(max_length=150, default="", null=False, blank=False)
company_desc = models.CharField(max_length=1000, default="")
and then i am register this model class in admin pannel like this...
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import Customer, User, Agent, Destination, Trip, Payment
admin.site.register(User, UserAdmin)
#admin.register(Customer)
class CustomerAdmin(admin.ModelAdmin):
list_display = ['username', 'email']
#admin.register(Agent)
class AgentAdmin(admin.ModelAdmin):
list_display = ['username', 'email', 'company_name']
NOTE : I am also create a model classes like Destination,Trip,Payment just ignore this class...
but in my adminsite http://127.0.0.1:8000/admin/ it is how like this...
https://i.stack.imgur.com/D8sX3.png
==> user class name as "User" , Customer class name as "User" as well as Agent class name as "User"
soo why my orignal model class name is not occure..?
I'm new in Django rest framework, I tried my whole day but can't do it,I want to do full crud operation in my UserProfile Model which have a OneToOne field user, User can only update their own profile and in UserProfile create or update user shouldn't update User[username], How can i achieve it Please Help me
*** serializers.py ***
from rest_framework import serializers
from product.models import UserProfile
from django.contrib.auth.models import User
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = '__all__'
read_only_fields = ['username','password', ]
class UserProfileSerializer(serializers.ModelSerializer):
user = UserSerializer(many=False)
class Meta:
model = UserProfile
fields = "__all__"
def create(self, validated_data):
user_data = validated_data.pop('user')
user_instance = User.objects.get(
username=user_data['username'])
user_instance.save()
user_profile_instance = UserProfile.objects.create(
**validated_data, user=user_instance)
user_profile.save()
return user_profile
*** views.py ***
from django.shortcuts import render
from .serializers import UserProfileSerializer
from rest_framework.views import APIView
from rest_framework import generics, permissions
from rest_framework.response import Response
from rest_framework import status
from django.contrib.auth.models import User
from product.models import UserProfile
# Create your views here.
class CreateUserView(generics.ListCreateAPIView):
serializer_class = UserProfileSerializer
permission_classes = [permissions.IsAuthenticated,]
def get_queryset(self):
user = self.request.user
return UserProfile.objects.filter(user = user)
*** models.py ***
from django.db import models
from django.contrib.auth.models import User
from django.core.validators import MaxValueValidator, MinValueValidator
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='user_profile', on_delete=models.CASCADE)
country = models.CharField(max_length=50, default='India')
city = models.CharField(max_length=100, default='')
phone = models.CharField(max_length=15,default='')
image = models.ImageField(upload_to='profile_image', blank=True)
created_date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.user.username
For Authentication you can use token based authentication(like jwt)
and for username you can use read_only=True
no need to send the password for get request
to update profile you need to handle put/post methods
CLEANED Serializers:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = '__all__'
read_only_fields = ['username','password']
class UserProfileSerializer(serializers.ModelSerializer):
# REMOVED all unecessary overrides
user = UserSerializer(read_only=True)
class Meta:
model = UserProfile
fields = "__all__"
Views:
class UserProfileViewSet(viewsets.GenericViewSet,
mixins.UpdateModelMixin):
# Changed inherited class and class NAME !
# I assume that your endpoint is something like /users/me/profile
# I think you want only to update user profile
# Listing or creating profile here is bad - user should have only ONE profile
# and you should do this on user model post_save signal
serializer_class = UserProfileSerializer
permission_classes = [permissions.IsAuthenticated,]
def get_object(self):
return self.request.user.user_profile
This setup will allow you to update profile and only profile data
In your models file you can make signal listener for automatically creating UserProfile object on User object create.
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
I am building a backend for a web app using django rest framework. I have a profile model that has a user forieingkey referencing a django user. Everything is loading correctly except for one issue which is that the User field is not showing up in the django rest framework backend urls so that I can assign a user to the profile object i want to create... does anyone know why this is happening...
models.py:
class Profile(models.Model):
user = models.ForeignKey(
User, on_delete=models.CASCADE
)
synapse = models.CharField(max_length=25, null=True)
bio = models.TextField(null=True)
profile_pic = models.ImageField(
upload_to='./profile_pics/',
max_length=150
)
facebook = models.URLField(max_length=150)
twitter = models.URLField(max_length=150)
updated = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.user.username + ' profile'
viewset:
from users.models import Profile
from users.api.serializers.ProfileSerializer import ProfileSerializer
from rest_framework import viewsets
class ProfileViewSet(viewsets.ModelViewSet):
queryset = Profile.objects.all()
serializer_class = ProfileSerializer
lookup_field = 'user__username'
url:
from users.api.views.ProfileView import ProfileViewSet
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'', ProfileViewSet, base_name='profile')
urlpatterns = router.urls
serializer:
from rest_framework import serializers
from users.models import Profile
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = (
'id',
'user',
'synapse',
'bio',
'profile_pic',
'facebook',
'twitter'
)
depth=2
That happens when you set a depth bigger that 0, foreign key fields become not editable (if you send a POST with that field containing some value, DRF viewset would ignore it, and if the field is required, it will raise an exception).
One solution for that is to override to_representation() method of the serializer and set the depth and restore it to zero:
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = (
'id',
'user',
'synapse',
'bio',
'profile_pic',
'facebook',
'twitter'
)
def to_representation(self, instance):
self.Meta.depth = 2
representation = super().to_representation(instance)
self.Meta.depth = 0
return representation
I'm building a django restful json API using rest_framework libraries, however it returns empty json [ ] when I submit a request to it, even though there's plenty of records in the DB table. Here' my Code
models.py
class Member(models.Model):
email = models.EmailField()
mobile = models.CharField(max_length=11, null=False)
username = models.CharField(max_length=20, null= False, help_text="Username")
password = models.CharField(max_length=15, null=False, help_text="Password")
mobile_id = models.CharField(max_length=100, null=True, blank=True)
joined_date = models.DateTimeField(auto_now_add=True)
serializers.py
class MemberSerializer(serializers.Serializer):
class Meta:
model = Member
fields = ('email', 'mobile', 'username', 'joined_date')
views.py
class MemberAPI(viewsets.ModelViewSet):
serializer_class = MemberSerializer
queryset = Member.objects.all()
urls.py
router = DefaultRouter()
router.register(r'member', MemberAPI, base_name='member')
urlpatterns = router.urls
I got it now. It appears, I was inheriting a base generic class of serialize in
serializers.py
I should have inherited from ModelSerializer like this
class MemberSerializer(serializers.ModelSerializer):
class Meta:
model = Member
fields = ('email', 'mobile', 'username', 'joined_date')