Django REST framework:Use OneToOneField can't GET - python

when i use Django REST framework ,and use Use OneToOneField and RetrieveUpdateDestroyAPIView can't GET by pk;
my code are as follows:
models.py
class UserAccount(models.Model):
username = models.CharField(null=False, max_length=45)
password = models.CharField(null=False, max_length=16)
class UserContactInfo(models.Model):
userAccount = models.OneToOneField(UserAccount, primary_key=True)
phone_number = models.CharField(null=True, blank=True)
email = models.CharField(null=True, blank=True, max_length=45)
serializers.py
class UserAccountSerializer(serializers.ModelSerializer):
class Meta:
model = UserAccount
fields = ('id', 'username', 'password')
class UserContactInfoSerializer(serializers.ModelSerializer):
class Meta:
model = UserContactInfo
fields = ('userAccount', 'phone_number', 'email')
views.py
class UserContactInfoDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = UserAccount.objects.all()
serializer_class = UserContactInfoSerializer
urls.py
urlpatterns = [
...
url(r'^ContactInfo/(?P<pk>[0-9]+)/$', views.UserContactInfoDetail.as_view()),
]
Ok , when i try to GET UserContactInfo data:
GET http://127.0.0.1:8000/ContactInfo/1/
and go wrong:
AttributeError at /ContactInfo/1/
'UserAccount' object has no attribute 'userAccount_id'
Request Method: GET
Request URL: http://127.0.0.1:8000/ContactInfo/1/
.....
Who can help me to fix it . Thanks!

I think you have typo in a view, in a queryset:
queryset = UserAccount.objects.all() instead of UserContactInfo.objects.all()

Related

How to get UserProfile to reference the fields from UserModel?

Just an fyi, I'm pretty new to programming & Django in general. I've been teaching myself.
Before I get into the problem, I'll share my Django code:
models.py :
class User(AbstractUser):
# DATABASE FIELDS
email = models.EmailField(("email address"), unique=True)
REQUIRED_FIELDS = ['username']
USERNAME_FIELD = 'email'
# META
class Meta:
verbose_name = "User"
verbose_name_plural = "Users"
# TO STRING METHOD
def __str__(self):
return "User " + str(self.id) + " - " + self.email
class UserProfile(models.Model):
# RELATIONSHIP
user = models.ForeignKey(
to = User,
on_delete = models.CASCADE,
related_name = "user_account"
)
# DATABASE FIELDS
first_name = models.CharField(max_length=100, verbose_name="First Name")
last_name = models.CharField(max_length=100, verbose_name="Last Name")
date_created = models.DateField(auto_now=False, auto_now_add=False, verbose_name="Profile Created On")
role = models.CharField(max_length=255, verbose_name="User Demographic")
# META
class Meta:
verbose_name = "User Profile"
verbose_name_plural = "User Profiles"
# TO STRING METHOD
def __str__(self):
return self.first_name
forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from .models import User
class AbstractUserCreationForm(UserCreationForm):
class Meta:
model = User
fields = ('username', 'email')
class AbstractUserChangeForm(UserChangeForm):
class Meta:
model = User
fields = UserChangeForm.Meta.fields
serializers.py
from rest_framework import serializers
from djoser.serializers import UserCreateSerializer, UserSerializer
from . import models
from .models import User, UserProfile
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = models.User
fields = ('id', 'email', 'username', 'password')
class UserCreateSerializer(UserCreateSerializer):
class Meta(UserCreateSerializer.Meta):
model = User
fields = ('id', 'email', 'username', 'password')
class UserProfileSerializer(serializers.ModelSerializer):
class Meta:
model = UserProfile
fields = ("id", "user", "first_name", "last_name", "date_created", "role")
The User(AbstractUser) model comes with some default fields. Two of those default fields I'm trying to reference are :
first_name & last_name
What I'm trying to do is, get those two default fields to connect with my UserProfile Model so that, when I create my User and fill out those fields, it will also show up in my UserProfile without having to fill it out there and connect it with a user.
Does anyone have any advice on how to achieve this connection/reference of two models?
(Just as an addition, I'm also using React for my frontend framework and have the requests working. It was just now that I realized I needed those two fields/models to connect after creating my SignUp component.)
By default, ForeignKey refers to the primary key for relation. But we can also point to other fields using to_field parameter.
I haven't tried the below code yet. But you can do something like this in your models.py:
models.py
class UserProfile(models.Model):
# RELATIONSHIP
user = models.ForeignKey(
to = User,
on_delete = models.CASCADE,
related_name = "user_account"
)
# DATABASE FIELDS
first_name = models.ForeignKey(User, to_field="firstname_field", verbose_name="First Name")
last_name = models.ForeignKey(User, to_field="lastname_field", verbose_name="Last Name")
You can refer the document here.
You need just to declare in Userprofile as OnetoOneField without declaring the first_name and last_name because User model has been declaring those field
models.py
from django.contrib.auth import get_user_model()
class UserProfile(models.model):
user = models.OnetoOneField(get_user_model(), on_delete=models.CASCADE)

Unable to save relationship between two objects with Django Rest Framework

I am building a Django/React App to allow users to submit orders that need to go from A to B. The user initially saves the addresses in the database and then he/she selects it in the order form. When they submit I attempt to create a relationship in the database, I'm using Django Rest Framework serializers to create the Order object in the database.
Unfortunately, I'm unable to successfully save the items as I'm not properly linking the addresses to the order. Im getting the following error:
destinationAddress: ["Invalid value."]
originAddress: ["Invalid value."]
Models
class Order(models.Model):
originAddress = models.ForeignKey(Address, related_name="originAddress", null=True, on_delete=models.CASCADE)
destinationAddress = models.ForeignKey(Address, related_name="destinationAddress", null=True, on_delete=models.CASCADE)
packages = models.CharField("Packages", max_length=1024)
class Address(models.Model):
address_code = models.CharField(max_length=250)
contact = models.CharField("Contact", max_length=1024)
phone = models.CharField("Phone", max_length=20)
company = models.CharField("Company", max_length=250)
addressLine1 = models.CharField("Address line 1", max_length=1024)
addressLine2 = models.CharField("Address line 2", max_length=1024, blank=True)
postalCode = models.CharField("Postal Code", max_length=12)
city = models.CharField("City", max_length=1024)
state = models.CharField("State", max_length=250)
Serializers
class AddressSerializer(serializers.ModelSerializer):
class Meta:
model = Address
fields = '__all__'
class OrderSerializer(serializers.ModelSerializer):
originAddress = serializers.SlugRelatedField(
queryset=Address.objects.all(),
slug_field='pk'
)
destinationAddress = serializers.SlugRelatedField(
queryset=Address.objects.all(),
slug_field='pk'
)
class Meta:
model = Order
fields = ('id', 'packages', 'destinationAddress', 'originAddress')
ViewSets
class OrderViewSet(viewsets.ModelViewSet):
queryset = Order.objects.all()
permission_classes = [
permissions.AllowAny
]
serializer_class = OrderSerializer
class AddressViewSet(viewsets.ModelViewSet):
queryset = Address.objects.all()
permission_classes = [
permissions.AllowAny
]
serializer_class = AddressSerializer
Any ideas? Thanks
Solved it by replacing SlugRelatedField to PrimaryKeyRelatedField
class OrderSerializer(serializers.ModelSerializer):
originAddress = serializers.PrimaryKeyRelatedField(
queryset=Address.objects.all(), allow_null=True, required=False
)
destinationAddress = serializers.PrimaryKeyRelatedField(
queryset=Address.objects.all(), allow_null=True, required=False
)
class Meta:
model = Order
fields = ('id', 'packages', 'destinationAddress', 'originAddress')

Failing to lookup a field with a foreign key subfield in Django Rest Framework

I am using the django framework to serialize a django object. I have a profile model and the first field in the model is a foreignkey of the user object. I want to be able to pass a usename is the url patters for the profile. In the Views, I want to be able to take that username and go through the user foreignkey and find the profile with that username user. THis is what I have right now in my code:
Views.py
class ProfileListView(ListAPIView):
query_set = Profile.objects.all()
serializer_class = ProfileSerializer
class ProfileDetailView(RetrieveAPIView):
query_set = Profile.objects.all()
serializer_class = ProfileSerializer
lookup_field = 'user__username'
urls.py
path('profile/', ProfileListView.as_view()),
path('profile/<username>', ProfileDetailView.as_view()),
serializers.py
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = ('user', 'gender', 'phone', 'ip_address', 'dob_month', 'dob_day',
'dob_year', 'address_street', 'address_city', 'address_state',
'address_postal', 'address_country', 'profile_pic', 'role')
models.py
class Profile(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
gender = models.CharField(max_length=12, choices=GENDER_CHOICES) # entity type
phone = models.CharField(max_length=22)
ip_address = models.CharField(max_length=32)
dob_month = models.CharField(max_length=22, choices=MONTH_CHOICES)
dob_day = models.SmallIntegerField()
dob_year = models.SmallIntegerField()
address_street = models.CharField(max_length=140)
address_city = models.CharField(max_length=22)
address_state = USStateField()
address_postal = models.IntegerField()
address_country = models.CharField(max_length=22)
profile_pic = models.ImageField(upload_to='profile_pics/')
role = models.CharField(max_length=12, choices=ROLE_CHOICES)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.user.username + ' - ' + self.type
One way of doing is to override get_object method. Try like this:
class ProfileDetailView(RetrieveAPIView):
queryset = Profile.objects.all() # it should be queryset not query_set
serializer_class = ProfileSerializer
def get_object(self):
return self.queryset.get(user__username=self.kwargs.get('username')).first()
There are some alternate solutions as well. For that please check this answer in SO.

Django Rest Framework: Could not resolve URL for hyperlinked relationship using view name "post-detail"

I found a lot of answers to the similar issue, but none of them helped me.
I am new to the backend and Django, I already spent a few days trying figure out what I am doing wrong, but no success.
I would appreciate any help a lot!
So, when I call http://127.0.0.1:8000/users/{user_name}/
I am getting :
ImproperlyConfigured: Could not resolve URL for hyperlinked relationship using view name "post-detail". You may have failed to include the related model in your API, or incorrectly configured the lookup_field attribute on this field.
If I change HyperlinkedRelatedField on any other field it's working properly...
urls.py
app_name = 'api'
urlpatterns = [
url(r'^posts/(?P<post_id>\d+)/$', PostDetails.as_view(),
name='post-detail'),
url(r'^users/(?P<username>[\w\-]+)/$', UserPosts.as_view()),
]
views.py
class PostDetails(APIView):
"""
- GET a post
"""
def get(self, request, post_id):
post = Post.objects.get(id=post_id)
post_serializer = PostSerializer(post)
return Response(post_serializer.data)
class UserPosts(APIView):
"""
GET all user posts
"""
def get(self, request, username):
user = User.objects.get(username=username)
serializer = UserSerializer(user, context={'request': request})
return Response(serializer.data)
serializer.py
class UserSerializer(serializers.ModelSerializer):
posts = serializers.HyperlinkedRelatedField(many=True,
read_only=True,
view_name='post-detail',
lookup_field='id')
# Mandatory for UUID serialization
user_id = serializers.UUIDField()
class Meta:
model = User
exclude = ('id', 'password')
read_only_fields = ('created', 'username', 'posts',)
class PostSerializer(serializers.ModelSerializer):
author = UserSerializer()
class Meta:
model = Post
fields = '__all__'
models.py
class User(models.Model):
username = models.CharField(max_length=30, unique=True)
password = models.CharField(max_length=50)
email = models.EmailField(unique=True)
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
phone = models.CharField(max_length=20, blank=False, unique=True)
user_id = models.UUIDField(editable=False,
unique=True,
null=False,
db_index=True,)
created = models.DateTimeField()
id = models.BigAutoField(primary_key=True)
class Meta:
ordering = ('created',)
def __unicode__(self):
return "Email: %s " % self.email
class Post(models.Model):
created = models.DateTimeField()
is_active = models.BooleanField(default=False)
title = models.CharField(max_length=200, blank=False)
body_text = models.CharField(max_length=1000, blank=False)
address = models.CharField(max_length=100)
author = models.ForeignKey(User, on_delete=models.PROTECT,
related_name='posts')
price = models.DecimalField(max_digits=10, decimal_places=0)
id = models.BigAutoField(primary_key=True)
class Meta:
ordering = ('created',)
def __unicode__(self):
return "Title : %s , Author: %s " % (self.title, self.author)
Your lookup_field does not match your url one which is post_id
url(r'^posts/(?P<post_id>\d+)/$', PostDetails.as_view(),
name='post-detail'),
From docs:
lookup_field - The field on the target that should be used for the lookup. Should correspond to a URL keyword argument on the referenced view. Default is 'pk'.
lookup_url_kwarg - The name of the keyword argument defined in the URL conf that corresponds to the lookup field. Defaults to using the same value as lookup_field.
So you should be fine with this:
posts = serializers.HyperlinkedRelatedField(many=True,
read_only=True,
view_name='post-detail',
lookup_url_kwarg='post_id')

Django Rest Framework - nested objects not being generated properly

I am trying to implement simple api in Django Rest Framework.
I have following models in models.py:
class Entry(BaseModel):
company_name = models.CharField(max_length=256, null=True, blank=True)
first_name = models.CharField(null=True, default=None, max_length=32)
last_name = models.CharField(null=True, default=None, max_length=32)
code = models.CharField(null=True, default=None, max_length=12)
class Meta:
db_table = 'entry'
class Admin(admin.ModelAdmin):
list_display = ('company_name', 'code')
list_display_links = ('company_name', )
ordering = ('-created',)
class EntryContactData(BaseModel):
entry = models.ForeignKey(Entry, related_name='contact')
email = models.CharField(max_length=256, null=True, blank=True)
website = models.CharField(max_length=64, null=True, blank=True)
phone = models.CharField(max_length=64, null=True, blank=True)
My API serializers.py:
from django.contrib.auth.models import User, Group
from rest_framework import serializers
from core.models import Entry, EntryContactData
class EntryContactSerializer(serializers.ModelSerializer):
class Meta:
model = EntryContactData
fields = ('uuid', 'email', 'website', 'phone')
class EntrySerializer(serializers.ModelSerializer):
contact = EntryContactSerializer(many=False, read_only=True)
class Meta:
model = Entry
fields = ('uuid', 'company_name', 'first_name', 'last_name', 'contact')
And my API views:
from core.models import Entry
from .serializers import EntrySerializer
class EntryViewSet(viewsets.ViewSet):
"""
A simple ViewSet for listing or retrieving users.
"""
queryset = Entry.objects.all()
def retrieve(self, request, pk=None):
queryset = Entry.objects.all()
entry = get_object_or_404(queryset, code=pk)
serializer = EntrySerializer(entry, context={'request': request})
return Response(serializer.data)
When I want to retrieve single entry its contact field is empty:
{
"uuid": "e6818508-a172-44e1-b927-3c087d2f9773",
"company_name": "COMPANY NAME",
"first_name": "FIRSTNAME",
"last_name": "LASTTNAME",
"contact": {}
}
So it doesn't contain any of fields defined in EntryContactSerializer
What am I doing wrong? How can I force it to return all fields included in serializer? Thank you guys.
Try setting many=True in EntrySerializer, and provide a source attribute to the serializer,
class EntrySerializer(serializers.ModelSerializer):
contact = EntryContactSerializer(source='contact', many=True, read_only=True)
class Meta:
model = Entry
fields = ('uuid', 'company_name', 'first_name', 'last_name', 'contact')

Categories