I'm trying to define a many-to-one field in the class that is the "Many". For example, imagine a situation where a user can only be a member of one group but a group can have many users:
class User(models.Model):
name = models.CharField()
class Group(models.Model):
name = models.CharField()
# This is what I want to do -> users = models.ManyToOneField(User)
Django docs will tell to define a group field in the User model as a ForeignKey, but I need to define the relationship in the Group model. As far as I know, there isn't a ManyToOneField and I would rather not have to use a ManyToManyField.
A ManyToOne field, as you've guessed, is called ForeignKey in Django. You will have to define it on your User class for the logic to work properly, but Django will make a reverse property available on the Groups model automatically:
class Group(models.Model):
name = models.CharField(max_length=64)
class User(models.Model):
name = models.CharField(max_length=64)
group = models.ForeignKey(Group)
g = Group.objects.get(id=1)
print g.user_set.all() # prints list of all users in the group
Remember that Django's models sit on top of a relational database... there's no way to define a single FK field in a table that points to more than one foreign key (without a M2M, that is), so putting the ManyToOne relationship on the Groups object doesn't map to the underlying data store. If you were writing raw SQL, you'd model this relationship with a foreign key from the user table to the group table in any event, if it helps to think of it that way. The syntax and logic of using a ManyToOne property that is defined on a Group instance, if such a concept existed, would be much less straightforward than the ForeignKey defined on User.
Assuming that the Users construct is the built-in authentication system... I would recommend creating a Profile model of some sort and attaching the OneToMany field to it instead. You can then hook the Profile model to the user model.
You should probably be looking at simply using built in reverse lookups:
group = Group.objects.get(id=1)
users_in_group = group.user_set.all()
Reverse lookup sets are automatically created for any foreign keys or many-to-many relationships to the model in question.
If you want to refer to this with a friendlier name, or provide additional filtering before returning, you can always wrap the call in a method:
class Group(models.Model):
name = models.CharField(max_length=64)
def users(self):
return self.user_set.all()
Either can be called from the templates:
{{ group.user_set.all }}
{{ group.users }}
Related
I'm implementing a Django Form witch should contain the field 'fieldA' from modelA:
class ModelA(models.Model):
fieldA = models.CharField(max_length=8)
...
My question is: Is there a way to have Django form, which will automatically handle validation of fieldA (check the max_length)? I know I Could use form.ModelFormclass referring to ModelA, but then the form would reflect all the fields of the ModelA. I would like to use simple forms.Form.
I'm looking for a solution like:
class formX(forms.Form):
fieldA = forms.CharField(**modelA.fieldA.constraints)
fieldB = ... some other fields not related to ModelA ...
.... even more fields
Maybe this question is an XY problem, but let me try...
Direct question: get field constraints from existing model
from django import forms
from django.db import models
class Foo(models.Model):
x = models.CharField(max_length=30)
y = models.IntegerField(null=True)
class FooForm(forms.Form):
foo_x = forms.CharField(max_length=Foo._meta.get_field('x').max_length)
You can access the field directly in two ways:
ModelClass.field_name.field (kind of hack, ModelClass.field_name is a django.db.models.query_utils.DeferredAttribute)
ModelClass._meta.get_field('field_name') (better way, described somewhere in docs)
However, this way you have to a) update form if field constraints are added or b) specify all attributes in advance (max_length, min_length, verbose_name, blank, etc.), making declaration of FooForm.foo_x too verbose.
Alternatives
Fields subset
First of all, if you need a subset of Foo fields, use ModelForm and specify them:
class FooForm(forms.ModelForm):
class Meta:
fields = ('x',)
Now you have a form with only x field.
Add some fields
If you want to add fields to this form (that are not related to other model), do it:
class FooForm(forms.ModelForm):
another_field = forms.IntegerField()
class Meta:
fields = ('x',)
def clean_another_field(self):
data = self.cleaned_data['another_field']
if data != 42:
raise ValidationError('Not an answer!') # i18n should be here
return data
Also you can override clean and save methods for another goals, documentation explains that nicely.
Mix fields from different models
If you need fields of two different models to be present in one form, you don't. You need two separate forms in this case, plus some inter-validation logic outside of this forms maybe (as a view method, for example, or as another class that is not a form). Maybe what you need is inline formset, it doesn't represent two mixed forms, but at least has some inter-model communication.
I found a way how to achieve a validation of form Field reflecting constrains from model Field.
class Foo(models.Model):
x = models.CharField(max_length=30)
y = models.IntegerField(null=True)
class FooForm(forms.Form):
foo_x = forms.CharField(validators=Foo._meta.get_field('x').validators)
Like this, the form will respect the max_length validator of attribute x or any other validator defined.
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 have a Django model that already exists that I'd like to duplicate, and I can't figure out an easy way how because of related-name conflicts across ForeignKeys and ManyToManys.
As an example, let's call the model I currently have Dog:
class Dog(models.Model):
name = models.CharField()
owner = models.ForeignKey('myapp.Owner')
breeds = models.ManyToMany('myapp.Breed', help_text="Remember, animals can be mixed of multiple breeds.")
I'd like to make an exact duplicate of this model for use elsewhere, with a different database table and name. I tried using an abstract base class:
class AnimalAbstract(models.Model):
name = models.CharField()
owner = models.ForeignKey('myapp.Owner')
breeds = models.ManyToMany('myapp.Breed', help_text="Remember, animals can be mixed of multiple breeds.")
class Meta:
abstract = True
class Dog(AnimalAbstract):
pass
class Cat(AnimalAbstract):
pass
This fails because of related_name conflicts.
Is there any way to automatically copy a model like this without explicitly redefining every ForeignKey and ManyToMany?
To preemptively answer questions: yes, I know about multi-table inheritance, and I don't want to use it. I also know that I could simply store this all in the same table and use proxy models with custom managers to automatically filter out the wrong type of animal, but I don't want that either—I want them on separate database tables.
https://docs.djangoproject.com/en/1.8/topics/db/models/#abstract-related-name
To work around this problem, when you are using related_name in an abstract base class (only), part of the name should contain %(app_label)s and %(class)s.
%(class)s is replaced by the lower-cased name of the child class that the field is used in.
%(app_label)s is replaced by the lower-cased name of the app the child class is contained within. Each installed application name must be unique and the model class names within each app must also be unique, therefore the resulting name will end up being different.
Ex:
class Dog(models.Model):
name = models.CharField()
owner = models.ForeignKey(
'myapp.Owner',
related_name="%(app_label)s_%(class)s_dogs")
breeds = models.ManyToMany(
'myapp.Breed',
help_text="Remember, animals can be mixed of multiple breeds.",
related_name="%(app_label)s_%(class)s_dogs")
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().
Is there explicit support for Single Table Inheritance in Django? Last I heard, the feature was still under development and debate.
Are there libraries/hacks I can use in the meantime to capture the basic behavior? I have a hierarchy that mixes different objects. The canonical example of a corporation structure with an Employee class, subclasses for types of employees, and a manager_id (parent_id) would be a good approximation of the problem I am solving.
In my case, I would like to represent the idea that an employee can manage other employees while being managed by a different employee. There are not separate classes for Manager and Worker, which makes this hard to spread across tables. Sub-classes would represent types of employees-programmers, accountants, sales, etc and would be independent of who supervises who (OK, I guess it's no longer a typical corporation in some respect).
Summary
Django's proxy models provide the basis for Single Table Inheritance.
However, some effort is required to make it work.
Skip to the end for a re-usable example.
Background
Martin Fowler describes Single Table Inheritance (STI) as follows:
Single Table Inheritance maps all fields of all classes of an inheritance structure into a single table.
This is precisely what Django's proxy model inheritance does.
Note, that, according to this blog post from 2010, proxy models have been around since Django 1.1.
A "normal" Django model is a concrete model, i.e. it has a dedicated table in the database.
There are two types of Django model that do not have dedicated database tables, viz. abstract models and proxy models:
Abstract models act as superclasses for concrete models. An abstract model can define fields, but it does not have a database table. The fields are only added to the database tables for its concrete subclasses.
Proxy models act as subclasses for concrete models. A proxy model cannot define new fields. Instead, it operates on the database table associated with its concrete superclass. In other words, a Django concrete model and its proxies all share a single table.
Django's proxy models provide the basis for Single Table Inheritance, viz. they allow different models to share a single table, and they allow us to define proxy-specific behavior on the Python side. However, Django's default object-relational mapping (ORM) does not provide all the behavior that would be expected, so a little customization is required. How much, that depends on your needs.
Let's build a minimal example, step by step, based on the simple data-model in the figure below:
Step 1: basic "proxy model inheritance"
Here's the content of models.py for a basic proxy inheritance implementation:
from django.db import models
class Party(models.Model):
name = models.CharField(max_length=20)
person_attribute = models.CharField(max_length=20)
organization_attribute = models.CharField(max_length=20)
class Person(Party):
class Meta:
proxy = True
class Organization(Party):
class Meta:
proxy = True
Person and Organization are two types of parties.
Only the Party model has a database table, so all the fields are defined on this model, including any fields that are specific either to Person or to Organization.
Because Party, Person, and Organization all use the Party database table, we can define a single ForeignKey field to Party, and assign instances of any of the three models to that field, as implied by the inheritance relation in the figure. Note, that, without inheritance, we would need a separate ForeignKey field for each model.
For example, suppose we define an Address model as follows:
class Address(models.Model):
party = models.ForeignKey(to=Party, on_delete=models.CASCADE)
We can then initialize an Address object using e.g. Address(party=person_instance) or Address(party=organization_instance).
So far, so good.
However, if we try to get a list of objects corresponding to a proxy model, using e.g. Person.objects.all(), we get a list of all Party objects instead, i.e. both Person objects and Organization objects. This is because the proxy models still use the model manager from the superclass (i.e. Party).
Step 2: add proxy model managers
To make sure that Person.objects.all() only returns Person objects, we need to assign a separate model manager that filters the Party queryset. To enable this filtering, we need a field that indicates which proxy model should be used for the object.
To be clear: creating a Person object implies adding a row to the Party table. The same goes for Organization. To distinguish between the two, we need a column to indicate if a row represents a Person or an Organization. For convenience and clarity, we add a field (i.e. column) called proxy_name, and use that to store the name of the proxy class.
So, enter the ProxyManager model manager and the proxy_name field:
from django.db import models
class ProxyManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(proxy_name=self.model.__name__)
class Party(models.Model):
proxy_name = models.CharField(max_length=20)
name = models.CharField(max_length=20)
person_attribute = models.CharField(max_length=20)
organization_attribute = models.CharField(max_length=20)
def save(self, *args, **kwargs):
self.proxy_name = type(self).__name__
super().save(*args, **kwargs)
class Person(Party):
class Meta:
proxy = True
objects = ProxyManager()
class Organization(Party):
class Meta:
proxy = True
objects = ProxyManager()
Now the queryset returned by Person.objects.all() will only contain Person objects (and the same for Organization).
However, this does not work in the case of a ForeignKey relation to Party, as in Address.party above, because that will always return a Party instance, regardless of the value of the proxy_name field (also see docs). For example, suppose we create an address = Address(party=person_instance), then address.party will return a Party instance, instead of a Person instance.
Step 3: extend the Party constructor
One way to deal with the related-field issue is to extend the Party.__new__ method, so it returns an instance of the class specified in the 'proxy_name' field. The end result looks like this:
class Party(models.Model):
PROXY_FIELD_NAME = 'proxy_name'
proxy_name = models.CharField(max_length=20)
name = models.CharField(max_length=20)
person_attribute = models.CharField(max_length=20)
organization_attribute = models.CharField(max_length=20)
def save(self, *args, **kwargs):
""" automatically store the proxy class name in the database """
self.proxy_name = type(self).__name__
super().save(*args, **kwargs)
def __new__(cls, *args, **kwargs):
party_class = cls
try:
# get proxy name, either from kwargs or from args
proxy_name = kwargs.get(cls.PROXY_FIELD_NAME)
if proxy_name is None:
proxy_name_field_index = cls._meta.fields.index(
cls._meta.get_field(cls.PROXY_FIELD_NAME))
proxy_name = args[proxy_name_field_index]
# get proxy class, by name, from current module
party_class = getattr(sys.modules[__name__], proxy_name)
finally:
return super().__new__(party_class)
Now address.party will actually return a Person instance if the proxy_name field is Person.
As a last step, we can make the whole thing re-usable:
Step 4: make it re-usable
To make our rudimentary Single-Table Inheritance implementation re-usable, we can use Django's abstract inheritance:
inheritance/models.py:
import sys
from django.db import models
class ProxySuper(models.Model):
class Meta:
abstract = True
proxy_name = models.CharField(max_length=20)
def save(self, *args, **kwargs):
""" automatically store the proxy class name in the database """
self.proxy_name = type(self).__name__
super().save(*args, **kwargs)
def __new__(cls, *args, **kwargs):
""" create an instance corresponding to the proxy_name """
proxy_class = cls
try:
field_name = ProxySuper._meta.get_fields()[0].name
proxy_name = kwargs.get(field_name)
if proxy_name is None:
proxy_name_field_index = cls._meta.fields.index(
cls._meta.get_field(field_name))
proxy_name = args[proxy_name_field_index]
proxy_class = getattr(sys.modules[cls.__module__], proxy_name)
finally:
return super().__new__(proxy_class)
class ProxyManager(models.Manager):
def get_queryset(self):
""" only include objects in queryset matching current proxy class """
return super().get_queryset().filter(proxy_name=self.model.__name__)
Then we can implement our inheritance structure as follows:
parties/models.py:
from django.db import models
from inheritance.models import ProxySuper, ProxyManager
class Party(ProxySuper):
name = models.CharField(max_length=20)
person_attribute = models.CharField(max_length=20)
organization_attribute = models.CharField(max_length=20)
class Person(Party):
class Meta:
proxy = True
objects = ProxyManager()
class Organization(Party):
class Meta:
proxy = True
objects = ProxyManager()
class Placement(models.Model):
party = models.ForeignKey(to=Party, on_delete=models.CASCADE)
More work may be required, depending on your needs, but I believe this covers some of the basics.
I think the OP is asking about Single-Table Inheritance as defined here:
Relational databases don't support inheritance, so when mapping from objects to databases we have to consider how to represent our nice inheritance structures in relational tables. When mapping to a relational database, we try to minimize the joins that can quickly mount up when processing an inheritance structure in multiple tables. Single Table Inheritance maps all fields of all classes of an inheritance structure into a single table.
That is, a single database table for a whole hierarchy of entity classes. Django does not support that kind of inheritance.
There are currently two forms of inheritance in Django - MTI (model table inheritance) and ABC (abstract base classes).
I wrote a tutorial on what's going on under the hood.
You can also reference the official docs on model inheritance.
See my attempt:
http://djangosnippets.org/snippets/2408/
An emulation of "table per hierarchy" a.k.a. "single table inheritance" in Django. The base class must hold all the fields. It's subclasses are not allowed to contain any additional fields and optimally they should be proxies.
Not exactly "single table inheritance", but close enough for many situations.
this might be of use: https://github.com/craigds/django-typed-models
It looks to be somewhat of an implementation of Single Table Inheritance but it has the limitation that subclasses can't have any extra fields.
here is a recent discussion on the django developer mailing list about STI:
https://groups.google.com/forum/#!msg/django-developers/-UOM8HNUnxg/6k34kopzerEJ
I think you can do something akin to this.
I have to implement a solution for this problem myself, and here was how I solved it:
class Citrus(models.Model):
how_acidic = models.PositiveIntegerField(max_value=100)
skin_color = models.CharField()
type = models.CharField()
class TangeloManager(models.Manager):
def get_query_set(self):
return super(TangeloManager, self).get_query_set().filter(type='Tangelo')
class Tangelo(models.Model):
how_acidic = models.PositiveIntegerField(max_value=100)
skin_color = models.CharField()
type = models.CharField()
objects = TangeloManager()
class Meta:
# 'appname' below is going to vary with the name of your app
db_table = u'appname_citrus'
This may have some locking issues... I'm not really sure how django handles that off the top of my head. Also, I didn't really test the above code, it's strictly for entertainment purposes, to hopefully put you on the right track.