I am trying to obtain in a query the data of a client and the contacts he has registered I tried to do it in the following way but it did not work.
class ClientReadOnlySerializer(serializers.ModelSerializer):
clientcontacts = ClientContactSerializer(many=True, read_only=True)
class Meta:
model = Client
fields = "__all__"
Is there any way to make this relationship nested?
these are my models
clients model
# Relations
from apps.misc.models import City, TypeIdentity, TypeCLient, CIIU
from apps.clients.api.models.broker.index import Broker
from apps.authentication.models import User
class Client(models.Model):
id = models.CharField(max_length=255, unique=True,primary_key=True, editable=False)
type_client = models.ForeignKey(TypeCLient, on_delete=models.CASCADE, blank=True)
type_identity = models.ForeignKey(TypeIdentity, on_delete=models.CASCADE, blank=True)
document_number = models.CharField(max_length=255, blank=True, unique=True)
first_name = models.CharField(max_length=255, blank=True, null=True)
last_name = models.CharField(max_length=255, blank=True, null=True)
social_reason = models.CharField(max_length=255, blank=True, null=True)
city = models.ForeignKey(City, on_delete=models.CASCADE, blank=True)
address = models.CharField(max_length=255, blank=True)
email = models.CharField(max_length=255, blank=True, unique=True)
phone_number = models.CharField(max_length=255, blank=True, unique=True)
ciiu = models.ForeignKey(CIIU, on_delete=models.CASCADE, blank=True)
broker = models.ForeignKey(Broker, on_delete=models.CASCADE, blank=True)
user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True)
income = models.SmallIntegerField(blank=True, default=0)
state = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(null=True, default=None)
client contacts model
# Relations
from apps.clients.api.models.index import Client
class ClientContact(models.Model):
id = models.CharField(max_length=255, primary_key=True, unique=True, editable=False)
client = models.ForeignKey(Client, on_delete=models.CASCADE)
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
phone_number = models.CharField(max_length=255)
state = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(null=True, blank=True, default=None)
after some research I came up with a solution that doesn't seem very practical, what I did was to create a method in the serializer that queries the client's contacts as follows
class ClientReadOnlySerializer(serializers.ModelSerializer):
contacts = serializers.SerializerMethodField(method_name='get_contacts')
class Meta:
model = Client
fields = "__all__"
extra_fields = ['contacts']
def get_contacts(self, obj):
contacts = ClientContact.objects.filter(client=obj)
serializer = ClientContactSerializer(contacts, many=True)
return serializer.data
using the model and the serializer of the contact model I made a query which I added in an extra field of the customer serializer, if someone knows how to make this process more optimal please reply.
Related
I get such an error while migrating to a database:
return Database.Cursor.execute(self, query)
django.db.utils.OperationalError: foreign key mismatch - "user_auth_customer"
referencing "user_auth_profile"
I have checked Foreign_Keys of my models and they look good.
I have no idea why I receive that error :(
Please, help me out here.
class Customer(AbstractUser):
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username']
objects = UserManager()
id = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True, editable=False)
profile = models.OneToOneField("Profile", related_name="user_profile",
on_delete=models.CASCADE, null=True)
first_name = models.CharField(max_length=50, null=True, blank=True)
last_name = models.CharField(max_length=50, null=True, blank=True)
username = models.CharField(max_length=30, null=True, blank=True)
phone = models.CharField(max_length=10, default='', null=True, blank=True)
email = models.EmailField(validators=[validators.EmailValidator()],
unique=True)
password = models.CharField(max_length=100, null=True, blank=True)
date_created = models.DateTimeField(auto_now_add=True)
#staticmethod
def get_customer_by_email(email):
try:
return Customer.objects.get(email=email)
except:
return False
def isExists(self):
if Customer.objects.filter(email=self.email):
return True
return False
class Meta:
verbose_name = 'Customer'
verbose_name_plural = 'Customers'
class Profile(models.Model):
first_name = models.CharField(max_length=50, null=True, blank=True)
last_name = models.CharField(max_length=50, null=True, blank=True)
phone = models.CharField(max_length=10, default='', null=True, blank=True)
email = models.EmailField(primary_key=True, unique=True, validators=[validators.EmailValidator()])
password = models.CharField(max_length=100, null=True, blank=True)
# Add a photo field
owner = models.OneToOneField(Customer, related_name='profile_owner',
on_delete=models.SET_NULL, null=True)
username = models.CharField(max_length=30, null=True, blank=True,
validators=[UnicodeUsernameValidator()])
date_created = models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name = 'Profile'
verbose_name_plural = 'Profiles'
if you need any else details, I can provide you with those in the comments.
You can't have both ways OneToOneField. Choose one way.
If you delete Customer's profile field, then still you will have possibility to call relation with:
customer = Customer.objects.get(id=1)
customer.profile # that will call Customer's related Profile object
Assuming, that you will change related_name='profile_owner' to simpler related_name='profile'.
Read more about OneToOneRelationships.
I have a user model that has to go through several tasks such as completing their information, taking some tests, and interviews. So I added a progress level field that shows the user status at the moment. this is my model:
class User(AbstractUser):
id = models.AutoField(primary_key=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
isPreRegistered = models.BooleanField(default=False)
role = models.CharField(max_length=25, null=True, choices=USER_ROLE_CHOICES, default=USER_ROLE_CHOICES[0][0])
role_id = models.CharField(max_length=10, default='applicant')
username = models.CharField(unique=True, max_length=13)
first_name = models.CharField(max_length=32, null=True, default=None)
last_name = models.CharField(max_length=64, null=True, default=None)
gender = models.CharField(max_length=10, null=True)
personalInfo = models.OneToOneField(PersonalInfo, on_delete=models.CASCADE, null=True)
contactInfo = models.OneToOneField(ContactInfo, on_delete=models.Case, null=True)
eliteInfo = models.OneToOneField(EliteInfo, on_delete=models.CASCADE, null=True)
progress_level = models.CharField(max_length=25, null=True, choices=USER_PROGRESS_LEVELS, default=USER_PROGRESS_LEVELS[0][0])
and there are multiple models which are connected to the user model using a foreign key relation.
this is one of the models I added here for instance:
class PsychologicInfo(models.Model):
id = models.AutoField(primary_key=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
final_assessment = models.TextField(null=True, blank=True)
is_approved = models.CharField(max_length=64, blank=True)
is_interviewed = models.BooleanField(default=False)
I want to write a signal or a save method that does something like this:
if the is_interviewed field was True, change that progress_level to USER_ROLE_CHOICES[1][0]
I have no idea how to do this so thanks for the tips
You can override the .save() method of PsychologicInfo
class PsychologicInfo:
...
def save(self):
super().save()
if self.is_interviewed:
self.user.role = USER_ROLE_CHOICES[1][0] # or enter value here
self.user.save()
or you can use Django signals.
I have two models: 1) SchoolProfile & 2) Content
I want to show content data in schoolprofile, But data should be display as per user foreignkey.
User foreignkey common for both the models.
School Profile Model
class SchoolProfile(models.Model):
id=models.AutoField(primary_key=True)
user=models.ForeignKey(User,on_delete=models.CASCADE,unique=True)
school_name = models.CharField(max_length=255)
school_logo=models.FileField(upload_to='media/', blank=True)
incharge_name = models.CharField(max_length=255, blank=True)
email = models.EmailField(max_length=255, blank=True)
phone_num = models.CharField(max_length=255, blank=True)
num_of_alu = models.CharField(max_length=255, blank=True)
num_of_student = models.CharField(max_length=255, blank=True)
num_of_cal_student = models.CharField(max_length=255, blank=True)
def __str__(self):
return self.school_name
Content Model
class Content(models.Model):
id=models.AutoField(primary_key=True)
user=models.ForeignKey(User,on_delete=models.CASCADE)
content_type = models.CharField(max_length=255, blank=True, null=True)
show=models.ForeignKey(Show,on_delete=models.CASCADE, blank=True, null=True)
sponsor_link=models.CharField(max_length=255, blank=True, null=True)
status=models.BooleanField(default=False, blank=True, null=True)
added_on=models.DateTimeField(auto_now_add=True)
content_file=models.FileField(upload_to='media/', blank=True, null=True)
title = models.CharField(max_length=255)
subtitle = models.CharField(max_length=255, blank=True, null=True)
description = models.CharField(max_length=500, blank=True, null=True)
draft = models.BooleanField(default=False)
publish_now = models.CharField(max_length=255, blank=True, null=True)
schedule_release = models.DateField(null=True, blank=True)
expiration = models.DateField(null=True, blank=True)
tag = models.ManyToManyField(Tag, null=True, blank=True)
topic = models.ManyToManyField(Topic, null=True, blank=True)
category = models.ManyToManyField(Categorie, null=True, blank=True)
def __str__(self):
return self.title
I have used Inline but it's show below error:
<class 'colorcast_app.admin.SchoolProfileInline'>: (admin.E202) 'colorcast_app.SchoolProfile' has no ForeignKey to 'colorcast_app.SchoolProfile'.
My admin.py
class SchoolProfileInline(InlineActionsMixin, admin.TabularInline):
model = SchoolProfile
inline_actions = []
def has_add_permission(self, request, obj=None):
return False
class SchoolProfileAdmin(InlineActionsModelAdminMixin,
admin.ModelAdmin):
inlines = [SchoolProfileInline]
list_display = ('school_name',)
admin.site.register(SchoolProfile, SchoolProfileAdmin)
Using the StackedInline to link two models is straight forward and a much clean practice, so basically this is my solution below:
class ContentInlineAdmin(admin.StackedInline):
model = Content
#admin.register(SchoolProfile)
class SchoolProfileAdmin(admin.ModelAdmin):
list_display = ('school_name',)
inlines = [ContentInlineAdmin]
models:
class FullNameMixin(models.Model):
name_id = models.BigAutoField(primary_key = True, unique=False, default=None, blank=True)
first_name = models.CharField(max_length=255, default=None, null=True)
last_name = models.CharField(max_length=255, default=None, null=True)
class Meta:
abstract = True
class Meta:
db_table = 'fullname'
class User(FullNameMixin):
id = models.BigAutoField(primary_key = True)
username = models.CharField(max_length=255, unique=True)
email = models.CharField(max_length=255, unique=True)
token = models.CharField(max_length=255, unique=True, null=True, blank=True)
password = models.CharField(max_length=255)
role = models.IntegerField(default=1)
verified = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True, null=True, blank=True)
updated_at = models.DateTimeField(auto_now=True, null=True, blank=True)
def __str__(self):
return self.username
class Meta:
db_table = 'cga_user'
class Profile(FullNameMixin):
id = models.BigAutoField(primary_key = True)
birthday = models.DateTimeField(null=True, blank=True)
country = models.CharField(max_length=255, null=True, blank=True)
state = models.CharField(max_length=255, null=True, blank=True)
postcode = models.CharField(max_length=255, null=True, blank=True)
phone = models.CharField(max_length=255, null=True, blank=True)
profession_headline = models.CharField(max_length=255, null=True, blank=True)
image = models.ImageField(upload_to=get_upload_path, null=True, blank=True)
profile_banner = models.ImageField(upload_to=get_upload_path_banner, null=True, blank=True)
cga_user = models.OneToOneField(User, null=True, blank=True, on_delete=models.CASCADE, related_name="profile")
gender = models.CharField(
max_length=255, blank=True, default="", choices=USER_GENDER_CHOICES
)
created_at = models.DateTimeField(auto_now_add=True, null=True, blank=True)
updated_at = models.DateTimeField(auto_now=True, null=True, blank=True)
class Meta:
db_table = 'profile'
When i am creating Profile from django admin panel getting below error.
e
filename = self.upload_to(instance, filename)
File "/Users/soubhagyapradhan/Desktop/upwork/africa/backend/api/model_utils/utils.py", line 7, in get_upload_path
instance.user,
File "/Users/soubhagyapradhan/Desktop/upwork/africa/backend/env/lib/python3.8/site-packages/django/db/models/fields/related_descriptors.py", line 421, in __get__
raise self.RelatedObjectDoesNotExist(
api.models.FullNameMixin.user.RelatedObjectDoesNotExist: Profile has no user.
[24/Jul/2021 13:49:51] "POST /admin/api/profile/add/ HTTP/1.1" 500 199997
please take a look how can i fix this.
Note: User model creation working but, profile not working
I checked in drf and django admin panel .
both place not working.
The problem here is that you are declaring a User model which is in fact just a model. That's not how it works.
The User is a special type of model and if you want to change it you have to extend the AbstractUser class.
Alternatively you can connect to it via one-to-one classes in the classic user-profiles approach.
But here you are creating a user model that (besides using the reserved word 'User') has none of the requirements necessary to be treated as a user who can be authenticated and that can instantiate sessions.
> Example of a simple user-profiles architecture
> Working with User objects - Django Docs (i particularly recommend this one)
I would recommend you to read-up on django user authentication.
I have three models : Domain Topic Post
Topic has a foreign key to Domain and Post has a foreign key to Topic.
Post has a field updated_on.
I want to annotate last_updated field in Domain queryset which would contain the latest post object from Post .
Edit 1: Added models definition:
class Board(models.Model):
name = models.CharField(max_length=30, unique=True)
description = models.CharField(max_length=50)
creation_time = models.DateTimeField(auto_now_add=True)
class Topic(models.Model):
subject = models.CharField(max_length=300, unique=True)
board = models.ForeignKey(Board, on_delete=models.SET_NULL, related_name='topics', null=True)
created_by = models.ForeignKey(User, on_delete=models.SET_NULL, related_name='topics', null=True)
created_on = models.DateTimeField(auto_now_add=True)
views = models.PositiveIntegerField(default=0)
class Post(models.Model):
message = models.CharField(max_length=5000)
created_by = models.ForeignKey(User, on_delete=models.SET_NULL, related_name='posts', null=True)
created_on = models.DateTimeField(auto_now_add=True)
topic = models.ForeignKey(Topic, on_delete=models.SET_NULL, related_name='posts', null=True)
updated_on = models.DateTimeField(default=timezone.now)