Using Django model inheritence to clone a table - django

I have a user table and want to create a backup table named deleted_users that is a clone of the user table. When a user gets deleted I want to move the record from the user table to the deleted_users table.
class LCUser(models.Model):
email = models.EmailField(max_length=100,unique=True)
password = models.CharField(max_length=100)
first_name = models.CharField(max_length=100)
last_name=models.CharField(max_length=100)
class Meta:
db_table = "user"
class LCUserDeleted(LCUser):
deleted_at = models.DateTimeField(auto_now_add=True,null=True)
class Meta:
db_table = "deleted_users"
I tried as above but this creates the user table with all the fields and a deleted_users table with 2 fields ( lcusers_ptr_id and deleted_at ), How can I create the 2nd table with all the fields without typing everything one by one ?

to achieve what you're looking for you actually need 3 models, one abstract one and two actual models:
class BaseLCUser(models.Model):
email = models.EmailField(max_length=100,unique=True)
password = models.CharField(max_length=100)
first_name = models.CharField(max_length=100)
last_name=models.CharField(max_length=100)
class Meta:
abstract = True
class LCUser(BaseLCUser):
class Meta:
db_table = "user"
class LCUserDeleted(BaseLCUser):
deleted_at = models.DateTimeField(auto_now_add=True,null=True)
class Meta:
db_table = "deleted_users"
By using an abstract model as a common parent Django will actually create full tables for each of the models.
Edit:
Regarding the unique E-mail, you might want to avoid setting it to unique on a database level, and control it through your forms, because if you create and account with email example#example.org, delete it, create another one with the same email and delete than new account, you will be trying to have two deleted users with the same email.
another option would be to remove the email field from the abstract Model, and put it in each of the child models, being unique only in the not deleted user.

Related

Need to get the Foreign key value instead of ID in the database table using Django

model
class Project(models.Model):
project_name = models.CharField(max_length=20)
client= models.ForeignKey(Client,on_delete=CASCADE,related_name="Client1",default=None)
user=models.ManyToManyField(Default_User,related_name='users',default=None)
description=models.TextField()
type=models.TextField() #dropdown
start_date = models.DateTimeField(max_length=10)
end_date=models.DateTimeField(max_length=10)
technical_contact_name = models.CharField(max_length=30)
email=models.EmailField(max_length=254,default=None)
phone = PhoneField(blank=True)
delivery_head_contact_name=models.CharField(max_length=30)
class Meta:
db_table ='Project'
def __str__(self):
return self.project_name
model
class Job(models.Model):
job_name=models.CharField(max_length=50)
user= models.ForeignKey(Default_User,on_delete=CASCADE)
project = ChainedForeignKey(Project,chained_field="user", chained_model_field="user",related_name='projects',show_all=False, auto_choose=True, sort=True)
date = models.DateField(max_length=10,default=None)
class Meta:
db_table ='Job'
def __str__(self):
return '{}'.format(self.job_name)
serializers
class ProjectSerializers(serializers.ModelSerializer):
class Meta:
model= Project
fields= '__all__'
class Job_Serializers(serializers.ModelSerializer):
job = serializers.StringRelatedField()
class Meta:
model= Job
fields= ('id','job_name','user','project','date','job',)
I need to get the foreign key value displayed in the database table of Job model but as per the above code it is displaying the Foreign key ID. For example I linked the project model in the Job model and in the db table it is showing the Project_id as(1,2,3) but i need to return the values of that id as(app, learning etc). Please help me to get the values of the foreign key value instead of ID in the database table.
The database will by default take the unique field from the model and django provide id as unique key for models. It is for data consistency. So you can let that happen and in job serializera use SerializerMethodField to retrieve the value of project name based on instance of job objects.
Depends on what you want to achieve with it. If it is just to return another field value from project, then you can add it to the serializer as in below example. I am returning project_name as well.
class JobSerializers(serializers.ModelSerializer):
job = serializers.StringRelatedField()
project_name = serializers.SerializerMethodField()
class Meta:
model= Job
fields= ('id','job_name','user','project','date','job', 'project_name')
def get_project_name(self, job):
return job.project.project_name
If you want to return the whole project object then you have to include
project = ProjectSerializers()

Django Nested Serialization

this is my serializor.py
class AddressSerializor(serializers.ModelSerializer):
class Meta:
model = Address
fields = '__all__'
class PersonSerializer(serializers.ModelSerializer):
a = AddressSerializor(many=True)
class Meta:
model = Persion
fields = ('id' ,'name', 'age', 'a' )
this is my models page :
class Persion(models.Model):
name = models.TextField(max_length=200)
class Address(models.Model):
city = models.TextField(max_length=300)
state = models.TextField(max_length=301)
cuntry = models.TextField(max_length=222)
I am getting this error:
Got AttributeError when attempting to get a value for field `a` on serializer `PersonSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `Persion` instance.
Original exception text was: 'Persion' object has no attribute 'a'.
can any one help me what am i missing, as iam new to django i may miss the basic syntax too, Iam feguring this nearly 2 days no luck
Since according to your comments you have one address per person, you can technically put the address fields in the Person model, but if you want to separate it you need to link them like
class Address(models.Model):
city = models.TextField(max_length=300)
state = models.TextField(max_length=301)
cuntry = models.TextField(max_length=222)
class Persion(models.Model):
name = models.TextField(max_length=200)
address = models.OneToOneField(Address,
on_delete=models.CASCADE,
null=True, # allow field to be null
blank=True) # allow field to be blank (for admin interface)
This way the Persion would have an address field that would be of type Address model.
and your serializers
class AddressSerializor(serializers.ModelSerializer):
class Meta:
model = Address
fields = '__all__'
class PersonSerializer(serializers.ModelSerializer):
address = AddressSerializor() #note that address is the same name in the Persion model
class Meta:
model = Persion
fields = ('id' ,'name', 'address' )
in your question you had age as a field but you don't have an age field in the Persion model, you will need to add that.
check out the fields in Django docs
https://docs.djangoproject.com/en/3.2/ref/models/fields
You need to create a foreign key relationship between a Person and an Address. You can add the foreign key declaration to your models, and then generate/run migrations using python manage.py makemigrations <name-of-app> and python manage.py migrate.
class Person(models.Model):
... # the other model fields
address = models.ForeignKey(
"Address",
on_delete=models.SET_NULL,
null=True,
blank=True,
)

how to create two records in two modes at a time one having foreign key

Assume i have two models. ModelA & ModelB.ModelB will have Foregin key to ModelA. i want to create each record in both tables one haveing foregin key.
models.py
Class ModalA(models.Model):
name = models.CharField(max_length=200)
location = models.CharField(max_length=200)
Class ModelB(models.Model):
modela = models.ForeignKey(ModalA,on_delete=models.CASCADE)
state = models.CharField(max_length=200)
country = models.CharField(max_length=200)
serializer,py
class ModelBSerializers(serializers.ModelSerializer):
class Meta:
model = ModelB
fields = "__all__"
class ModalASerializers(serializers.ModelSerializer):
class Meta:
model = ModalA
fields = "__all__"
def create(self, validated_data):
return ModalA(**validated_data)
I would like to know how to create bot records in tables.
There are couple of way possible to ensure how we can populate two different model with some dependency requirement. Like after insert in model A there must be an entry of model B or vice-versa. One of well recommended way is to use django-signallink (post/pre what is more suitable for scenario). I would like to add additional link if you haven't work with django-signal you can follow this post.

How to fetch all records from 2 tables

I have 2 models
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True)
employee_id = models.CharField(max_length=13, unique=True)
class UserRole(models.Model):
employee_id = models.ForeignKey(CustomUser, to_field='employee_id', unique=True, on_delete=models.CASCADE)
supervisor_id = models.CharField(max_length=20, null=True)
and have defined seriallizers for both models
class UserSerializer(serializers.ModelSerializer):
class Meta:
fields = '__all__'
model = models.CustomUser
class UserRoleSerializer(serializers.ModelSerializer):
class Meta:
fields = '__all__'
model = models.UserRole
consider i have 5 records in both tables
How to fetch all records from both tables (email, employee_id, supervisor_id )
like, where CustomUser.employee_id = UserRole.employee_id
I tried with
models.CustomUser.objects.select_related('UserRole')
But, not able to fetch records from UserRole table.
UserRole.objects.select_related('employee_id')
-- this is fetching only userRole records
Thanks in Advance
You don't get automatic joins in Django, no need for it because you can just follow the ForeignKey relation on the object (the_object_you_get.its_foreign_key). Now, of course, that will hit the DB twice. if you'd rather avoid that, you can use something like .prefetch_related('employee_id') on whatever queryset you need to use. This will prevent you from hitting the DB multiple times (at the price of one larger initial query of course).
Finally, if you wanna serialize a ForeignKey relation, the answer Shakil gave is pretty comprehensive. Only thing is that you don't necessarily need to set the employee_id field as read_only=True (a bit of a limitation). You can also override the UserRoleSerializer .create() the method so that it calls the .create() method of UserSerializer.
I think from UserRole you want to all information about employe's too. What i am thinking you want to get all details information of employee_id foreign_key relation. This can be done by
UserRole.objects.all()
with the following serializers.
class UserSerializer(serializers.ModelSerializer):
class Meta:
fields = ('email','employee_id',)
model = models.CustomUser
class UserRoleSerializer(serializers.ModelSerializer):
employee_id = UserSerializer()
class Meta:
fields = ('employee_id','supervisor_id',)
model = models.UserRole

how to conditionally save a form using django multi table inheritance

I have the following form:
class PlaceForm(forms.ModelForm):
class Meta:
model = Place
I have the following models:
class Place(models.Model):
customer = models.ForeignKey(Customer)
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)
class Restaurant(Place):
serves_hot_dogs = models.BooleanField()
serves_pizza = models.BooleanField()
In my view I want to conditionally save either a Place or a Restaurant depending on the incoming url.
I have tried the following:
if form.is_valid():
place = form.save(commit=False)
place.customer = customer
place.save()
if url_name == 'restaurant':
restaurant = Restaurant(place_ptr_id=place.id)
restaurant.save()
This creates a place from the form and then tries to create a restaurant, but fails with following: (1048, "Column 'customer_id' cannot be null")
This is telling me that a new row for a new place is trying to be inserted and then the restaurant row.
I see a few different options:
Convert the Place to a restaurant and save the additional to the converted object.
Conditionally change the model type of the form to either Place or Restaurant
How can I accomplish saving the different parent and child objects conditionally?
It is related to Django model inheritance: create sub-instance of existing instance (downcast)? which suggests how to add object with existing base class object.
You may want to look at my question: Derived model filefield not available
In nutshell what you have to do is
restaurant = Restaurant(place_ptr_id=place.id)
restaurant.__dict__.update(place.__dict__)
restaurant.save()
You can add null=True and blank=True.
models:
class Place(models.Model):
customer = models.ForeignKey(Customer, null=True, blank=True)
name = models.CharField(max_length=50)
address = models.CharField(max_length=80)