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).
Related
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
I'm working on a catalogue application for storing product information in Django.
The challenge here is that there are a lot of products in the catalogue, each with their own attributes. Since this is a key part of the application, and a lot will be built around it, I want this to be designed as good as possible.
I know there are several options of handling this in Django, but I would like to know what others have experienced with these several options.
The first option: Single abstract class
I could just create a single abstract class, which contains all the base attributes, and let other classes derive from that one class.
class Product(models.Model):
name = models.CharField(max_length=100)
description = models.TextField(max_length=1000)
price = models.DecimalField()
class Meta:
abstract = True
class Phone(Product):
series = models.CharField(max_length=100)
This would be the most straightforward option, but this will include a lot of work in Django Forms and Views.
This will also create a single table for each Product subclass, so when the Product class is changed, all other tables will have to changed as well.
The second option: Product base class
Here the Product class is not abstract, which implies this class can be used as well.
class Product(models.Model):
name = models.CharField(max_length=100)
description = models.TextField(max_length=1000)
price = models.DecimalField()
class Phone(Product):
series = models.CharField(max_length=100)
This would also be pretty straightforward, but this would still imply a lot of work in the Forms and Views.
This would first create a table for the Product class, and then a single table for each Product subclass.
The first 2 options will also break the DRY principle, because attributes will have to be added to every Product subclass that might be common to some classes, but not to all.
Third option: Product class containing all the possible attributes.
class Product(models.Model):
name = models.CharField(max_length=100)
description = models.TextField(max_length=1000)
price = models.DecimalField()
# attributes for phones, tv's, etc...
series = models.CharField(max_length=100)
class PhoneForm(forms.ModelForm):
class Meta:
model = Product
fields = ['name', 'description', 'price', 'series']
A new form will have to be created for each product subclass. This does seem pretty easy, but the Product model will become very bloated.
In this case I could also use Proxy Models.
Fourth option: Create Abstract classes and use class Mixins
class ProductBase(models.Model):
name = models.CharField(max_length=100)
description = models.TextField(max_length=1000)
price = models.DecimalField()
class Meta:
abstract = True
class ElectronicsProduct(models.Model):
series = models.CharField(max_length=100)
class Meta:
abstract = True
class Phone(ProductBase, ElectronicsProduct):
pass
This method could solve the DRY problem I have with the issue I had above, but still not optimal.
Fifth option: One Product model with a separate attribute model
This is a method I would like to use anyway, but more to have the ability to add 'extra' features to a product that is too specific to put in a Product or Product subclass.
class Product(models.Model):
name = models.CharField(max_length=100)
description = models.TextField(max_length=1000)
price = models.DecimalField()
class Attribute(models.Model):
name = models.CharField(max_length=100)
class ProductAttribute(models.Model):
product = models.ForeignKey(Product)
attribute = models.ForeignKey(Attribute)
value = models.CharField(max_length=100)
The question here is if this method should be used for all product attributes, since I think this will add a lot of overhead on the database.
Another challenge here is the value type. In this case I can only use a character value, so what happens when I would like to use a Decimal value, or a File.
Sixth option: Something else
There are probably some methods I have not thought of at this point. So if you know something I don't please share it with me.
I am not looking for any opinions here, but for some solutions. So if you have an answer to this question please tell us why you would use the method you propose.
OK here goes, this is one of those questions that makes perfect sense in my head but is difficult to explain properly :) I have a django app where I want to store records for lots of different items of equipment. Each type of equipment will have a custom model to store its attributes, such as MyEquipment below. Each type of equipment will also have a 'category', which would be useful to store as an attribute.
class Category(models.Model):
code = models.CharField('Category', max_length=4, unique=True)
description = models.CharField('Description', max_length=30)
...
class MyEquipment(models.Model):
serial = models.IntegerField()
...
To save this attribute to my model I could use a foreign key to Category but I don't need to because every record in MyEquipment must be the same Category. So then I thought maybe I could hardcode the Category in the MyEquipment meta like this:
class MyEquipment(models.Model):
serial = models.IntegerField()
...
class Meta:
category = Category.objects.get(code='EC')
But then this would rely on the Category model being populated with data to build the MyEquipment model. To me this doesn't seem best practice, using data that may or may not exist to define the structure of another model. Is there a better way I should be using to set which Category the MyEquipment model is related to?
EDIT
Thanks for the discussion below, it's made me realise perhaps I wasn't clear on my original post. So what I want to do is have a way of linking MyEquipment to a Category. So I can do something like this:
>>> from myapp.models import MyEquipment
>>> MyEquipment.CATEGORY
<Category: EC>
I want to link the whole model to a Category, so I can process each model in different ways in my view depending on which category it is. Having thought about the problem a bit more, I can get this functionality by writing MyEquipment like this:
class MyEquipment(models.Model):
CATEGORY = Category.objects.get(code='EC')
serial = models.IntegerField()
...
This way works, but is it the best way? I guess the model would do this get operation everytime the class is instantiated? Is there a more efficient method?
You can't do this anyway; the Meta class doesn't support arbitrary attributes.
The best thing would be to define this as a property, which you can access via the instance itself. To make it more efficient, you could memoize it on the class.
#property
def category(self):
_category = getattr(self, '_category', None)
if not _category:
self.__class__._category = _category = Category.objects.get(code='EC')
return _category
but ... every record in MyEquipment must be the same Category
Then you don't need any relationship. As you said already, every record in MyEquipment are same Category, why do you want to store relation in db?
UPD: Solution with model inheritance
class Place(models.Model):
category = models.ForeignKey(Category)
class Meta:
abstract = True
def save(self, *args, **kwargs):
self.category = Category.objects.get(name=self.CATEGORY)
return super(Place, self).save(*args, **kwargs)
class Restaurant(Place):
...fields...
CATEGORY = 'RE'
class Building(Place):
...fields...
CATEGORY = 'BU'
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().
Can someone please explain why is meta class used in the following example.
Ex:
Class Employee (models.Model):
name = models.ForeignKey(name)
Gender = models.IntegerField()
class Meta:
ordering = ["Gender"]
Thanks.
Django models use the Meta class to contain extra information about the model that would not necessarily be appropriate to contain within the model class itself. Note that this is not the same as Python's metaclass; that is a completely different topic.
In this case it ordering or sorting the queries to this model by field "Gender"
Because author/programmer wants to sort results by value of Gender field.
In this case it defines the default field for ordering if you don't provide ORDER_BY in your query.
It is explained in Django Documentation for Models
https://docs.djangoproject.com/en/dev/topics/db/models/
Give your model metadata by using an inner class Meta, like:
Class Employee (models.Model):
....
class Meta:
ordering = ["attribute-X"]
Another useful option can be used in class Meta is verbose_name.