I have two models:
class ModelA(models.Model):
name = models.CharField(max_length=256)
class ModelB(models.Model):
user = models.ForeignKey(MyUser)
model_a = models.ForeignKey(ModelA)
points = models.IntegerField(default=0)
How can I prevent creating the same object? For example:
I have A, B, C instances of ModelA, and two users. In ModelB I need relationships like this:
User1 can has only one 'link' to A, one to B, etc.
User2 the same. He can only one 'link' to each ModelA instance.
Each User can has one record in ModelB associated with ModelA.
E.g. (User1, A, 100), (User2, A, 50)
But if I will try to do something like this
...create(user=User1, model_a=A, points=50)
I need to get from db records with user1, and A, and ad points, not creating another similiar model.
So you want all pairs of user and model_a to be unique. You can specify this in the metadata of the model using unique_together.
unique_together = (("driver", "restaurant"),)
This is a tuple of tuples that must be unique when
considered together. It’s used in the Django admin and is enforced at
the database level (i.e., the appropriate UNIQUE statements are
included in the CREATE TABLE statement).
Django documentation - unique_together
Therefore modify your model in following way:
class ModelB(models.Model):
user = models.ForeignKey(MyUser)
model_a = models.ForeignKey(ModelA)
points = models.IntegerField(default=0)
class Meta:
unique_together = (('user', 'model_a'),)
Related
I have three models in a django DRF project:
class ModelA(models.Model):
name = ....
other fields...
class ModelB(models.Model):
name = ....
other fields...
class ModelC(models.Model):
name = ....
model_a = FKField(ModelA)
model_b = FKField(ModelB)
I was using the default ModelViewSet serializers for each model.
On my react frontend, I'm displaying a table containing 100 objects of ModelC. The request took 300ms. The problem is that instead of displaying just the pk id of modelA and ModelB in my table, I want to display their names. I've tried the following ways to get that data when I use the list() method of the viewset (retreive all modelc objects), but it significantly increases call times:
Serializing the fields in ModelCSerializer
class ModelCSerializer(serializers.ModelSerializer):
model_a = ModelASerializer(read_only=True)
model_b = ModelBSerializer(read_only=True)
class Meta:
model = ModelC
fields = '__all__'
Creating a new serializer to only return the name of the FK object
class ModelCSerializer(serializers.ModelSerializer):
model_a = ModelANameSerializer(read_only=True) (serializer only returns id and name)
model_b = ModelBNameSerializer(read_only=True) (serializer only returns id and name)
class Meta:
model = ModelC
fields = '__all__'
StringRelatedField
class ModelCSerializer(serializers.ModelSerializer):
model_a = serializer.StringRelatedField()
model_b = serializer.StringRelatedField()
class Meta:
model = ModelC
fields = '__all__'
Every way returns the data I need (except number 3 takes more work to get the FKobject's id) but now my table request takes 5.5 seconds. Is there a way to do this without significantly increasing call times? I guess this is due to the DB looking up 3 objects for every object I retrieve.
Also I wouldn't be able to make the primary_key of ModelA & ModelB the name field because they aren't unique.
Thanks
EDIT Answer for my example thanks to bdbd below:
class ModelCViewSet(viewsets.ModelViewSet):
queryset = ModelC.objects.select_related('model_a', 'model_b').all()
# ...
You can use select_related for this to optimise your queries and make sure that every object in your ModelC does not do extra DB hits
I am trying to create a Django application where each User has one model attached to them ( a list of Plants ) and that model is composed of individual plants. I already know I can have the plants connected to the plant list through a many-to-one relationship using foreign key as shown down below:
class PlantList(models.Model):
plant_list_id = models.AutoField(primary_key=True)
class Plant(models.Model):
plantlist = models.ForeignKey(PlantList, on_delete = models.CASCADE)
name = models.CharField(max_length = 20)
wateringInterval = models.PositiveSmallIntegerField()
However, I want each user to have a plant list attached to them that can be displayed uniquely for each user, according to the plants that they add to their list. How would I make it so that each user has a plant list?
I was trying to have it inside the register form but couldn't figure out how to do it and I wanted each plantlist to have a unique ID so that I can add plants to it easier.
class AddNewPlant(forms.Form):
name = forms.CharField(label='Name',max_length = 20)
wateringInterval = forms.IntegerField(label='Watering Interval')
The thing is, you don't need the model PlantList.
What you should do instead is: set a ForeignKey to the User Model inside the Plant Model, and in that foreign_key set a related_name='plants'.
To access the User Model use:
from django.contrib.auth import get_user_model
code example:
class Plant(models.Model):
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE, related_name='plants')
name = models.CharField(max_length = 20)
wateringInterval = models.PositiveSmallIntegerField()
Then you can access all user's plants using:
first_user = get_user_model().objects.first().plants
Try this:
class User(models.Model):
plant_list = models.ForeignKey(PlantList, on_delete=models.CASCADE)
this is for connecting plant_list with the user. Also, you need to change the relationship between plant and plant_list, so that users can have the same plants as well like below:
class Plant(models.Model):
plantlist = models.ManyToManyField(PlantList)
that way different users can have the same plants on their plant_list and every user has only one plant_list.
models.py :
class Employee(models.Model):
name = models.CharField(max_length=100)
class Department(models.Model):
name = models.CharField(max_length=100)
employee = models.ManyToManyField(Employee, null=True, blank=True)
I need to save employee ids (instead of employee object) in 'employee' ManyToManyField of 'Department' model. How to do that?
views.py:
dept = Department(name=name)
dept.save()
employee_ids = [1,2]
We can use method add (Django Docs):
Adds the specified model objects to the related object set.
dept = Department.objects.create(name=name)
dept.employee.add(*[1, 2])
Or method set(Django Docs):
Replace the set of related objects
dept.employee.set([1, 2])
Note that add(), create(), remove(), clear(), and set() all
apply database changes immediately for all types of related fields. In
other words, there is no need to call save() on either end of the
relationship.
I think this question is unclear what exactly are you trying to do ?
If you want to create a relation between department and employee on the database level django does that for you
on your current structure the relation and is like
id|department_id|user_id
--|-------------|-------
1| 3 | 2
New to Django and relational DBs. I'm building the classic Doctor appointment booking app and have come to a point where I don't know what to do. I've created the Doctor model pointing to a Clinic, but in my API the Clinic model won't show a list of all Doctors. How could I achieve this?
class Clinic(models.Model):
name = models.CharField(max_length=200)
class Doctor(models.Model):
clinic = models.ManyToManyField(Clinic, related_name="doctors")
class ClinicSerializer(serializers.ModelSerializer):
class Meta:
model = Clinic
fields = '__all__'
class DoctorSerializer(serializers.ModelSerializer):
class Meta:
model = Doctor
fields = '__all__'
class ClinicViewset(viewsets.ModelViewSet):
queryset = Clinic.objects.all()
serializer_class = ClinicSerializer
class DoctorViewset(viewsets.ModelViewSet):
queryset = Doctor.objects.all()
serializer_class = DoctorSerializer
Django will automatically create the link from Clinic to Doctor. You don't need to (shouldn't) define it. From the docs:
Django also creates API accessors for the “other” side of the relationship – the link from the related model to the model that defines the relationship. For example, a Blog object b has access to a list of all related Entry objects via the entry_set attribute: b.entry_set.all().
The related_name argument that you passed to ManyToManyField when you created the clinic field is the name of the relation from Clinic to Doctor. It is optional and if you didn't pass it, it would be the lower-cased named of the model + _set - doctor_set in your case.
Usually you would set it to a plural in the case of ManyToManyField. In your case: doctors.
Because you have related_name="doctor" currently, you can retrieve a clinic's doctors with: clinic.doctor.all().
I have a model suppose
class A(models.Model):
name = models.CharField(max_length=256)
class B(models.Model):
city = models.CharField(max_length=256)
users = models.ManyToManyField(A)
Now can I say if I have to save these models I can use
users = A.objects.all()
and suppose I have a data for to store as
b = B(city="XYZ", user=users).save()
that is can I use directly the complete query set to store the manytomany field data.
You can't pass a many-to-many field when you instantiate a model, in any case.
After the model is saved, though, you can do:
b.users.add(*users)