Django: constrain foreign key to only rows with the same id - python

For a Django project, I got two models:
class User(AbstractUser):
child = models.ForeignKey('children.Child', null=True, on_delete=models.SET_NULL)
And the following:
class Child(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
What I want is that User.child can only be set to an entity that has child.user_id = user.id, with a constraint preferably. Is this possible? If it matters, I am using PostgreSQL

Aren't you looking for a one-to-one relationship?
user in Child can only be set to one User.
child in User can also only be set to one Child.
You want user in Child and child in User to point to each other.
This is exactly what a one-to-one relationship is. The following code is even simpler than your current one and it enforces the constraint at the database level:
class User(AbstractUser):
# The relationship only needs to be defined in one of the models
pass
class Child(models.Model):
user = models.OneToOneField(User, null=True, on_delete=models.CASCADE)
If there are finer points you need to cover (eg. if there are situations in which you would need the relationship to be defined in one direction but not in the other), then please clarify the use case.

Related

Django: Same model with different features?

Object Model:
class Object(models.Model):
author = models.ForeignKey(ProfileUser, on_delete=models.CASCADE)
title = models.CharField(max_length=300)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
address = models.CharField(max_length=300)
content = models.TextField()
created_date = models.DateTimeField(default=timezone.now)
approved_object = models.BooleanField(default=False)
admin_seen = models.BooleanField(default=False)
def __str__(self):
return f"{self.title}"
Category model:
class Category(models.Model):
title = models.CharField(max_length=50)
def __str__(self):
return f"{self.title}"
For example I have some categories, like hotels, restaurants etc. So I want for each category to have different features (radio buttons when adding new), but I'm not sure, how to handle it properly. Hotels must have rooms, pool etc. Restaurants must have country kitchen, seats etc. In future I will have and other categories.
Quesion is: Which is the best way (practice) to do this.
My solution: To create third table with features and every category to have column features and store features separate by comma, but it's not very good solution based on DB normalization.
You could use abstract base classes:
Abstract base classes are useful when you want to put some common information into a number of other models. You write your base class and put abstract=True in the Meta class. This model will then not be used to create any database table. Instead, when it is used as a base class for other models, its fields will be added to those of the child class.
You can then make your Restaurant and Hotel models inherit from this abstract class. Django will then create two tables with the base fields from the abstract class plus the specific fields from each models.
You can use multi-table inheritance
You define a base object, and from there you can define different child objects which will share the parent's properties
In your case that would look something like this:
class Object(models.Model):
...
class Restaurant(Object):
seats = IntegerField(...)
reservations = ManyToManyField(...)
class Hotel(Object):
rooms = IntegerField(...)
has_pool = BooleanField(...)
Django will automatically create relationships and manage the querying for you. To get all restaurants, you can use Restaurant.objects.all(), there is a limitation though. When querying Object.objects.all(), you will get a list of the Objects, not their specific subclass. If I remember correctly, you can access the specific instance through (for instance) object.restaurant.
If you do want to get the specific objects, you can look into a library called Django-polymorphic.
i will explain this one by one :
category table contains all categories.
now there may have some common and unique feature for every category.features will have many to many relation with category table.
so we create feature_master table and we will map it with category table.
feature_master table contains all features.
category_feature_map table is map table(junction table)
object table have all the detail about object and object_detail table will contain all the feature to particular object

django multitable inheritance in django modeladmin

I have to models
class Parent(object):
text_field = models.TextField()
boolean_field = models.BooleanField()
class Child(Parent):
another_text_field = models.TextField()
With the following ModelAdmin
class ChildAdmin(admin.ModelAdmin):
pass
admin.site.register(Child, ChildAdmin)
I currently see all fields in the admin page, i.e. text_field, boolean_field, and another_text_field.
Question: How can I get a parent select field and exclude text_field and boolean_field (for latter I guess I can use exclude).
Current Solution: I add a Form and use its clean method to set the parent field. text_field and boolean_field can be excluded by addind it to the ModelAdmin's excluded variable.
simply overwrite fields
class Child(Parent):
another_text_field = models.TextField()
text_field = None
boolean_field = None
if you want to use inheritance in django models use abstract models please.
I am not sure if it is really necessary to use model inheritance. if not, you may consider using OneToOneField without model inheritance.
Example using OneToOneField:
models.py
class Parent(models.Model):
text_field = models.TextField()
boolean_field = models.BooleanField()
class Child(models.Model):
parent = models.OneToOneField(Parent,
on_delete=models.CASCADE,
primary_key=True)
child_field = models.TextField()
admin.py
#admin.register(Parent)
class ParentAdmin(admin.ModelAdmin):
pass
doing so you can see a drop down menu for picking Parent instance at child admin page. but meanwhile, you lose one 'benefit' of using inheritance, which is the availability of Parent field in Child
as mentioned in the docs,
All of the fields of Place will also be available in Restaurant,
although the data will reside in a different database table.
but there is a easy fix for that, just use something like Child.objects.filter(parent__text_field="something"). Query performance should be the same (I guess) since implementation in db are basically the same for these two approaches (both use separated table) (please correct if I am wrong)
Apart from from this and admin display behavior, I am not sure how these two approaches (your approach and this answer) are differed.

Django models: Inherit from variable abstract base class

I'm hoping to inherit to a child class from a variable abstract base class. So a child class would not have to inherit from a pre-defined base class and would instead be able to inherit from any one class of multiple base classes. Ideally, the models would be setup like so:
class Orders(models.Model):
order_number = models.IntegerField()
# Orders metrics
class Meta:
abstract = True
class Fees(models.Model):
fee_number = models.IntegerField()
# Fee metrics
class Meta:
abstract = True
class Transactions(Inherit from either Orders or Fees):
transaction_number = models.IntegerField()
# Transaction metrics
Transactions would be able to inherit from either orders or fees as they could both be a source of a transaction.
Generic foreign keys could be implemented to allow for variable foreign key reference within the Orders model and Fees model but I am curious if there is a way to do this without using generic foreign keys. Is there a specific arrangement, mixin, decorator, property, or method that will allow for association of a child class with a variable abstract parent class?
This is not possible. But what you want can be easily achieved by creating ForeignKey realtionships from Transaction to both Fees and Order.
No you can't do this. Django models can't be modified like this during runtime (after django is intialized). Anyway, this is not a good design pattern. You're confusing composition and inheritance. A Transaction is not a type of Fee or a type of Order so it makes no sense to subclass like this.
You can solve your problem without a generic foreign key by just using two separate ForeignKey fields:
class Transactions(models.Model):
transaction_number = models.IntegerField()
order = models.ForeignKey(Orders, null=True, blank=True)
fee = models.ForeignKey(Fees, null=True, blank=True)
You can then query the different transaction types like this:
fee_payments = Transactions.objects.exclude(fee=None)
order_payments = Transaction.objects.exclude(order=None)

Django Generic Foreign Key Sorting

So I have a model that has a generic foreign key relationship with with three other models
class Status(BaseRequestStatus):
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
class Request(models.Model):
name = models.CharField(max_length=50, db_index=True)
...some fields
statuses = GenericRelation(Status, related_query_name='request')
class AnotherRequest(models.Model):
name = models.CharField(max_length=50, db_index=True)
...some fields
statuses = GenericRelation(Status, related_query_name='another_request')
class ThirdRequest(models.Model):
name = models.CharField(max_length=50, db_index=True)
...some fields
statuses = GenericRelation(Status, related_query_name='third_request')
So currently I am displaying the statuses with the name in a table. I want to be able to sort by the name. Currently I am sorting it like this.
Status.objects.all().order_by('request__name', 'another_request__name', 'third_request__name')
however with this method all of the 'request' is sorted in a chunk, then 'another_request', then 'third_request'
is there anyway to sort all of these together? I was able to do it by converting it to a list.. but in this case I need to use a Queryset.
Thanks in advance for any help.
If you want them treated the same way (deducing this from the fact that you want them sorted by their common name field) then this indicates that these models have the same base.
Use model inheritance in that case with a base model that is abstract and defines the name field and the generic fkey relation.
class RequestBase(models.Model):
name = models.CharField(max_length=50, db_index=True)
statuses = GenericRelation(Status, related_query_name='request')
class Meta:
abstract = True
class Request(RequestBase):
# ... more fields
Status.objects.all().order_by('request__name')
A more general explanation: to be able to sort objects by one attribute, you have to make clear that they all share that same attribute. Either by fetching the values in your own routines and creating lists that are sortable (this would be the qs approach you mentioned) or by creating a common interface - which is this Model inheritance approach.
As long as you are not using table inheritance, though, you will not be able to use the database for sorting (meaning: you cannot use the Django ORM for sorting).
There are certainly other approaches, including those that are outside of Django models: for example generating an additional lookup structure like a search index which will contain your transformed data as required (e.g. a haystack index).

Django What is reverse relationship?

Can someone tell me what is reverse relationship means?
I have started using Django and in lot of places in the documentation I see 'reverse relationship, being mentioned. What is it exactly mean? why is it useful? What does it got to do with related_name in reference to this post ?
Here is the documentation on related_name
Lets say you have 2 models
class Group(models.Model):
#some attributes
class Profile(models.Model):
group = models.ForeignKey(Group)
#more attributes
Now, from a profile object, you can do profile.group. But if you want the profile objects given the group object, How would you do that? Thats' where related name or the reverse relationship comes in.
Django, by defaults gives you a default related_name which is the ModelName (in lowercase) followed by _set - In this case, It would be profile_set, so group.profile_set.
However, you can override it by specifying a related_name in the ForeignKey field.
class Profile(models.Model):
group = models.ForeignKey(Group, related_name='profiles')
#more attributes
Now, you can access the foreign key as follows:
group.profiles.all()
For a clearer picture you can assume that when we use reverse relationship, it adds an extra field in the referenced model:
For example:
class Employee(models.Model):
name = models.CharField()
email = models.EmailField()
class Salary(models.Model):
amount = models.IntegerField()
employee = models.ForeignKey(Employee, on_delete=models.CASCADE, related_name='salary')
After using related_name in Salary model, now you can assume the Employee model will have one more field: salary.
For example, the available fields would now be:
name, email, and salary
To find an employee, we can simply query in this way:
e = Employee.objects.filter(some filter).first()
To check their salary, we can check it by writing
e.salary (now we can use salary an attribute or field in employee model). This will give you the salary instance of that employee, and you can find the amount by writing e.salary.amount. This will give you the salary of that employee.
In case of many to many relationship we can use .all() and then iterate over that.
In Django 2.0 you would define a ForeignKey as follows
mainclient = models.ForeignKey( MainClient, on_delete=model.CASCADE, related_name='+')
the related_name='+' would cancel the default reverse relationship that Django sets up, so in the previous example, you would not be able to query the profiles using group.profiles.all().

Categories