I am using Django-rest-auth to authenticate my users, that works well. how my model is set up is that I have the custom user model for authentication and I also have a profile model that gets created with a signal whenever a user is created.
I want that when the users are fetched in its URL, the profile for that user is also displayed, and I have passed through the serializer.
THE PROBLEM: I am getting null instead of the actual data
my models.py (I didnt include some models like the user managers, skill, e.t.c as i felt they werent relevant)
class User(AbstractBaseUser, PermissionsMixin):
username = None
email = models.EmailField(max_length=254, unique=True)
fullname = models.CharField(max_length=250)
is_staff = models.BooleanField(default=False)
is_superuser = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
last_login = models.DateTimeField(null=True, blank=True)
date_joined = models.DateTimeField(auto_now_add=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['fullname']
objects = UserManager()
class Profile(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='profiles')
date_of_birth = models.DateField(blank=True, verbose_name="DOB", null=True)
bio = models.TextField(max_length=500, blank=True, null=True)
profile_photo = models.CharField(blank=True, max_length=300, null=True)
skills = models.ManyToManyField(Skill, related_name='skills')
sex = models.CharField(max_length=1, choices=SEX, blank=True, null=True)
type_of_body = models.CharField(max_length=8, choices=BODYTYPE, blank=True, null=True)
feet = models.PositiveIntegerField(blank=True, null=True)
inches = models.PositiveIntegerField(blank=True, null=True)
lives_in = models.CharField(max_length=50, blank=True, null=True)
updated_on = models.DateTimeField(auto_now_add=True)
the serializers.py code
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = "__all__"
read_only_fields = ('pk',)
class CustomUserDetailsSerializer(serializers.ModelSerializer):
profiles = ProfileSerializer(read_only=True)
class Meta:
model = User
fields = ('pk', 'email', 'fullname', 'profiles')
read_only_fields = ('email', 'fullname', 'profiles')
view.py
class ListUsersView(APIView):
permission_classes = [AllowAny]
def get(self, request):
user = User.objects.all()
serializer = CustomUserDetailsSerializer(user, many=True)
return Response(serializer.data)
urls.py
url(r'^list-users/$', ListUsersView.as_view(), name='list-users'),
the JSON response I get
[
{
"pk": 1,
"email": "opeyemiodedeyi#gmail.com",
"fullname": "opeyemi odedeyi",
"profiles": {
"date_of_birth": null,
"bio": null,
"profile_photo": null,
"sex": null,
"type_of_body": null,
"feet": null,
"inches": null,
"lives_in": null
}
}
]
how do I get the profiles to show in the response?
I guess the problem is in your CustomUserDetailsSerializer. you have one-to-many relationship with User and Profile, but you are not explicitly telling it in your profiles attribute of the serializer. You have to pass many=True argument to the ProfileSerializer:
class CustomUserDetailsSerializer(serializers.ModelSerializer):
profiles = ProfileSerializer(many=True, read_only=True)
class Meta:
model = User
fields = ('pk', 'email', 'fullname', 'profiles')
read_only_fields = ('email', 'fullname', 'profiles')
But I am curious why you are using one-to-many relationship for that. You could use OneToOneField which explicitly tells that one user can only have one profile. But I am not familiar with your situation, so that is only my advice.
Related
This is the model that I want to show on the admin panel. I'm registering the model via admin.py file with admin.site.register(Ad). I tried to re-write the register line twice, and an exception appeared that the model is already registered.
class Ad(AdModel):
plate = models.CharField(max_length=50, unique=True)
description = models.TextField(max_length=500)
ad_type = models.CharField(
max_length=255,
choices=AdTypes.get_choices(),
default=AdTypes.OFFERING,
)
price = models.PositiveIntegerField(
default=0,
help_text='In cents'
)
location = models.CharField(
max_length=255,
choices=AdLocations.get_choices(),
default=AdLocations.VILNIUS,
)
user = models.ForeignKey(User, on_delete=models.PROTECT)
approved_date = models.DateField(null=True, blank=True)
approved_by = models.ForeignKey(
User, on_delete=models.PROTECT, related_name='approved_by', null=True
)
The two base models:
class UUIDBaseModel(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
uuid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
class Meta:
abstract = True
class AdModel(UUIDBaseModel):
expires_at = models.DateTimeField(null=True)
is_draft = models.BooleanField(default=False)
is_active = models.BooleanField(default=False)
class Meta:
abstract = True
This is really strange, maybe that could be the problem because of the naming 'Ad'? I have a serializer for this model and everything works just fine, but the admin panel doesn't want to display it.
views.py
class AdCreateViewSet(ModelViewSet, CreateModelMixin):
serializer_class = AdCreateSerializer
permission_classes = (AllowAny,)
filter_backends = [DjangoFilterBackend]
search_fields = ('plate', 'description', 'user__email')
queryset = Ad.objects.select_related('user')
def perform_create(self, serializer):
user = User.objects.first()
serializer.save(user=user) # self.request.user)
serializers.py
class AdCreateSerializer(CustomAdSerializer):
class Meta:
model = Ad
exclude = ['expires_at']
read_only_fields = ('user',)
I'm trying to validate data in order to store it. But the serializer is removing valid fields. Here my code:
models.py
class MyModel(models.Model):
user_id = models.UUIDField('action uid',default=uuid.uuid4,null=False,primary_key=True,blank=False,editable=False, unique=True)
city = models.CharField('City', max_length=50, null=True, blank=True, editable=False)
latitude = models.CharField('Latitude', max_length=50, null=True, blank=True, editable=False)
longitude = models.CharField('Longitude', max_length=50, null=True, blank=True, editable=False)
datetime = models.DateTimeField('datatime', null=False, blank=False, editable=False)
serializer.py
class MyModelSerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
fields = '__all__'
view.py
def save_my_data(self, request):
user_info ={
"user_id": resquest.user.user_uid,
"city": resquest.user.city,
"latitude": "17.6801",
"longitude": "83.2016",
"datetime": timezone.now()
}
serializer = serializers.MyModelSerializer(data=user_info)
serializer.is_valid(raise_exception=True) # Not error thrown.
print( serializer.data ) # returns void
Any thoughts about this? thanks in advance.
You didn't call the .save() method of the serializer
serializer = serializers.MyModelSerializer(data=user_info)
serializer.is_valid(raise_exception=True)
print("This is validated data, ", serializer.validated_data)
serializer.save()
print("This is saved data, ", serializer.data)
Update
Some of the model fields are set as editable=False which causing the issue. DRF thinks that those fields shouldn't be edited, which in turns the fields into read_only.
So,
Method 1
Remove editable=False and migrate
class MyModel(models.Model):
user_id = models.UUIDField(
'action uid',
default=uuid.uuid4,
null=False,
primary_key=True,
blank=False,
editable=False,
unique=True
)
# other fields
Method 2
Explicitly define corresponding fields in the serializer class.
class MyModelSerializer(serializers.ModelSerializer):
user_id = serializers.UUIDField()
# other `editable=False` fields
class Meta:
model = MyModel
fields = '__all__'
I've set up my models, serializers and viewsets in my Django REST API to assign a search record to a particular user, and to associate all the relevant user's searches to their record in the User model. It was all working fine, but I'm now getting the TypeError error message (in the subject line of this question) when I try to create a new user. I've listed the relevant models, serializers and viewsets below. Please could anyone take a look and let me know where I'm going wrong? Any help would be very much appreciated.
User serializer:
class UserSerializer(serializers.ModelSerializer):
searches = serializers.PrimaryKeyRelatedField(many=True, queryset=SearchHistoryModel.objects.all())
class Meta:
model = User
fields = ('id', 'username', 'email', 'password', 'searches')
extra_kwargs = {'email': {
'required': True,
'validators': [UniqueValidator(queryset=User.objects.all())]
}}
def create(self, validated_data):
user = User.objects.create_user(**validated_data)
Token.objects.create(user=user)
return user
User viewset:
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = [permissions.AllowAny]
Search model:
class SearchHistoryModel(models.Model):
"""
Stores each user's search submission
"""
created_date = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(User, related_name='searches', on_delete=models.CASCADE)
cpu_component_name = models.CharField(max_length=10, blank=False)
cpu_subcomponent_name = models.CharField(max_length=50, blank=False)
motherboard_name = models.CharField(max_length=20, blank=False)
gpu_component_name = models.CharField(max_length=10, blank=True, null=True)
gpu_subcomponent_name = models.CharField(max_length=50, blank=True, null=True)
gpu_subcomponent_quantity = models.PositiveIntegerField(default=0)
ram_component_name = models.CharField(max_length=15, blank=True, null=True)
ram_component_quantity = models.PositiveIntegerField(default=0)
ssd_component_name = models.CharField(max_length=15, blank=True, null=True)
ssd_component_quantity = models.PositiveIntegerField(default=0)
hdd_component_name = models.CharField(max_length=20, blank=True, null=True)
hdd_component_quantity = models.PositiveIntegerField(default=0)
optical_drive_name = models.CharField(max_length=15, blank=True, null=True)
class Meta:
verbose_name = 'Search'
verbose_name_plural = 'Searches'
ordering = ['owner', 'created_date']
def __str__(self):
return '{}\'s search choices'.format(self.owner)
Search serializer:
class SearchHistorySerializer(serializers.ModelSerializer):
"""
Serializes the user's search history data passed into the SearchHistoryModel
Associates each search with the relevant user
"""
owner = serializers.ReadOnlyField(source='owner.username')
class Meta:
model = SearchHistoryModel
fields = (
'id', 'created_date', 'owner', 'cpu_component_name', 'cpu_subcomponent_name',
'motherboard_name', 'gpu_component_name', 'gpu_subcomponent_name',
'gpu_subcomponent_quantity', 'ram_component_name', 'ram_component_quantity',
'ssd_component_name', 'ssd_component_quantity', 'hdd_component_name',
'hdd_component_quantity', 'optical_drive_name'
)
Search viewset:
class SearchHistoryViewSet(viewsets.ModelViewSet):
queryset = SearchHistoryModel.objects.all()
serializer_class = SearchHistorySerializer
permission_classes = [permissions.IsAuthenticated]
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
In user = User.objects.create_user(**validated_data), validated_data contains a searches value which is an id.
But actually the ForeignKey is in the other sense : in Searches model, and to refer to a User instance, not the opposite.
To link a user to searches, it is not in User DB table that you write an id, but in Searches that you write a User id.
class UserSerializer(serializers.ModelSerializer):
(...)
def create(self, validated_data):
# Extract the value from 'validated_data'
search_ids = validated_data.pop('searches', None)
user = User.objects.create_user(**validated_data)
Token.objects.create(user=user)
# Update existing search instances
for search_id in search_ids:
Search.objects.filter(id=search_id).update(owner=user)
return user
I just started toying around with the Django Rest Framework, so I'm still not entirely sure what exactly is going on. But I have a user model, a friend model, and a post model, I also have my serializers and views in order. But, I can't figure out how to return all the posts from my user's friends. Any help would be greatly appreciated.
models.py
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField('email address', unique=True, db_index=True)
password1 = models.CharField(max_length=50)
username = models.CharField('username', max_length=50, unique=True, db_index=True)
image = models.FileField(upload_to='photos', null=True, blank=True)
joined = models.DateTimeField(auto_now_add=True)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = []
objects = CustomUserManager()
def __unicode__(self):
return self.username
class Meta:
unique_together = (('username', 'password1'),)
class Friendship(models.Model):
created_at = models.DateTimeField(auto_now_add=True, editable=False)
creator = models.ForeignKey(CustomUser, related_name="friendship_creator")
friend = models.ForeignKey(CustomUser, related_name="friends")
class Post(models.Model):
poster = models.ForeignKey(CustomUser)
body = models.CharField(max=200)
def save(self, *args, **kwargs):
super(Post, self).save(*args, **kwargs)
serializers.py
class FriendSerializer(HyperlinkedModelSerializer):
class Meta:
model = Friendship
fields = ('creator', 'friend', 'created_at')
readonly_fields = 'created_at'
class CustomUserSerializer(HyperlinkedModelSerializer):
friends = FriendSerializer(many=True)
class Meta:
model = CustomUser
fields = ('email', 'username', 'password1', 'image', 'friends')
readonly_fields = 'image'
views.py
class FriendViewSet(ModelViewSet):
queryset = CustomUser.objects.all()
serializer_class = FriendSerializer
class UserProfileViewSet(RetrieveModelMixin, UpdateModelMixin, GenericViewSet):
queryset = CustomUser.objects.all()
serializer_class = CustomUserSerializer
This may get you started,
So what you need to do first is get all the friends, you can do that by using
friends = <user_objects>.Friendship_set.all()
Read more about is here.
Now that you have all the friends of that particular user, covert their IDs to list and use the in list filter.
Post.objects.filter(poster__id__in=[list_of_ids_of_friends])
See this answer for filtering on foreign key properties.
I'm facing a problem using python2.7 with django rest-framework. When I serialize my JSON data, a field is omitted by the serializer and I don't understand why. Here is some details.
The missing field is "country". When I'm doing POST or PUT requests on /campaigns/:id
class CampaignSerializer(serializers.HyperlinkedModelSerializer):
created_by = UserFullSerializer(read_only=True)
country = CountrySerializer(read_only=True)
class Meta:
model = Campaign
fields = ('id', 'created_by', 'name', 'media', 'status', 'begin', 'end', 'country')
class CampaignFullSerializer(serializers.HyperlinkedModelSerializer):
client = ClientSerializer(read_only=True)
collection = CollectionSerializer(read_only=True)
created_by = UserFullSerializer(read_only=True)
updated_by = UserFullSerializer(read_only=True)
channels = ChannelSerializer(read_only=True, many=True)
country = CountrySerializer(read_only=True)
class Meta:
model = Campaign
fields = ('id',
'client',
'name',
'media',
'status',
'begin',
'end',
'created_at',
'created_by',
'updated_at',
'updated_by',
'collection',
'channels',
'country')
class CountrySerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Country
fields = ('id', 'name', 'code')
class Country(models.Model):
name = models.CharField(max_length=255)
code = models.CharField(max_length=255)
class Campaign(models.Model):
name = models.CharField(max_length=255)
media = models.IntegerField(choices=constant.MEDIA_CHOICES, default=0)
status = models.IntegerField(choices=constant.STATUS_CHOICES, default=2)
created_at = models.DateTimeField(auto_now_add=True)
created_by = models.ForeignKey(User, blank=True, null=True, related_name="created_by")
updated_at = models.DateTimeField(auto_now_add=True, blank=True, null=True)
updated_by = models.ForeignKey(User, blank=True, null=True, related_name="updated_by")
client = models.ForeignKey(client.Client)
begin = models.DateField(blank=True, null=True)
end = models.DateField(blank=True, null=True)
collection = models.ForeignKey(collection.Collection, blank=True, null=True)
country = models.ForeignKey(country.Country, blank=True, null=True)
mediaplan = models.ForeignKey(mediaplan.Mediaplan, blank=True, null=True, default=None)
channels = models.ManyToManyField(channel.Channel)
When I'm doing POST on /campaign/id with the following JSON, everything works except the country field.
{
...
"channels": [],
"country": {
"id": 74,
"name": "France",
"code": "FR"
}
On the controller side when I print the request.data I got all the fields. I'm not overriding the create method of the controller.
{
...
u'country': {u'code': u'AL', u'id': 3, u'name': u'Albania'}
}
My controller looks like:
class CampaignViewSet(viewsets.ModelViewSet):
queryset = Campaign.objects.all()
serializer_class = CampaignSerializer
def create(self, request):
logger.info(request.data)
return super(CampaignViewSet, self).create(request, *args, **kwargs)
I tried to override the create method of my CountrySerializer and when I print the content of validated_data, the country field is missing in the OrderedDict..
class CountrySerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Country
fields = ('id', 'name', 'code')
def create(self, validated_data):
logger.info(validated_data)
I'm really lost, I can't find my mistake, maybe you will. Thanks for your time.
Your CountrySerializer is read only as a nested serializer by default (per http://www.django-rest-framework.org/api-guide/relations/#nested-relationships) so you have to override the create/update method of the Campaign serializer for POST/PUT. You've tried to override it on the Country serializer instead.