How to save multiple object in a single POST request - django

I am new to DRF
I am saving a user details and his pets details .
Here is the model
class Users(models.Model):
id = models.AutoField(primary_key=True)
first_name = models.CharField(max_length=255, blank=True)
last_name = models.CharField(max_length=255, blank=True)
job = models.CharField(max_length=255, blank=True)
age = models.CharField(max_length=255, blank=True)
class PetDetails(models.Model):
user = models.ForeignKey(
Users, on_delete=models.CASCADE, blank=True, null=True)
pet_name = models.CharField(max_length=255, blank=True)
pet_color = models.CharField(max_length=255, blank=True)
pet_category = models.CharField(max_length=255, blank=True)
In this I need to save both user and his pets in a single Post request.
So I created a serializer like this
class UserCreateSerializer(ModelSerializer):
pet = PetDetailCreateSerializer(many=True)
class Meta:
model = Users
fields = ['first_name','last_name','job','age', 'pet']
def create(self, validated_data):
pets_data = validated_data.pop('pet')
user_obj = Users.objects.create(**validated_data)
for pet in pets_data:
PetDetails.objects.create(user=user_obj, **pet)
return user_obj
The issue I am facing is if a single person can have multiple pets.
For Example John is a user and he having two Pets.
So in this cases two users object will creating .How to resolve this
OR is there any other methods for handling this
My views is
class UserCreateView (CreateAPIView):
serializer_class = UserCreateSerializer

One way is to check if user already exists by using get_or_create:
user_obj = Users.objects.get_or_create(**audit_data)
But better way, I think, is to create user with multiple pets instead:
class UserCreateSerializer(ModelSerializer):
petdetails_set = PetDetailCreateSerializer(many=True)
class Meta:
model = Users
fields = ['first_name','last_name','job','age', 'petdetails_set']
def create(self, validated_data):
pets_data = validated_data.pop('pet')
user_obj = User.objects.create(**validated_data)
for pet in pets_data:
PetDetails.objects.create(user=user_obj, **pet)
return user_obj
Also, I advice to use separate endpoints/serializers for user creation.

Related

This field must be unique error in postman in OnetoOneField in Django Rest Framework

I am trying to update Customer Profile also updating main Customuser first_name and last_name field at the same time using nested serialization. But I am getting customer field must be unique error.
I have posted the pics here.
My models:
class CustomUser(AbstractUser):
# username = None
first_name = models.CharField(max_length=255, verbose_name="First name")
last_name = models.CharField(max_length=255, verbose_name="Last name")
email = models.EmailField(unique=True)
is_seller = models.BooleanField(default=False)
is_customer = models.BooleanField(default=False)
USERNAME_FIELD = "email"
REQUIRED_FIELDS = ["first_name", "last_name"]
objects = CustomUserManager()
def __str__(self):
return self.email
class Customer(models.Model):
customer = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, blank=True, null=True)
full_name = models.CharField(max_length=100, blank=True)
phone_num = models.CharField(max_length=50, blank=True)
#dob = models.CharField(max_length=255,blank=True,null=True)
region = models.CharField(max_length=255, blank=True,null=True)
city = models.CharField(max_length=255, blank=True, null=True)
area = models.CharField(max_length=255,blank=True,null=True)
address = models.CharField(max_length=255, blank=True, null=True)
def __str__(self):
return self.customer.email
My serializers:
class CustomerProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Customer
fields = '__all__'
# depth = 1
class CustomerUpdateSerializer(serializers.ModelSerializer):
customer = CustomerProfileSerializer()
class Meta:
model = User
fields = ('id', "first_name", "last_name",'customer')
def update(self,request, instance, validated_data):
user = self.request.user
instance.user.first_name=user.get('first_name')
instance.user.last_name = user.get('last_name')
instance.user.save()
customer_data = validated_data.pop('customer',None)
if customer_data is not None:
instance.customer.region = customer_data['region']
instance.customer.city = customer_data['city']
instance.customer.area = customer_data['area']
instance.customer.address = customer_data['address']
instance.customer.save()
return super().update(instance,validated_data)
My views:
class CustomerUpdateView(UpdateAPIView):
permission_classes = [IsAuthenticated]
queryset = User.objects.all()
serializer_class = CustomerUpdateSerializer
The url is visible in postman put request. I have sent the raw json data in the postman, but it throws this error. How to update those 4 fields in customer and 2 fields (first_name and last_name) from User model??
My code worked after I made some changes to the serializer.
Here is the working code:
class CustomerUpdateSerializer(serializers.ModelSerializer):
customer = CustomerProfileSerializer(many=False)
class Meta:
model = User
fields = ('id', "first_name", "last_name",'customer')
depth = 1
def update(self, instance, validated_data):
user = self.context['request'].user
user.first_name = validated_data.get('first_name')
user.last_name = validated_data.get('last_name')
user.save()
customer_data = validated_data.pop('customer',None)
if customer_data is not None:
instance.customer.region = customer_data['region']
instance.customer.city = customer_data['city']
instance.customer.area = customer_data['area']
instance.customer.address = customer_data['address']
instance.customer.save()
return super().update(instance,validated_data)
Its because I was using instance of user and same instance to customer model. Now, I get the fields first_name and last_name separately and use instance for customer only.It worked.

Request.user on Django Model forms

I have a ledger account table that consist of ledger accounts of all the companies. The user in logged into a specific company and hen he selects an account to use on a form only the accounts that company must be available for the user. for this purpose I use the request.user to determine the user. I however get an error "request does not exist". I understand why it is not available on the forms.py as there is no request executed. Is there a way that I can make request.user available of the form.
Models.py
class tledger_account(models.Model):
id = models.AutoField(primary_key=True)
description = models.CharField(max_length=30, unique=True)
gl_category = models.CharField(max_length=30, choices=category_choices, verbose_name='category', db_index=True)
note = models.CharField(max_length=25, blank=True, default=None)
active = models.BooleanField(default=True)
company = models.ForeignKey(tcompany, on_delete=models.PROTECT, db_index=True)
forms.py
class SelectAccountForm(forms.ModelForm):
date_from = forms.DateField(widget=forms.SelectDateWidget(years=year_range))
date_to = forms.DateField(widget=forms.SelectDateWidget(years=year_range))
select_account = forms.ModelChoiceField(queryset=tledger_account.objects.filter(
company = request.user.current_company))
class Meta:
model = ttemp_selection
fields = ['select_account', 'date_from', 'date_to']
When you use request.user you are using the fields of the user model so it is not necessary to have them in the form, for that you need to have a forensic relationship with the user model:
class tledger_account(models.Model):
id = models.AutoField(primary_key=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
description = models.CharField(max_length=30, unique=True)
gl_category = models.CharField(max_length=30, choices=category_choices, verbose_name='category', db_index=True)
note = models.CharField(max_length=25, blank=True, default=None)
active = models.BooleanField(default=True)
company = models.ForeignKey(tcompany, on_delete=models.PROTECT, db_index=True)
and the view:
def tledger_account_view(request):
template_name = 'your template'
user = request.user
tledger_account = tledger_account.objects.get(user=user)
return render(request, template_name, {
'tledger_account': tledger_account,
})
more info https://docs.djangoproject.com/en/3.1/topics/auth/default/

Django Model object creation method

I'm having two models where UserGroup model, which contains a group admin, and DetailedUser model which related to the group model, where the field user points all users in the certain UserGroup, I want to add a field that when a new user added to the group it store its date and time of user added to the particular group.
class UserGroup(models.Model):
group_admin = models.ForeignKey(User, on_delete=models.CASCADE, related_name='group_by')
group_name = models.CharField(max_length=100)
group_amount = models.PositiveSmallIntegerField()
def __str__(self):
return self.group_name
class DetailedUser(models.Model):
group = models.ForeignKey(UserGroup, on_delete=models.CASCADE, related_name='user_group')
user = models.ManyToManyField(
User, related_name='single_user')
user_added = models.DateTimeField(auto_now_add=True)
is_active = models.BooleanField(default=True)
def __str__(self):
return f"{self.group.group_name}"
How can I done this method?
I think your model design is not correct. What you need(I think) is ManyToManyField with though. For example:
class UserGroup(models.Model):
group_admin = models.ForeignKey(User, on_delete=models.CASCADE, related_name='group_by')
group_name = models.CharField(max_length=100)
group_amount = models.PositiveSmallIntegerField()
members = models.ManyToManyField(User, through="DetailedUser")
def __str__(self):
return self.group_name
class DetailedUser(models.Model):
group = models.ForeignKey(UserGroup, on_delete=models.CASCADE, related_name='user_group')
user = models.ForeignKey(
User, related_name='single_user')
user_added = models.DateTimeField(auto_now_add=True)
is_active = models.BooleanField(default=True)
def __str__(self):
return f"{self.group.group_name}"
Usage example:
>> group = UserGroup.objects.get(pk=1)
>> user = User.objects.first()
>> DetailedUser.objects.create(group=group, user=user)
>> group.memebers.all()

Multiple type user's authority is messy when change user profile with UpdateView - Django

I have three user types in user model(create, query and common), multiple type user's authority is messy when I am changing user profile with UpdateView, for example, a user who is admin, when admin clicked a user who is common user, then that user in page is in common user's authority, my UpdateView is as below:
class UserUpdateView(UpdateView):
model = User
form_class = UserForm
context_object_name = 'user'
template_name = 'general/teachers/user_change_form.html'
def get_object(self):
return get_object_or_404(User, pk=self.kwargs['pk'])
models of user:
class User(AbstractUser):
name = models.CharField(max_length=100, verbose_name="姓名", default="", blank=True)
gender = models.CharField(
max_length=7,choices=(("male","男"),("female","女")),
default="female", verbose_name="性别",
)
department = models.ForeignKey(
Department,
on_delete=models.CASCADE, null=True, blank=True, verbose_name="所属部门",
)
job_title = models.CharField(max_length=100, verbose_name="职位", default="", blank=True)
mobile = models.CharField(max_length=11, verbose_name="手机号", default="", blank=True)
email = models.EmailField(max_length=50, verbose_name="邮箱", default="", blank=True)
is_employee = models.BooleanField(default=True, verbose_name='是否是普通用户')
is_teacher = models.BooleanField(default=False, verbose_name='是否是查询用户')
is_supervisor = models.BooleanField(default=False, verbose_name='是否是评测人')
add_time = models.DateTimeField(auto_now=True, verbose_name="添加时间")
forms of user:
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ('username', 'department', 'gender', 'job_title', 'email', 'mobile')

How to create a user profile with different views in django?

I've two type of users: Students and Institutions.
Both can login in the website and they have different profiles views.
I'd like to use "http://example.com/accounts/" for both types of users but running different logics and displaying different templates for each one.
For example, Students when they go to their profile they can view/modify their attributes as what are they studying, interested courses.. etc. On the other side, the institution users can view/modify attributes of their own model as institution information.
Institution User Type:
class InstitutionProfile(models.Model):
user = models.OneToOneField(User, related_name='client')
gender = models.CharField(max_length=40, choices=GENDERS_TYPES, blank=True)
#Contact Information
location = models.ManyToManyField(Location)
address = models.CharField(max_length=254, blank=True)
zipcode = models.CharField(max_length=56, blank=True)
phone = models.CharField(max_length=56, blank=True)
def __unicode__(self):
return '%s' % format(self.user)
Student User Type:
class StudentProfile(models.Model):
user = models.OneToOneField(User, related_name='profile')
about_me = models.TextField(null=True, blank=True)
gender = models.CharField(max_length=40, choices=GENDERS_TYPES, blank=True)
birth = models.DateTimeField(blank=True, null=True)
#Contact Information
location = models.ManyToManyField(Location, related_name='homecountry')
address = models.CharField(max_length=254, blank=True)
zipcode = models.CharField(max_length=56, blank=True)
phone = models.CharField(max_length=56, blank=True)
#Interested
countries_interested = models.ManyToManyField(Location, blank=True, related_name='countries interested')
areas_interested = models.ManyToManyField(StudyArea, blank=True)
levels_interested = models.ManyToManyField(StudyLevel, blank=True)
languages_interested= models.ManyToManyField(LanguageCourse, blank=True)
def __unicode__(self):
return '%s' % format(self.user)
view.py
class InstitutionProfileDetailView(DetailView):
model = get_user_model()
slug_field = "username"
template_name = "account/institution_profile.html"
def get_object(self, queryset=None):
user = super(InstitutionProfileDetailView, self).get_object(queryset)
InstitutionProfile.objects.get_or_create(user=user)
return user
class StudentProfileDetailView(DetailView):
model = get_user_model()
slug_field = "username"
template_name = "account/student_profile.html"
def get_object(self, queryset=None):
user = super(StudentProfileDetailView, self).get_object(queryset)
StudentProfile.objects.get_or_create(user=user)
return user
What is the best solution for having different views with 2 different type of users?
You can use an unified view and return different views from that according to your logic -
def accounts_view(request):
if request.user.is_student(): # <-- check with your logic, is_student() is a stub
return StudentProfileDetailView.as_view()
elif request.user.is_institute():
return InstitutionProfileDetailView.as_view()
And point accounts/ to accounts_view.