Initialize user django so he has default settings values - django

I am using Django + Angular 2
. I am creating a user fine but he does not have the default values i want...
Model
class Settings(models.Model):
user = models.ForeignKey('auth.User', related_name='settings', on_delete=models.CASCADE)
bolean1 = models.BooleanField(default=False)
boolean2 = models.BooleanField(default=False)
boolean3 = models.BooleanField(default=False)
string1 = models.CharField(max_length=100, default='No description')
Serializer
class SettingsSerializer(serializers.ModelSerializer):
class Meta:
model = Settings
fields = ('id', 'bolean1', 'bolean1', 'bolean3', 'string1')
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'username', 'email', 'password' ,'settings', 'image')
extra_kwargs = {'password': {'write_only': True}}
class CreateUserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('email', 'username', 'password')
extra_kwargs = {'password': {'write_only': True}}
def create(self, validated_data):
user = User(
email=validated_data['email'],
username=validated_data['username']
)
user.set_password(validated_data['password'])
user.save()
return user
Views
class SettingsValues(generics.ListAPIView):
serializer_class = SettingsSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
def get_queryset(self):
queryset = Settings.objects.all()
queryset = queryset.filter(user=self.request.user.id)
return queryset
class RegisterUser(generics.ListCreateAPIView):
queryset = User.objects.all()
serializer_class = CreateUserSerializer
The problem is that when i create a new user he does not have default values,e.g boolean 1, boolean 2 etc. i must go to django admin create new setting and choose the user.
Any idea ?

Sounds like you want Django's Signals, specifically post_save. You'll want to create a Settings() for each User() that's created - you have default values right now, but that only helps when you've saved the Settings model.
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.contrib.auth import get_user_model
User = get_user_model()
#receiver(post_save, sender=User)
def create_settings(sender, instance, created, **kwargs):
# Only create a Settings relation if the User is new
if created:
settings = Settings(user=instance)
settings.save()
If your Settings model is in an app called settings, then your settings/apps.py should have this - good StackOverflow answer on this:
from django.apps import AppConfig
class SettingsConfig(AppConfig):
name = 'settings'
def ready(self):
from . import signals
Now, whenever a new User is created, a Settings relation is created for them as well.

I am not sure if this is what you want to achieve, but try this.
//admin.py
from django.contrib import admin
from django.contrib.auth.models import User
from django.contrib.auth.admin import UserAdmin
from accounts import models
admin.site.unregister(User)
class UserRoleInline(admin.StackedInline):
model = models.UserRole
class UserRoleAdmin(UserAdmin):
inlines = [UserRoleInline]
admin.site.register(User, UserRoleAdmin)
//model.py
from django.db import models
from django.contrib.auth.models import User
class RoleType(object):
MANAGER = 'm'
CANDIDATE = 'c'
CHOICES = ((MANAGER, 'Manager'), (CANDIDATE, 'Candidate'))
class UserRole(models.Model):
user = models.OneToOneField(User)
role = models.CharField(max_length=1, choices=RoleType.CHOICES)
Reference: django StackedInline
This will help you stack the setting models at end of User model. This won't automatically take a default value, but will let you choose the settings as the user models is created.

Related

Django image field not showing on admin form for extended User model

I am trying to extend the User model to allow a user to add an image to their profile, however have no option to save an image in the admin for my page. The other extended fields are showing. I am not sure why this is..
model.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
first_name = models.TextField(default='', blank='')
last_name = models.TextField(default='', blank='')
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
def user_image_upload_handler(instance, filename):
fpath = pathlib.Path(filename)
new_fname = str(uuid.uuid1()) # uuid1 -> uuid + timestamps
return f"request/{new_fname}{fpath.suffix}"
class ProfilePicture(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(upload_to=user_image_upload_handler, blank=True)
admin.py
from django.contrib import admin
from django.contrib.auth.models import User
from .models import Profile, ProfilePicture
class ProfileAdmin(admin.ModelAdmin):
model = [Profile]
list_display = ['id']
class ProfilePictureAdmin(admin.ModelAdmin):
model = [ProfilePicture]
extra = 10
class UserAdmin(admin.ModelAdmin):
model = ProfileAdmin
model = ProfilePictureAdmin
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
from https://docs.djangoproject.com/en/4.0/ref/contrib/auth/
first_name, last_name and email are already part of the standard django User so there was no need to extend those. My accounts/admin.py was simply
from django.contrib import admin
from django.contrib.auth.models import User
from .models import ProfilePicture
class ProfilePictureAdmin(admin.StackedInline):
model = ProfilePicture
extra = 1
class ExtendedUserAdmin(admin.ModelAdmin):
inlines = [ProfilePictureAdmin]
list_display = ['id', 'username', 'first_name']
admin.site.unregister(User)
admin.site.register(User, ExtendedUserAdmin)

Serialise an extended User Model in Django

I'm extending a django auth user model in a Profile model:
from django.db import models
from django.contrib.auth.models import User
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
activity = models.IntegerField(default=500)
def _str_(self):
return self
in my views I'm getting the current auth user and I get the associated profile:
#api_view(['GET'])
#permission_classes([IsAuthenticated])
def getUserProfile(request):
profile = Profile.objects.get(user = request.user)
serializer = profileSerializer(profile, many=False)
return Response(serializer.data)
Here is my serializers code:
from rest_framework import serializers
from .models import Profile
class profileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = ('first_name', 'activity')
The error I'm getting that Profie object has not a first_name attribute, but when I replace 'first_name' with 'user' I get only the id of the user, so I want to show the first_name as well.
Thank you
The OneToOneField connects your field user in the Profile model to a User object which has a first_name attribute, but in the Profile table that user field is just a number that says which User object it is. To access the first name, you can do this:
from rest_framework import serializers
from .models import Profile
class profileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = '__all__'
Then in your template you could display the first_name like this, assuming you pass person to it where person is an instance of the Profile model:
{{ person.user.first_name }}
I also think it would be less confusing to use another name for the field, rather then user. Call it person maybe, like:
from django.db import models
from django.contrib.auth.models import User
class Profile(models.Model):
person = models.OneToOneField(User, on_delete=models.CASCADE)
activity = models.IntegerField(default=500)
def _str_(self):
return self
Try this:
from django.contrib.auth.models import User
class profileSerializer(serializers.ModelSerializer):
first_name = serializers.CharField(max_length=200, read_only=True)
class Meta:
model = Profile
fields = ('user', 'first_name', 'activity')
def get_first_name(self, obj):
return User.objects.filter(id=obj.user.id).first().values_list('first_name', flat=True).last()
I was able to show the fields I wanted using Django depth in the serializer
from rest_framework import serializers
from .models import Profile
from django.contrib.auth.models import User
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('first_name', 'last_name')
class profileSerializer(serializers.ModelSerializer):
user = UserSerializer()
class Meta:
model = Profile
fields = ('activity','user')
depth=1

Django Signals set signal to create a default avatar image on UserExtended model after registering User

I want to create an entry on UserExtended model after registering an user on Django default user model.
here is UserExtended model:
class UserExtended(models.Model):
extended_id = models.AutoField(primary_key=True, editable=False)
avatar = models.ImageField(null=True, blank=True, default='Capture.PNG')
user = models.OneToOneField(User, on_delete=models.CASCADE, null=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
here is the view function that registering the user
#api_view(['POST'])
def register_user(request):
data = request.data
user = User.objects.create(
first_name=data['name'],
username=data['username'],
email=data['email'],
password=make_password(data['password'])
)
serializer = UserSerializerWithToken(user, many=False)
return Response(serializer.data)
here is the serializer
class UserSerializer(serializers.ModelSerializer):
name = serializers.SerializerMethodField(read_only=True)
isAdmin = serializers.SerializerMethodField(read_only=True)
avatar = serializers.SerializerMethodField()
def get_avatar(self, obj):
avatar = obj.userextended.avatar.url
print(avatar)
if avatar == '':
avatar = 'null'
return avatar
class Meta:
model = User
fields = ['id', 'username', 'email', 'name', 'avatar', 'isAdmin']
def get_name(self, obj):
name = obj.first_name
if name == '':
name = obj.email
return name
def get_isAdmin(self, obj):
return obj.is_staff
class UserSerializerWithToken(UserSerializer):
token = serializers.SerializerMethodField(read_only=True)
class Meta:
model = User
fields = ['id', 'username', 'email', 'name', 'isAdmin', 'token']
here is the signal.py:
from django.db.models.signals import post_save, pre_delete
from django.contrib.auth.models import User
from django.dispatch import receiver
from .models import UserExtended
#receiver(post_save, sender=User)
def create_user_extended(sender, instance, created, **kwargs):
if created:
UserExtended.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_user_extended(sender, instance, **kwargs):
instance.userextended.save()
but the signal is not working to create an default avatar file for an new registered user
I am new. Please help me.
Django does not look for any file named signal.py, etc. by default. Hence what is happening it that your signals are never registered (in fact the file you write them in is never run). The general solution to adding signals is to write them in a separate file and then import / register them in the app config's ready method.
In the app in which you write signal.py there should be a file apps.py in which there should be a class inheriting from AppConfig edit this class and add a ready method to it and import your signals there:
from django.apps import AppConfig
# The parts marked as "Don't edit" mean to keep them as it already is in _your_ code and not copy it
class YourAppConfig(AppConfig): # Don't edit
default_auto_field = 'django.db.models.BigAutoField' # Don't edit
name = 'your_app' # Don't edit
# Copy only the code below
def ready(self):
# models, signals etc. are imported only here because otherwise the models might not be loaded yet
from . import signal

I want to filter my product on the bases of rating, How can i do that?

My Models
from django.db import models
from django.contrib.auth.models import User
from django.core.validators import MaxValueValidator, MinValueValidator
# Create your models here.
class Product(models.Model):
title = models.CharField(max_length=100)
description = models.TextField()
def no_of_ratings(self):
ratings = Rating.objects.filter(product=self)
return len(ratings)
def avg_rating(self):
ratings = Rating.objects.filter(product=self)
sum=0
for rating in ratings:
sum += rating.rating
if len(ratings)>0:
return sum/len(ratings)
else:
return None
def __str__(self):
return self.title
class Rating(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE)
rating = models.IntegerField(validators=[MinValueValidator(1), MaxValueValidator(5)])
class Meta:
unique_together = (('user', 'product'),)
index_together = (('user', 'product'),)
serializer.py
from rest_framework import serializers
from django.contrib.auth.models import User
from rest_framework.authtoken.models import Token
from .models import Product, Rating
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'username', 'password')
extra_kwargs = {'password': {'write_only': True, 'required': True}}
def create(self, validated_data):
user = User.objects.create_user(**validated_data)
Token.objects.create(user=user)
return user
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields =('id', 'title', 'description', 'no_of_ratings', 'avg_rating')
class RatingSerializer(serializers.ModelSerializer):
class Meta:
model = Rating
fields = ('product', 'user', 'rating')
views.py
from django.shortcuts import render
from rest_framework import viewsets, status
from rest_framework.authentication import TokenAuthentication
from rest_framework.response import Response
from rest_framework.decorators import action
from django.contrib.auth.models import User
from .models import Rating, Product
from rest_framework.authtoken.views import ObtainAuthToken
from rest_framework.authtoken.models import Token
from rest_framework.permissions import IsAuthenticated, AllowAny
from .serializers import ProductSerializer, RatingSerializer
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.filter(product__rating__gte = 4 )
serializer_class = ProductSerializer
authentication_classes = (TokenAuthentication,)
permission_classes = (AllowAny,)
class RatingViewSet(viewsets.ModelViewSet):
queryset = Rating.objects.filter(rating__gte = 4)
serializer_class = RatingSerializer
authentication_classes = (TokenAuthentication,)
permission_classes = (AllowAny,)
Hi, I'm new in Django Rest Framework, I want to filter my product on the bases of rating, but my filter doesn't work, I have two models classes Product and Rating every Product have a rating( Foreign key ), I want to list only +4 rated product, how can I achieve that, and can I filter results to get models with specific rating?
With queryset = Product.objects.filter(product__rating__gte = 4 ) you look up products and filter them by their field product but your product instances don't have this field or property.
In your views.ProducViewSet You should filter for something like
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.filter(rating_set__rating__gte = 4 )
# ...
instead. rating_set is the default name to access foreign keys in the other direction (from the model where it's not defined in) You can use the related_name parameter in the ForeignKey to set this to a custom name like product_rating. (Notice the use of single _, it wouldn't work with double __)

Django rest framework not updating extended user model

I have extended user model in Django, and it is of Customer type. I am using django rest framework (DRF). So, while going through docs in DRF I came to know about writing in nested models, so I did override create and update methods in serializer, creation is working fine but not the update as it says :
HTTP 400 Bad Request
Allow: GET, PUT, PATCH, DELETE, OPTIONS
Content-Type: application/json
Vary: Accept
{
"user": {
"username": [
"A user with that username already exists."
]
}
}
Here is my Customer model:
from django.db import models
from django.contrib.auth.models import User
class Customer(models.Model):
user = models.OneToOneField(User, related_name="customer", on_delete=models.CASCADE)
date_of_birth = models.DateField(max_length=8)
def __unicode__(self):
return u'%s' % self.user.username
My User serializer:
from django.contrib.auth.models import User
from rest_framework import serializers
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ('url', 'username', 'email', 'is_staff')
And my extended customer model serializer:
from django.contrib.auth.models import User
from django.contrib.auth import get_user_model
from rest_framework import serializers
from customers.models import Customer
from api.serializers import UserSerializer
class CustomerSerializer(serializers.HyperlinkedModelSerializer):
user = UserSerializer()
class Meta:
model = Customer
fields = ('url', 'date_of_birth', 'user')
depth = 1
def create(self, validated_data):
print "coming inside create"
user_data = validated_data.pop("user")
user = User.objects.create(**user_data)
customer = Customer.objects.create(user=user, **validated_data)
return customer
def update(self, instance, validated_data):
print "coming inside update"
user_data = validated_data.pop("user")
username = user_data.pop('username')
user = get_user_model().objects.get_or_create(username=username)[0]
user.email = user_data.get('email', user.email)
user.save()
instance.user = user
instance.date_of_birth = validated_data.get('date_of_birth', instance.date_of_birth)
instance.save()
return instance
Here is the viewset view:
from rest_framework import viewsets
from customers.models import Customer
from customers.serializers import CustomerSerializer
class CustomerViewSet(viewsets.ModelViewSet):
serializer_class = CustomerSerializer
queryset = Customer.objects.all()
So, what could be wrong here that it is creating a new profile of customer even the new user but not updating?
Edit 1
Ok, so I did this on UserSerializer:
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ('url', 'username', 'email', 'is_staff')
extra_kwargs = {
'username': {'validators': []},
}
So, update is fine for all the other fields of user or customer fields but
if I try to set a new username it creates an entirely new user,
and also when trying to create a new user, it gives the following error:
IntegrityError at /api/customers/
duplicate key value violates unique constraint "auth_user_username_key"
DETAIL: Key (username)=(customer1) already exists.
You should drop the unique validator for the nested serializer:
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('url', 'username', 'email', 'is_staff')
extra_kwargs = {
'username': {'validators': []},
}
You may want to print your serializer before to make sure you don't have other validators on that field. If you have some, you'll have to include them in the list.