In a Django multi-table inheritance scenario:
from django.db import models
class Place(models.Model):
pass
class Restaurant(Place):
pass
the subclass can be accessed through a superclass instance with the lower-case class name:
place = Place.objects.get(id=id)
restaurant = place.restaurant # auto-generated from `Restaurant`
How can the accessor name be customized, such that:
restaurant = place.custom_accessor_name
?
Given that the accessor is an implicitly-created OneToOneField, it is not clear where the related_name can be customized. It seems possible to add:
custom_accessor_name = models.OneToOneField(Restaurant)
but it is not clear if such a field is redundant or not.
If you want to define the one or one field manually, then use parent_link=True. Otherwise, an additional field will be created.
Related
I'm using Python 3.6+PostgreSQL 10+latest Django and DjangoRestFRamework. I have the following models, in which several models inherit from a class which is the ForeignKey (One-to-Many) of another class.
class Voteable(models.Model):
Voteable_id = models.BigAutoField(primary_key=True);
class base(Voteable):
class Meta:
abstract = False
class traslated_info(models.Model):
info_about=models.ForeignKey(base)
info_body=models.TextField()
info_language=models.CharField(max_length=2)
class A(base):
A_id=models.BigAutoField(primary_key=True)
A_field=models.TextField()
class B(base):
B_id=models.BigAutoField(primary_key=True)
B_field=models.TextField()
B_belongs_to=models.ForeignKey(A)
class C(base):
C_id=models.BigAutoField(primary_key=True)
C_field=models.TextField()
C_belongs_to=models.ForeignKey(A)
C_belongs_to=models.ForeignKey(B)
Whenever I try saving an object A (via curl), django says that base_ptr is required. I don't know how to model this situation. The end user is not expected to create item base and then item A, B or C. I tried class base as abstract, but an abstract class can't be ForeignKey. I want to automatically create a base class whenever a class A is created.
I think I have two options: A) Remove the ForeignKey and store the language-specific info fields as HStoreField. This makes the code somewhate dependent on Postgree. B) Create some sort of routine that automatically creates parent base item whenever a child A item is created (preserving the one to one relationship).
What do you recommend? Is there some django easy option I'm missing to make option B? I have not found this. Thank you.
Having an autofield as primary_key in the models A, B or C causes this error, as creating a child model doesn't cascade-create parents.
I found two workarounds:
Change autofield option primary_key to false and add
SILENCED_SYSTEM_CHECKS=['fields.E100']
Overriding Viewset create method:
#transaction.atomic
def create(self,request,*args,**kwargs):
request.data['base_ptr'] = base.objects.create(user=request.user,created_date=datetime.utcnow()).pk
return super(viewsets.ModelViewSet,self).create(request,*args,**kwargs)
I will stick with the second, I'm quite sure more issues will arise.
Make your serializer as below, you dont need to create base classes explicitly, it will be created automatically.
class ASerializer(serializers.ModelSerializer):
class Meta:
model = A
read_only_fields = ('base_ptr',)
fields = '__all__'
I have a situation where I need to subclass a custom user model for a django 1.5 project (related question/background here: Subclassing AbstractUser in Django for two types of users )
I need an abstract user class SchoolPerson and a number of subclasses (Student, Teacher, etc) based on this. I think I've resolved that I need to have the user model in a separate DB table to the subclasses as other apps rely on AUTH_USER_MODEL, of which there can only be one.
So the way I see it, I have to options to do this: add one-to-one to the standard user model in my abstract SchoolPerson class:
class SchoolPerson(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL)
...
class Meta:
abstract = True
class Student(SchoolPerson):
year_level = models.CharField(max_length=3)
...
class Teacher(SchoolPerson):
govt_id = models.CharField(max_length=10)
...
Or I can make my SchoolPerson model inherit AbstractUser, but keep this class non-abstract:
class SchoolPerson(AbstractUser):
...
#no Meta abstract here
class Student(SchoolPerson):
year_level = models.CharField(max_length=3)
...
class Teacher(SchoolPerson):
govt_id = models.CharField(max_length=10)
...
Are there any advantages to one of these over the other?
I haven't tested this but what I expect is for your first suggestion to create two db tables:
one for Student and one for Teacher each with a foreign key to the AUTH_USER_MODEL.
For the second one I expect Django to create three db tables:
One for the SchoolPerson(which will be exact as the default Users table with the additional fields) and two for Student and Teacher with foreign keys to SchoolPerson.
So I think the answer depends on your requirements.
This is my code:
class Resource(models.Model):
[...]
class Theme(models.Model):
[...]
resource_set = models.ManyToManyField(Resource, through='Match', related_name='theme_set', blank=True)
class Match(models.Model):
resource = models.ForeignKey(Resource)
theme = models.ForeignKey(Theme)
[...]
I am intentionally using an intermediate model, because I want to add some attributes to the relationship. Now... I know that when declaring many-to-many relationship in Theme, I am also getting a reverse relationship from Resource. See the related_name I'm using? This way I have "symmetrical" field names in both models (resource_set, theme_set, and match_set in both models).
My problem is that when I generate forms from both models (Resource and Theme) they are not symmetrical. When I generate a Theme form I automatically get a multiple choice field to choose from the already existing Resources. But when I generate a Resource form I don't.
So that is why I would like to declare many-to-many relationship in both models - to make them really equal (not like in the Pizzas and Toppings example ;) and to have these additional multiple choice fields generated.
The question is - is it possible, or do I have to add the multiple choice field to the ResourceForm myself or use FormSets which I don't understand yet?
BTW - as I can't save a new Theme from ThemeForm using save() ("Cannot set values on a ManyToManyField which specifies an intermediary model.") I do this:
[...]
theme = form.save(commit=False)
theme.save()
for resource in form.cleaned_data['resource_set']:
match = Match()
match.resource = resource
match.theme = theme
match.save()
return redirect([...]
You can simply define it on both sides.
One problem would be the related_name - As far as I know, there is no way of telling the ORM "I'll take care of the reverse relation myself". So you'll need to change the related_names so they don't clash with the real field names. In this example I added underscore to the related_names, so Resource objects now have both theme_set and _theme_set, which are two handles to the same data.
class Resource(models.Model):
[...]
theme_set = models.ManyToManyField('Theme',
through='Match',
related_name='_resource_set',
blank=True)
class Theme(models.Model):
[...]
resource_set = models.ManyToManyField(Resource,
through='Match',
related_name='_theme_set',
blank=True)
Also, if you're using South, you may need to add_ignored_fields to one of the field.
So I have a model heirarchy using multi-table inheritance and I was wondering if there was a some sort of ModelForm or similar approach for creating an object like a normal model form and have the user choose which of the subclasses they want to use in the form in like a choice field.
The heirarchy is as follow:
class Base(models.Model):
field1 = models.CharField(max_length=10)
field2 = models.CharField(max_length=20)
class A(Base):
pass
class B(Base):
pass
class C(Base):
pass
I can't use Meta abstract models because I have one class that needs a foreign key to the Base which is why I'm using multi-table inheritance and in the future the child classes may have additional field. Do you have any suggestions of how I go about doing this?
Currently the way I'm doing it is using a normal form and having all the common fields in that form as well as a choice field which they can select the type of the model they want to use and then I've created a save method which interprets the type from the choice field and creates the object of that type. I can't help but feel there is a better method of doing this.
In Django, is there a way to create the following dynamic relationship between models?
class ClothingMale(models.Model):
# male specific fields
class ClothingFemale(models.Model):
# female specific fields
class Person(models.Model):
gender = models.IntegerField(max_length=2, choices=GENDER_CHOICES, blank=True)
clothes = models.ForeignKey(???)
I am using a ModelForm for Person. The clothes fields inside the form should change dynamically depending on which gender was selected. I am aware of GenericForeignKeys but I was wondering if there is better way to solve this?
IMHO it's a question of DB design; I would go for a PersonClothing superclass and subclass it with MalePersonClothing and FemalePersonClothing. The PersonClothing superclass would be a Django abstract base class; a specific class useful when you want to put some common information into a number of other models.
To do it just specify the following option in your model's meta:
class Meta:
abstract = True
One option is to use GenericForeignKey. This of course has int's down-sides, for exampl you cannot filter() on GenericForeignKey
Another option is to use model inheritance, which also has quite a few gotchas.