Im trying to find a method for posting a string value and saving it to a foreign key field instead of using the pk.
My models:
class CustomUser(models.Model):
username = models.CharField(max_length=500, unique=True)
def __str__(self):
return self.username
class Order(models.Model):
ordernumber = models.UUIDField(primary_key=False, default=uuid.uuid4, editable=False)
user = models.ForeignKey(CustomUser, on_delete=models.SET_NULL, null=True, blank=True)
amount = models.FloatField(null=True, blank=True)
def __str__(self):
return "{0}".format(self.ordernumber)
And my serializer:
class OrderSerializer(serializers.ModelSerializer):
username = serializers.CharField(source='user.username')
class Meta:
model = Order
fields = ('id','username', 'ordernumber', 'amount')
read_only_fields = ('id')
When using GET, everything works perfectly, but I can't seem to fix the POST method.
I tried to override the create method like this:
def create(self, validated_data):
username = validated_data.pop('username')
order = Order.objects.create(**validated_data)
order.user = CustomUser.objects.get(username=username)
order.save()
return order
But I get a KeyError on the username = validated_data.pop('username') line: Exception Value:'username'
When you use source with nested fields, data will be accessible as validated_data['parent_field']['child_field']. Try this:
def create(self, validated_data):
user_data = validated_data.pop('user')
username = user_data.pop('username')
order = Order.objects.create(**validated_data)
order.user = CustomUser.objects.get(username=username)
order.save()
return order
Related
I am trying to get a list of all pathologists in my system. I need to filter the user on 2 basis i-e is_pathologist and Lab_Id=request.data[email]
I have tried switching between filter and get but then I get
Authentication.models.User.MultipleObjectsReturned: get() returned more than one User -- it returned 12!
Error traceback here
This is the code of my view
#api_view(['POST'])
def getAllPathologists(request):
user = get_user_model().objects.get(is_pathologist=True)
# If user exists, get the employee
print("user is: ", user)
pathologist = Employee.objects.get(user=user.email, Lab_Id=request.data['email'])
pathologistSerializer = EmployeeSerializer(pathologist, many=True)
return Response(pathologistSerializer.data)
This is user model
class User(AbstractUser):
# Add additional fields here
id = None
email = models.EmailField(max_length=254, primary_key=True)
name = models.CharField(max_length=100)
password = models.CharField(max_length=100)
contact_number = models.CharField(max_length=100)
is_patient = models.BooleanField(default=False)
is_doctor = models.BooleanField(default=False)
is_homesampler = models.BooleanField(default=False)
is_pathologist = models.BooleanField(default=False)
is_admin = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_lab = models.BooleanField(default=False)
date_joined = models.DateTimeField(auto_now=True,editable=False)
last_login = models.DateTimeField(auto_now=True)
first_name = None
last_name = None
username = None
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['name', 'password']
objects = CustomUserManager()
def __str__(self):
return self.email
# Ensure that the password is hashed before saving it to the database
def save(self, *args, **kwargs):
self.password = make_password(self.password)
super(User, self).save(*args, **kwargs)
def has_perm(self, perm, obj=None):
return self.is_superuser
This is Employee model
class Employee(models.Model):
user = models.OneToOneField(
get_user_model(), on_delete=models.CASCADE, primary_key=True)
CNIC = models.CharField(max_length=100, unique=True)
Lab_Id = models.ForeignKey(Lab, on_delete=models.CASCADE)
def __str__(self):
return self.user.name
This is employee serializer
class EmployeeSerializer(serializers.ModelSerializer):
userData = UserSerializer(read_only=True, source='user')
email = serializers.EmailField(write_only=True)
password = serializers.CharField(write_only=True)
name = serializers.CharField(write_only=True)
contact_number = serializers.CharField(write_only=True)
is_homesampler = serializers.BooleanField(write_only=True)
class Meta:
model = Employee
# fields = " __all__"
fields = ["CNIC", "Lab_Id", "userData",
"name", "contact_number", "email", "password", "is_homesampler"]
def create(self, validated_data):
print("validated data = ", validated_data)
email = validated_data.pop("email")
password = validated_data.pop("password")
name = validated_data.pop("name")
contact_number = validated_data.pop("contact_number")
is_homesampler = validated_data.pop("is_homesampler")
user = get_user_model().objects.create_user(
email=email, password=password, name=name, contact_number=contact_number)
if (is_homesampler):
user.is_homesampler = True
else:
user.is_pathologist = True
user.save()
EmployeeObj = Employee.objects.create(user=user, **validated_data)
return EmployeeObj
You are getting objects and querysets conflated, filter() will return a queryset whereas get() tries to return an object. Below are the reasons for your errors:
The reason for your error with filter() is that a queryset is essentially a group of user objects. The queryset itself has no attribute email, but each user object within the group would. You therefore need to extract a single user from the queryset using first() or last(), for example.
Your error with get() is that your parameters are too broad and thus 12 users are returned. You need to adjust your code to handle this, it's usually done with either a try/except block or using the get_object_or_404 Django shortcut. Once you successfully get the user object, you can call user.email without issue.
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.
I am set on building a small website using django. What i am trying to do right now is using a CreateView based on a Model "Order", which one of its fields is another model "Customer".
The form itself works to create Orders, but im trying to find out how i can validate that the Customer that was selected is "enabled" (there is a status in the Customer model).
I was trying using the clean method but it doesnt even seem to be executing. I tried just raising the error on the clean, without validating anything, and still doesnt work. Any clue what might be wrong?
My Form:
class OrderForm(ModelForm):
def clean_customer(self, *args, **kwargs):
raise forms.ValidationError("This customer is banned.")
class Meta:
model = Order
fields = '__all__'
Relevant Models:
class Order(models.Model):
ORDER_STATUS = (('Pending Delivery', 'Pending Delivery'),
('Book on Customer', 'Book on Customer'),
('Overdue', 'Overdue'),
('Completed','Completed'))
customer = models.ForeignKey(Customer, null=True, on_delete=models.SET_NULL)
book = models.ForeignKey(Book, null=True, on_delete=models.SET_NULL)
date_created = models.DateTimeField(auto_now_add=True)
date_due = models.DateTimeField(null=True)
date_completed = models.DateTimeField(null=True, blank=True)
status = models.CharField(max_length=100, choices=ORDER_STATUS, null=True)
def get_absolute_url(self):
return reverse('orders')
class Customer(models.Model):
status = models.CharField(max_length=10, null = True, choices=STATUS_CHOICES)
name = models.CharField(max_length=200, null=True)
username = models.CharField(max_length=25, null = True)
email = models.EmailField(null=True)
def __str__(self):
return str(self.name)+" - " +str(self.username)
def get_absolute_url(self):
return reverse('customers')
The View:
class OrderCreateView(CreateView):
model = Order
fields = '__all__'
def form_valid(self, form):
return super().form_valid(form)
I have some problem in uploading picture in user profile its already extended onetoone from users , when I wanted to upload pic via postman it returned null value
serializer :
class UserProfileSerializer(serializers.ModelSerializer):
user = UserSerializer()
class Meta:
model = UserProfile
fields = ('user', 'bio', 'avatar')
def validate(self, data):
print(data)
self.context['avatar'] = self.context['request'].FILES.get('avatar')
return data
def create(self, validated_data):
user_data = validated_data.pop('user')
user = UserSerializer.create(UserSerializer(), validated_data=user_data)
validated_data['avatar'] = self.context['avatar']
validated_data['user'] = user
profile = UserProfile.objects.create(**validated_data)
profile.bio = validated_data["bio"]
profile.save()
return profile
The model:
class UserProfile(models.Model):
user = models.OneToOneField(User, primary_key=True, related_name='profile', on_delete=True)
bio = models.CharField(max_length=50, blank=True)
avatar = models.ImageField(upload_to="media", blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.user.username
i found the solution ,the picture in django store in memory at request.FILES
userprofile = UserProfile.objects.create(user=user, bio=validated_data.pop('bio'), user_type=type)
images_data = self.context.get('view').request.FILES
for image_data in images_data.values():
ProfileImage.objects.create(userprofile=userprofile, image=image_data, user_type=type)
I have a question in django rest framework. Since I'm learning how to use some advanced options, I do not quite understand. I need to currently change a booleanfield every time a foreignkey is inserted into table.
How can I do this in model ?
Model:
class Persona(models.Model):
name = models.CharField(max_length=32)
cart = models.ForeignKey(Credit,null=True)
rg = models.IntergerField()
end = models.CharField(max_length=256)
details = models.TextField(blank=True, null=True)
order = models.ForeignKey(Order, null=True)
def __str__(self):
return self.cart
class Meta:
db_table='person'
app_label = 'bank'
class Credit(models.Model):
number = models.CharField(max_length=16, unique=True)
create_at = models.DateField(auto_add_now=True)
updated_at = models.DateField()
available = models.BooleanField()
def __str__(self):
return self.number
class Meta:
db_table = 'credit'
app_label = 'bank'
Serializer:
class PersonaSerializer(serializers.ModelSerializer):
order__id = serializers.ReadOnlyField(source='order.id')
class Meta:
model = Persona
fields = '__all__'
class Persona(viewsets.ModelViewSet):
allowed_methods = ('GET', 'POST', 'PUT', 'PATCH')
queryset = Persona.objects.all()
serializer_class = PersonaSerializer
You can override the create method on the ModelSerializer to achieve this:
def create(self, validated_data):
cart = validated_data['cart']
persona = super(PersonaSerializer, self).create(validated_data)
cart.available = True # update boolean
cart.save()
return persona
You can read more about this in the docs
If you want to handle this in your model you can override the Persona model save method:
class Persona(models.Model):
name = models.CharField(max_length=32)
cart = models.ForeignKey(Credit,null=True)
rg = models.IntergerField()
end = models.CharField(max_length=256)
details = models.TextField(blank=True, null=True)
order = models.ForeignKey(Order, null=True)
def __str__(self):
return self.cart
class Meta:
db_table='person'
app_label = 'bank'
def save(self, *args, **kwargs):
# Will only update the available field when the Persona
# instance is created and the cart field is not null
if not self.pk and self.cart:
self.cart.available = True
self.cart.save()
return super(Persona, self).save(*args, **kwargs)