radio buttons incorrectly written to the database in django - python

I've a registration form, where user must chose one of 2 options.
Django renders all correctly, django admin also have it ok, but db records all possible choices as value.
forms.py
class UserRegisterForm(UserCreationForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['username', 'email','password1','password2']
class UserProfileForm(forms.ModelForm):
terms_compliance = forms.BooleanField(label=mark_safe('I agree with terms and conditions '))
class Meta:
model = UserProfile
widgets = {'role': forms.RadioSelect}
fields = ('role','terms_compliance')
def __init__(self):
self.fields['terms_compliance'].initial = True
models.py
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
role_choices = [('publisher','Publisher'), ('advertiser','Advertiser')]
role = models.CharField(max_length=15, choices=role_choices, default=None)
terms_compliance = models.BooleanField()
def __str__(self):
return self.user.username
In new instance (which is user.userprofile.role_choices) I need advertiser or publisher, but all I have is: [('publisher','Publisher'), ('advertiser','Advertiser')]

If you want to provide choices in a Database Field. Do like this:
class UserProfile(models.Model):
class RoleChoice(ChoiceEnum):
PUBLISHER = 'Издатель'
ADVERTISER = 'Рекламодатель'
user = models.OneToOneField(User, on_delete=models.CASCADE)
role = models.CharField(max_length=15, choices=RoleChoice.choices(), default=None)
terms_compliance = models.BooleanField()
def __str__(self):
return self.user
In Views.py, populate the DB like this.
For example:
...
choice = request.query_params.get('choice') or UserProfile.RoleChoice.PUBLISHER.value
...
For more details read from here: https://django-mysql.readthedocs.io/en/latest/model_fields/enum_field.html

Related

Better way to fetch related object, in Self Refrencing ManyToMany Relationship?

I am working on a small application containing models CustomUser and PollQuestion. CustomUser having ManyToMany relation between itself and a CustomUser can have multiple PollsQuestion as well so there is Foreign Key relation between them.
An authenticated user is only able to see polls raised by users he is following, to full-fill this requirement i have written following view**:-**
Actually this is not view this is an utility method returning the polls to original view.
def all_polls_utils(request):
following = request.user.get_all_followings().values_list("id")
user_id = [id[0] for id in following]
all_polls = PollQuestion.objects.none()
for u_id in user_id:
user = CustomUser.objects.get(id=u_id)
polls = user.poll_questions.all()
all_polls = all_polls | polls
return all_polls
Main Question:- Is there in better way to do the same?
Any suggestion will be highly appretiated
I am posting the models bellow:-
from django.db import models
from django.contrib.auth.models import AbstractUser
# Create your models here.
class CustomUser(AbstractUser):
email = models.EmailField(max_length=250, null=False)
name = models.CharField(max_length=50, null=False)
username = models.CharField(max_length=50, null=False, unique=True)
password = models.CharField(max_length=15, null=False)
user = models.ManyToManyField('self', through='Relationship', symmetrical=False, related_name='related_to')
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['name', 'email']
def get_all_polls(self):
pass
def create_relationship(self, person):
status, obj = Relationship.objects.get_or_create(
to_person=person,
from_person=self,
)
return status
def remove_relationship(self, person):
Relationship.objects.filter(
from_person=self,
to_person=person
).delete()
return 'dummy_value'
def get_all_followings(self):
return self.user.all()
class Relationship(models.Model):
from_person = models.ForeignKey(CustomUser, related_name='from_people', on_delete=models.CASCADE)
to_person = models.ForeignKey(CustomUser, related_name='to_person', on_delete=models.CASCADE)
And PollQuestion:-
class PollQuestion(models.Model):
user = models.ForeignKey(CustomUser, null=True, on_delete=models.CASCADE, related_name="poll_questions")
# Other fields
Note:- You can also suggest me a better title for this post?
Thanks in advance,
Hope to here from you soon.
Simply
def all_polls_utils(request):
all_polls_by_followed = PollQuestion.objects.filter(
user__in=request.user.get_all_followings()
)
As an aside, you should probably rename the user many-to-many in CustomUser to e.g. followed_users (with a related name followers).

I cannot register a user using Django-Rest-Framework

I can't add a new user using Django Rest Framework. Here is my code from models.py:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
password = models.CharField(max_length=15, default= None)
first_name = models.CharField(max_length=100, validators=[name_validator])
last_name = models.CharField(max_length=100, validators=[name_validator])
email = models.CharField(max_length=100, validators=[mail_validator])
created_at = models.DateTimeField(auto_now_add=True)
As you can see I am using models.OneToOneField cause I want to extend the default user to add some more fields.
Bellow is my serializers.py file:
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
permissions_classes = [
permissions.AllowAny
]
fields = '__all__'
The viewset is the following:
class UserViewset(viewsets.ModelViewSet):
queryset = Profile.objects.all()
serializer_class = ProfileSerializer
When I go to my endpoints and try to add a new user, I cannot put anything in the "user" field:
Click for image
I am a beginner and it would be of great help.
Thank you!
you can to this
from django.contrib.auth.models import User
class Profile(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
password = models.CharField(max_length=15, default= None)
first_name = models.CharField(max_length=100, validators=[name_validator])
last_name = models.CharField(max_length=100, validators=[name_validator])
email = models.CharField(max_length=100, validators=[mail_validator])
created_at = models.DateTimeField(auto_now_add=True)
serializer.py
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = "__all__"
class ProfileSerializer(serializers.ModelSerializer):
user = UserSerializer(read_only=True)
class Meta:
model = Profile
fields = '__all__'
views.py
class UserViewset(viewsets.ModelViewSet):
queryset = Profile.objects.all()
serializer_class = ProfileSerializer
permission_classes = [permission. AllowAny,]
When you want to extend the default user to add some more fields, the best way for that is substituting a custom User model by inheritance the AbstractUser model. Using this way, you can CRUD the user easily.

count likes in ManyToManyField - django rest framework

in models.py:
class Post(models.Model):
body = models.TextField(max_length=10000)
date = models.DateTimeField(auto_now_add=True, blank=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
liked_by = models.ManyToManyField(User, blank=True, related_name='liked_by')
class Meta:
ordering = ['-date']
in serializers.py:
class PostSerializer(serializers.ModelSerializer):
user = UserSerializers()
class Meta:
model = Post
fields = ('body','date','user')
how to count likes of a single post? and also show which user liked the post.
class PostSerializer(serializers.ModelSerializer):
user = UserSerializers()
total_likes = serilaizers.SerializerMethodField()
liked_by = UserSerializers(many=True)
class Meta:
model = Post
fields = ('body','date','user', 'total_likes', 'liked_by')
def get_total_likes(self, instance):
return instance.liked_by.count()
You need to change class Post manyToMany relation adding "through=".
liked_by = models.ManyToManyField(User, through='liked_users', blank=True, related_name='liked_by')
Create manually model LikedUsers:
class LikedUsers(models.Model):
liked_count = models.IntegerField(default=0)
post = models.ForeignKey(Post, related_name='likedusers', on_delete=models.CASCADE)
user = models.ForeignKey(User, related_name='likedusers', on_delete=models.CASCADE)
Get access to likes (post.likedusers[0].liked_count, ... next users)
You can get the total likes of a post using SerializerMethodField.
from rest_framework.fields import SerializerMethodField
class PostSerializer(serializers.ModelSerializer):
user = UserSerializers()
total_likes = SerializerMethodField()
class Meta:
model = Post
fields = ('body','date','user')
def get_total_likes(self, instance):
return instance.liked_by.all().count()
Your liked_by field is just referencing to User model, but not to User model and you have only who liked your post but likes quantity. So you can query certain post and count User quantity, but I suggest to have separate filed of likes count

Django Rest - Serializer: must be a instance on create

I'm trying to create create a nested serializer using the Django Rest framework. The relationship is Profile X User but when i use Profile.objects.create(user=profile, **user_data) i get ValueError: Cannot assign "<Profile: Profile object (7)>": "Profile.user" must be a "User" instance..
This should be some rookie misunderstanding of models relationship definitions or the serializer declaration itself but I can't find anything around the docs. If someone can point me a direction I'll be gracefull.
models.py
class User(models.Model):
name = models.CharField(max_length=100, blank=False)
email = models.CharField(max_length=100, blank=True, default='')
password = models.CharField(max_length=100, blank=True, default='')
timestamp = models.DateTimeField(default= timezone.now)
class Meta:
ordering = ['timestamp']
class Profile(models.Model):
# choices [...]
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True)
profile_type = models.CharField(max_length=2,choices=PROFILE_CHOICES,default=TEAMMEMBER)
authentication_token = models.CharField(max_length=100, null=True)
avatar_url = models.CharField(max_length=100, default='')
permissions = models.CharField(max_length=100, null=True)
timestamp = models.DateTimeField(default= timezone.now)
class Meta:
ordering = ['timestamp']
serializer.py
class UserSerlializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['name', 'email', 'password']
class ProfileSerializer(serializers.ModelSerializer):
user = UserSerlializer()
class Meta:
model = Profile
fields = ['user', 'profile_type']
def create(self, validated_data):
user_data = validated_data.pop('user')
profile = Profile.objects.create(**validated_data)
Profile.objects.create(user=profile, **user_data)
return Profile
POST
{
"profile_type" : "ST",
"user": {
"name" : "test",
"email" : "test#test.com",
"password" : "123456"
}
}
You are creating instances in wrong way. Change your create(...) method as,
class ProfileSerializer(serializers.ModelSerializer):
user = UserSerlializer()
class Meta:
model = Profile
fields = ['user', 'profile_type']
def create(self, validated_data):
user_data = validated_data.pop('user')
user_instance = User.objects.create(**user_data)
profile_instance = Profile.objects.create(user=user_instance, **validated_data)
return profile_instance
Profile.user should beUser instance, but you are assigning Profile instance.
Change your create method to this:
class ProfileSerializer(serializers.ModelSerializer):
user = UserSerlializer()
class Meta:
model = Profile
fields = ['user', 'profile_type']
def create(self, validated_data):
user_data = validated_data.pop('user')
profile = Profile.objects.create(**validated_data)
user = User.objects.create(**user_data) # 1. creating user
profile.user = user # 2. assigning user
profile.save() # 3. saving profile after adding user
return profile # returning Profile instance.
inherit your user model from django contrib auth module also, and make a one to one relation with profile
from django.contrib.auth.models import User

Django - extended user model not saving

I'm having trouble attempting to save data from my extended user model.
model.py
class Person(models.Model):
"""
The 'user' field creates a link between the django-registration-redux's
default user and allows it to be extended through this model.
"""
user = models.OneToOneField(User)
# Person attributes
address = models.CharField(max_length=50)
town = models.CharField(max_length=50)
postcode = models.CharField(max_length=10)
phone_no = models.CharField(max_length=10, unique=True)
# Meta contains information about the class which is not a field.
class Meta:
abstract = True
class Customer(Person):
# No extra attributes required for Customer.
def __str__(self):
return self.user.username
class Staff(Person):
# Staff attributes
job_role = models.CharField(max_length=50)
medical_contact = models.CharField(max_length=50)
nation_insurance = models.CharField(max_length=50, unique=True)
def __str__(self):
return self.user.username
forms.py
class UserProfileForm(RegistrationFormUniqueEmail):
address = forms.CharField(max_length=50)
town = forms.CharField(max_length=50)
postcode = forms.CharField(max_length=7)
phone_no = forms.CharField(max_length=10)
class Meta:
model = User
fields = ['username', 'first_name', 'last_name', 'email', 'password1', 'password2']
regbackend.py
class CustomRegistrationView(RegistrationView):
form_class = UserProfileForm
def register(self, form_class):
new_user = super(CustomRegistrationView, self).register(form_class)
user_profile = Customer()
user_profile.user = new_user
user_profile.address = form_class.cleaned_data['address']
user_profile.town = form_class.cleaned_data['town']
user_profile.postcode = form_class.cleaned_data['postcode']
user_profile.phone_no = form_class.cleaned_data['phone_no']
user_profile.save()
return user_profile
So I need to save attributes of Customer through the registration form which is in the django-registration-redux app. However with my current code it will only save "User" attributes. When I attempted to change the forms model to "Customer" it won't save "User" attributes.
It's because User is a OnetoOnefield, so you need to create the user, save it and then add it to your Customer object and save it.
You need to do something like that in your forms.py, redefine the save method:
def save(self, commit=True):
user = user.super(UserProfileForm, self).save()
customer = Customer(user=user)
customer.save()
Don't juste copy paste, it's just you to know you have first to register the user, and then add it to your new object, add the other fields, and save it.

Categories

Resources