I am trying to create a Many to Many relation with a model in between, I have a Client model, and a Zone model, each client may have access to different zones, and each zone may have multiple clients.
Therefore I created a model called Access Permission, that stores said relation, and I want to show a dropdown selector in the post form that shows the existing clients and zones, or to ask for the Id of an existing object, instead of showing the form to create new ones.
These are my models:
class Zone(models.Model):
name = models.TextField()
created = models.DateTimeField(auto_now=True)
def __str__(self):
return '%s' % (self.name)
class Client(models.Model):
name = models.TextField()
birthDate = models.DateField()
created = models.DateTimeField(auto_now=True)
def __str__(self):
return '%s' % (self.name)
class AccessPermission(models.Model):
idClient = models.ForeignKey(Client, on_delete=models.CASCADE, null=False)
idZone = models.ForeignKey(Zone, on_delete=models.CASCADE, null=False)
And these my current serializers:
class ZoneSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Zone
fields = ('name',)
class ClientSerializer(serializers.HyperlinkedModelSerializer):
zones = ZonesSerializer(source='accesspermission_set', many=True, read_only=True)
class Meta:
model = Client
fields = ('name', 'birthDate', 'zones')
class AccessPermissionSerializer(serializers.ManyRelatedField):
idClient = ClientSerializer(many=False)
idZone = ZoneSerializer(many=False)
class Meta:
model = AccessPermission
fields = ('idClient', 'idZone')
Is there any way to ask for the Id of an existing object, or show the existing ones, instead of the fields to create new ones?
You can do it like:
models
class AccessPermission(models.Model):
client = models.ForeignKey(Client, on_delete=models.CASCADE, null=False)
zone = models.ForeignKey(Zone, on_delete=models.CASCADE, null=False)
serializers
class AccessPermissionSerializer(serializers.ManyRelatedField):
id = serializers.IntegerField(read_only=True)
client_id = serializers.PrimaryKeyRelatedField(
queryset=Client.objects.all(), source='client', allow_null=False, required=True
)
zone_id = serializers.PrimaryKeyRelatedField(
queryset=Zone.objects.all(), source='zone', allow_null=False, required=True
)
class Meta:
model = AccessPermission
fields = (
'id', 'client_id', 'zone_id'
)
Related
I want to Post the Company object using React. However, the Foreign key seems to be failing. I'm not sure how so I pass the data for address and invoice address.
Below is my code
models.py
class Address(models.Model):
id = models.UUIDField()
city = models.CharField(max_length=20, null=True, blank=True)
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
class Company(models.Model):
id = models.UUIDField()
address = models.ForeignKey(Address, on_delete=models.CASCADE,
related_name='address')
invoice_address = models.ForeignKey(Address, on_delete=models.CASCADE,
related_name='invoice_address')
serializers.py
class AddressSerializer(serializers.ModelSerializer):
class Meta:
model = Address
exclude = ('id', 'created', 'modified')
class CompanySerializer(serializers.ModelSerializer):
address = AddressSerializer()
invoice_address = AddressSerializer()
class Meta:
model = Company
def create(self, data):
#create address if it does not exist
In this project, I have two models Student and Parent related to each other through one to one field.
In Parent serializer, I want to add Students attributes like age. I am thinking of using SerializerMethodField for both cases is their any better way to do it?
I am not getting the queries on how to get the object attributes and little explanation would be great.
Here what I have done till now.
Models.py
class Student(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True, default=None)
batch = models.ForeignKey(Batch, on_delete=models.CASCADE, null=True, related_name='students')
email = models.EmailField(null=True)
phone_number = models.CharField(max_length=10, null=True)
dob = models.DateField(blank=True, null=True, help_text="Enter in the following format : YYYY-MM-DD")
address = models.TextField(max_length=150, null=True)
age = models.IntegerField(blank=True)
image = models.ImageField(upload_to='profile_pictures', default='student_image.png', blank=True)
#property
def remarks(self):
return self.remark_set.all()
#property
def marks(self):
return self.marks_set.all()
def __str__(self):
return self.user.firstName + ' ' + self.user.lastName
class Parent(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True, default=None)
child = models.ForeignKey(Student, on_delete=models.CASCADE)
email = models.EmailField(null=True)
phone_number = models.CharField(max_length=10, null=True)
address = models.TextField(max_length=150, null=True)
image = models.ImageField(upload_to='profile_pictures', default='student_image.png', blank=True)
def __str__(self):
return self.user.firstName + ' ' + self.user.lastName
Serilaizer.py
class ParentSerializer(serializers.HyperlinkedModelSerializer):
student_age = serializers.SerializerMethodField()
student_batch = serializers.SerializerMethodField()
parent_name = serializers.SerializerMethodField()
class Meta:
model = Parent
fields = "__all__"
def get_student_age(self, obj):
return Parent.objects.get(child__age = self.obj.user.child)
def get_student_batch(self, obj):
return Parent.objects.get(child__bacth = self.obj.user.child)
def get_parent_name(self, user):
return Parent.objects.get(user=self.request.user)
Views.py
class ParentView( mixins.ListModelMixin, mixins.RetrieveModelMixin,viewsets.GenericViewSet):
queryset = Parent.objects.all()
serializer_class = serializers.ParentSerializer
first way:
from apps.models import Student, parent
class BasicUserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = "__all__"
class BasicStudentSerializer(serializers.ModelSerializer):
class Meta:
model = Student
fields = "__all__"
class ParentSerializer(serializers.ModelSerializer):
user = BasicUserSerializer(read_only=True,many=False)
child = BasicStudentSerializer(read_only=True, many=True)
class Meta:
model = Parent
fields = '__all__'
you can do this way . its replace a serializer field that you want and if parent have several child then in child's field you have new all child's information as dictionary.
================================================================
second way is use HyperLinkModel .
class ParentSerializer(serializers.ModelSerializer):
user = serializers.HyperlinkedRelatedField(read_only=True,many=False)
child = serializers.HyperlinkedRelatedField(read_only=True, many=True)
class Meta:
model = Parent
fields = '__all__'
but notice that in first way you will have a independent serializer class that every time you need to serialize model class that related to User or Child you can use them simply.
I have the following models
class Company(models.Model):
name = models.CharField(max_length=100)
description = models.TextField(
max_length=500,
blank=True,
help_text='Any text to describe a company'
)
url = models.URLField('company URL', blank=True, null=True)
email = models.EmailField(blank=True, null=True)
created_on = models.DateTimeField('date created', default=timezone.now)
class Meta:
verbose_name = 'company'
verbose_name_plural = 'companies'
ordering = ['name', '-created_on']
def __repr__(self):
return '<Company {0.name}>'.format(self)
def __str__(self):
return self.name
class Project(models.Model):
name = models.CharField(max_length=100)
description = models.TextField(
max_length=500,
blank=True,
help_text='Any text to describe the project'
)
company = models.ForeignKey(
Company,
on_delete=models.PROTECT,
)
created_on = models.DateTimeField('date created', default=timezone.now)
class Meta:
verbose_name = 'project'
verbose_name_plural = 'projects'
ordering = ['-created_on', 'company']
permissions = (
("can_view_project",
"Can view all project related work"),
)
def __repr__(self):
return '<Project {0.name}>'.format(self)
def __str__(self):
return self.name
class Worker(models.Model):
description = models.TextField(
max_length=500,
blank=True,
help_text='Optional. Describe what the worker does or who they are'
)
user = models.ForeignKey(settings.AUTH_USER_MODEL)
company = models.ForeignKey(Company)
class Meta:
order_with_respect_to = 'user'
def __repr__(self):
return '<Worker {0.id}'.format(self)
def __str__(self):
return self.user.get_fullname()
The problem
I would like to add a ManyToMany relationship between Project and Worker so that I can view
a list of workers under a certain project. However, I want to make sure that a worker can only
be added to a project if they are both part of the same company.
I was planning on using a junction table with a ForeignKey to both of their company attributes,
but according to the django docs, a foreignkey can only be used once per model
(https://docs.djangoproject.com/en/1.10/topics/db/models/#extra-fields-on-many-to-many-relationships)
How do I make sure that the many to many relationship between the two tables is limited to the same company?
Is there perhaps another way to ensure that workers cannot work on projects outside of their own company?
Assuming you define the many to many relationship this way in the Project model:
workers = ManyToManyField(Worker)
Assuming you have a model form named ProjectForm to create or modify projects. You can define a clean function in this form:
def clean(self):
cleaned_data = super(ProjectForm, self).clean()
for w in cleaned_data['workers']:
if w.company.id != cleaned_data['company'].id:
self.add_error('workers', your_error_message)
break
return cleaned_data
Hope this help.
I am having some problem with djangorestframework's serializers.
Below is part of my code.
from django.db import models
from django.contrib.auth.models import User
class Image(models.Model):
id = models.AutoField(primary_key=True)
owner = models.ForeignKey(User)
album = models.ForeignKey(Album, null=True)
name = models.CharField(max_length=128, default='')
class Album(models.Model):
id = models.AutoField(primary_key=True)
owner = models.ForeignKey(User)
name = models.CharField(max_length=128, default='')
class ImageSerializer(serializers.ModelSerializer):
owner = serializers.Field(source='owner.id')
album = serializers.Field(source='album.id')
uploadDevice = serializers.Field(source='uploadDevice.id')
class Meta:
model = Image
fields = ('id', 'owner', 'album', 'name')
class AlbumSerializer(serializers.ModelSerializer):
owner = serializers.Field(source='owner.id')
class Meta:
model = Album
fields = ('id', 'owner', 'name')
So the thing is, I want to hide the integer id value of the models when they are serialized into json. For example, Image model instance with values
id = 12
owner = 425
album = 24
name = DSC2091.JPG
will turn into
{
id: '7VHXHIGMH4XWAKYMPSYYYENYA7NPZ7RGVY6GQJMG3BSIQXWZELNQ====',
owner: 'J2M5BVZB2RCJQNXPN33G2LTMFSAXWPFVFHFTNQSHP56QO3OHFCNA====',
album: 'HCMOMOEEA7YZEI5JJTTXN7LQHOEW3FCRQ7OB6ZMD7UEWISUG7PFA====',
name: 'DSC2091.JPG'
}
And same in the other way.
I've already made the encrypting, decrypting, and the hashing part.
Where and what should I do to make this id security conversion happen smoothly?
Checkout transform methods on serialization: transform_ http://www.django-rest-framework.org/api-guide/serializers/#serializing-objects
Also validate method does the reverse so you can do the encryption going each way.
Hi I need to add a field in a serializer of a 2 level reference item.
I have the following model:
model.py:
class Company(models.Model):
companyName = models.CharField(max_length=50, blank=True)
class Poll(models.Model):
questionString = models.CharField(max_length=500, blank=True)
companyId = models.ForeignKey(Company, null=True, db_column='companyId', blank=True)
class PossibleAnswer(models.Model):
answerString = models.CharField(max_length=100, blank=True)
pollId = models.ForeignKey(Poll, null=True, db_column='pollId', blank=True,related_name='answers')
token = models.CharField(max_length=10, blank=True)
serializers.py:
class PossibleAnswerSerializer(serializers.ModelSerializer):
#companyId = serializers.RelatedField()
class Meta:
model = PossibleAnswer
fields = ('answerString', 'token', 'pollId', 'companyId')
I want to make a Serializer for the PossibleAnswer object that has a field named company. How to make a this reference? Something similar to: pollId__companyId in a django query set filter.
Another solution...
class PossibleAnswerSerializer(serializers.ModelSerializer):
companyId = serializers.SerializerMethodField()
def get_companyId(self, obj):
return obj.pollId.companyId
class Meta:
model = PossibleAnswer
fields = ('answerString', 'token', 'pollId', 'companyId',)
I the field is read-only you can easily achieve this with a serializers.Field, which accept dotted paths to the source.
Your Serializer would be:
class PossibleAnswerSerializer(serializers.ModelSerializer):
companyId = serializers.Field(source='pollId.companyId')
class Meta:
model = PossibleAnswer
fields = ('answerString', 'token', 'pollId', 'companyId')
I too agree with Erik, that naming model attributes with Id is a bad idea even though the DB representation is only the ID.