Setting default value of field in model to another model instance - django

Model
class SlackPermission(models.Model):
#fields
class GithubPermission(models.Model):
#fields
class Employee(models.Model):
#fields
slack_permission = models.OneToOneField(SlackPermission, on_delete=models.CASCADE, related_name='Slack',default=SlackPermission.objects.get(pk=1))
github_permission = models.OneToOneField(GithubPermission, on_delete=models.CASCADE, related_name='Github',default=GithubPermission.objects.get(pk=1))
Error:
ValueError: Cannot serialize: <GithubPermission: GithubPermission object (1)>
There are some values Django cannot serialize into migration files.
I am creating API just to create Employee. Where there is not option of giving slackpermissions and githubpermissions. How do I give default value in there?

The problem is that the default is calculated immediately, and for migrations, it can not really serialize that.
That bing said, it is not very useful to do this anyway. You can just pass the primary key as default value. This is specified in the documentation on the default=… parameter [Django-doc]:
For fields like ForeignKey that map to model instances, defaults should be the value of the field they reference (pk unless to_field is set) instead of model instances.
So we can write this as:
class Employee(models.Model):
full_name = models.CharField(max_length=100)
first_name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
slack_permission = models.OneToOneField(
SlackPermission,
on_delete=models.CASCADE,
related_name='Slack',
default=1
)
github_permission = models.OneToOneField(
GithubPermission,
on_delete=models.CASCADE,
related_name='Github',
default=1
)
Note that you should ensure that there exists an object with that primary key. Therefore it might not be ideal to do that.

The issue here is that you are attempting to set a field value to an object instance. So your default value should be just 1 if you are certain of the pk.
Also, I am not sure the advantage of creating two separate models for these permission values. Seems like they can just be fields in your employee model. Seems like these permissions share identical fields as well which will allow you to flatten them a bit.

Related

How i can create a muti value filed without manytomany field in django?

I have a model:
class People(models.Model):
family = models.CharField(null=True)
phone_numbers = ?
How i can implement phone_numbers for some phone numbers. I think ManyToManyField is not a good idea for doing this.
What is best practice for this?
admin.py
class PhonesInline(admin.TabularInline):
model = models.Phones
class PeopleAdmin(admin.ModelAdmin):
inlines = [
PhonesInline,
]
admin.site.register(models.People, PeopleAdmin)
What you can do is create a Phone model and create a Many-to-one relationship between Phone and People using ForeignKey. With this you can associate various phone numbers to a single person.
class People(models.Model):
family = models.CharField(null=True)
class Phone(models.Model):
number = models.CharField(max_length=15, unique=True)
person = models.ForeignKey(People, on_delete=models.CASCADE)
Now, for example, if you have a People instance in a variable called people, you can access its related phone numbers with values_list:
people.phone_set.values_list('number', flat=True)
As a note for your model, it's not recommended to use null=True to a CharField/TextField. The official Django documentation states the following:
Avoid using null on string-based fields such as CharField and TextField. If a string-based field has null=True, that means it has two possible values for “no data”: NULL, and the empty string. In most cases, it’s redundant to have two possible values for “no data;” the Django convention is to use the empty string, not NULL. One exception is when a CharField has both unique=True and blank=True set. In this situation, null=True is required to avoid unique constraint violations when saving multiple objects with blank values.
You can also take a look at this question, which tackles my last point.
Also I don't know which logic you want to apply to your project, but I think a better way to organize your models and their relationships is to create a Family class to deal with families like:
class Family(models.Model):
name = models.CharField(max_length=100)
class People(models.Model):
family = models.ForeignKey(Family, blank=True, null=True)
class Phone(models.Model):
number = models.CharField(max_length=15, unique=True)
person = models.ForeignKey(People, on_delete=models.CASCADE)
With this extra model you will be able to create another Many-to-one relationship between People and Family. Depending on your needs, you should adapt the arguments when creating the fields, the ones I provided are just an example.

How to make a model parameter unique by a other parameter in Django?

I want my id field to be unique per each customer field. Just like the option unique_for_date from Django (https://docs.djangoproject.com/en/1.11/ref/models/fields/#unique) but in this case, not date but customer.
class Sample(NGObject):
id = models.CharField(max_length=128, null=True, blank=False)
customer = models.ForeignKey(Customer, related_name="blood_samples", on_delete=models.SET(get_default_customer))
I believe this should be done, before the save() method?
When a User writes the wrong ID (that already exists) I would also like to present the information in the Admin Form just like it would for normal unique error.
class Meta:
unique_together = ('sample_id', 'customer',)
This has done the trick :)

Django: How to create a queryset from a model relationship?

I have been struggling with grasping relations for some time and would be very grateful if someone can help me out on this issue.
I have a relation that connects the User model to a ProcessInfo model via one to many and then I have a relation that connects the ProcessInfo to the ProcessAssumptions as One to one
Is there a way to use the User id to get all ProcessAssumptions related to all processes from that user.
I would like to retrieve a queryset of all ProcessAssumptions related to a user id
Here is the model relation :
class ProcessInfo(models.Model):
process_name = models.CharField(max_length=120, null=True)
user_rel = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
class ProcessAssumptions(models.Model):
completion_time = models.FloatField(default='0')
process_rel_process = models.OneToOneField(ProcessInfo, primary_key = True, on_delete=models.CASCADE)
Using field referencing for foreign keys.
process_assumption_objects = ProcessAssumptions.objects.filter(process_rel_process__user_rel=<user_id>)
Replace <user_id> with the id you wish to query for.
When you define a relationship to model X in another model Y, all related Ys can be accessed from an instance of X by X_instance.Y_set.all(). You can even perform the regular filter or get operations on that. X_instance.Y_set is the default object manager for Y (same as Y.objects), but it's filtered to only contain the objects that are related to X_instance.
So in this specific case, you can get all ProcessInfo objects for a certain user like this:
user = User.objects.get(the_user_id)
required_assumptions = [proc_info.process_assumptions for proc_info in user.process_info_set.all()]
This might be a bit hard to read with _set suffix, so you can define a related_name argument while defining the relation on the model.
like:
# in class ProcessInfo
user_rel = models.ForeignKey(User, null=True, on_delete=models.SET_NULL, related_name='processes')
# and now you can do
some_user.processes.all()

Best way to handle one ForeignKey field that can be sourced from multiple Database Tables

I am running into a little bit of unique problem and wanted to see which solution fit best practice or if I was missing anything in my design.
I have a model - it has a field on it that represents a metric. That metric is a foreign key to an object which can come from several database tables.
Idea one:
Multiple ForeignKey fields. I'll have the benefits of the cascade options, direct access to the foreign key model instance from MyModel, (although that's an easy property to add), and the related lookups. Pitfalls include needing to check an arbitrary number of fields on the model for a FK. Another is logic to make sure that only one FK field has a value at a given time (easy to check presave) although .update poses a problem. Then theres added space in the database from all of the columns, although that is less concerning.
class MyModel(models.Model):
source_one = models.ForeignKey(
SourceOne,
null=True,
blank=True,
on_delete=models.SET_NULL,
db_index=True
)
source_two = models.ForeignKey(
SourceTwo,
null=True,
blank=True,
on_delete=models.SET_NULL,
db_index=True
)
source_three = models.ForeignKey(
SourceThree,
null=True,
blank=True,
on_delete=models.SET_NULL,
db_index=True
)
Idea two:
Store a source_id and source on the model. Biggest concern I have with this is needing to maintain logic to set these fields to null if the source is deleted. It otherwise seems like a cleaner solution, but not sure if the overhead to make sure the data is accurate is worth it. I can probably write some logic in a delete hook on the fk models to clean MyModel up if necessary.
class MyModel(models.Model):
ONE = 1
TWO = 2
THREE = 3
SOURCES = (
(ONE, "SourceOne"),
(TWO, "SourceTwo"),
(THREE, "SourceThree")
)
source_id = models.PositiveIntegerField(null=True, blank=True)
source = models.PositiveIntegerField(null=True, blank=True, choices=SOURCES)
I would love the communities opinion.
Your second idea seems fragile as the integrity is not ensured by the database as you have pointed out yourself.
Without knowing more about the use case, it's difficult to provide an enlightened advice however if your "metric" object is refered by many other tables, I wonder if you should consider approaching this the other way round, i.e. defining the relationships from the models consuming this metric.
To exemplify, let's say that your project is a photo gallery and that your model represents a tag. Tags could be associated to photos, photo albums or users (e.g.. the tags they want to follow).
The approach would be as follow:
class Tag(models.Model):
pass
class Photo(models.Model):
tags = models.ManyToManyField(Tag)
class Album(models.Model):
tags = models.ManyToManyField(Tag)
class User(AbstractUser):
followed_tags = models.ManyToManyField(Tag)
You may even consider to factor in this relationship in an abstract model as outlined below:
class Tag(models.Model):
pass
class TaggedModel(models.Model):
tags = models.ManyToManyField(Tag)
class Meta:
abstract = True
class Photo(TaggedModel):
pass
As mentioned in the comments, you are looking for a Generic Relation:
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
class SourceA(models.Model):
name = models.CharField(max_length=45)
class SourceB(models.Model):
name = models.CharField(max_length=45)
class MyModel(models.Model):
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
source = GenericForeignKey('content_type', 'object_id')
There are three parts to setting up a Generic Relation:
Give your model a ForeignKey to ContentType. The usual name for this field is “content_type”.
Give your model a field that can store primary key values from the models you’ll be relating to. For most models, this means a PositiveIntegerField. The usual name for this field is “object_id”.
Give your model a GenericForeignKey, and pass it the names of the two fields described above. If these fields are named “content_type” and “object_id”, you can omit this – those are the default field names GenericForeignKey will look for.
Now you can pass any Source instance to the source field of MyModel, regardless of which model it belongs to:
source_a = SourceA.objects.first()
source_b = SourceB.objects.first()
MyModel.objects.create(source=source_a)
MyModel.objects.create(source=source_b)

One-to-one and Many-to-one relationships with the same pair of models

I have a Profile model and Photo model. Each profile has photos (One-to-many relationship) and a profile photo (One-to-one relationship). When I try to do this on django I get the error NameError: name 'Photo' is not defined
because I'm referencing the model before it's defined.
class Profile(models.Model):
name = models.CharField(max_length=50, primary_key=True, blank=False)
profile_photo = models.OneToOneField(
Photo,
null=True,
on_delete=models.SET_NULL
)
class Photo(models.Model):
profile = models.ForeignKey(Profile, on_delete=models.CASCADE)
photo = models.ImageField(primary_key=True, upload_to='photos/')
A possible solution could be using a boolean field on Photo to specify if it's a profile photo or not, but I think that's inefficient because I'd have to query all photos of the profile and make a loop to find the profile photo. Are there a better solution for that?
The problem is not the fact that you create two relations. Although it can cause some trouble (and therefore you better for example define related_names, etc.), the issue is that you refer to a class before it is constructed.
Indeed, Python reads files from top to bottom. In your file you define a class Profile with a reference to Photo, but at that point, there is no variable named Photo yet (whether that is a class or not is irrelevant, at least for Python).
You can solve this by using a string literal instead, Django will later, when all models are loaded, do the linking itself. So you can write:
class Profile(models.Model):
name = models.CharField(max_length=50, primary_key=True, blank=False)
profile_photo = models.OneToOneField(
'Photo',
null=True,
on_delete=models.SET_NULL
)
That being said, it is not entirely clear to me why you define two relations: Django automatically adds a reverse relation, so without specifying profile = ... in the Photo class, Django will automatically have added such profile relation. This will then work by using a JOIN (and querying the database in "reverse"). Unless the two relations are two different ways to combine the two models, it is better to use one relation, since this will avoid data duplication.