I've found similar questions and answers, but none seems exactly right. I've got an abstract base model like so:
class BaseModel(models.Model):
timestamp = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
description = models.CharField(max_length=512, blank=True, null=True, help_text='Help')
class Meta:
abstract = True
And then I'm inheriting from it:
class AnotherModel(BaseModel):
field1 = models.CharField(max_length=512)
But I want this model's help_text on the description field to be something else, like help_text='Some other help text'
What's the best way to do this? Can I override options on fields from inherited models?
If this is really about the help text, I suggest to just override the ModelForm. However, you can use a factory and return the inner class:
def base_factory(description_help: str = "Standard text"):
class BaseModel(models.Model):
timestamp = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
description = models.CharField(
max_length=512, blank=True, null=True, help_text=description_help
)
class Meta:
abstract = True
return BaseModel
class ConcreteModel(base_factory("Concrete help")):
field1 = ...
Related
I have a abstract base model and two child models:
class Component(models.Model):
serial = models.PositiveIntegerField(unique=True)
last_modified = models.DateTimeField(auto_now_add=True)
class Meta:
abstract = True
class ChildComponentA(Component):
name = models.CharField(max_length=200, null=True, blank=True)
class ChildComponentB(Component):
name = models.CharField(max_length=200, null=True, blank=True)
I want the serial field to be unique for all children but this does not work for me.
How can I achieve this?
You can replace PositiveIntegerField by AutoField (source) or you can use another type of unique field, like an UUIDField, if another format is possible for you.
I have the following models:
class Category(models.Model):
name = models.CharField()
... # fields omitted
class Prediction(models.Model):
conversation = models.ForeignKey(Conversation)
category = models.ForeignKey(Category)
... # fields omitted
class Conversation(models.Model):
sid = models.CharField()
... # fields omitted
Now I'm trying to create a model serializer for Category that would return me the following serialized object:
{
"name":"blah",
"conversations":[
"2af22188c5c97256", # This is the value of the sid field
"073aef6aad0883f8",
"5d3dc73fc8cf34be",
]
}
Here is what I have in my serializer:
class CategorySerializer(serializers.ModelSerializer):
conversations = serializers.SlugRelatedField(many=True,
read_only=True,
source="prediction_set",
slug_field='conversation.sid')
class Meta:
model = models.Class
fields = ('class_name', 'conversations')
However, this doesn't work because somehow django doesn't allow me to set slug_field to be a field that's within an object field. Any suggestions on how to accomplish this?
You are modelling a Many-to-Many relationship between Categorys and Conversations with a explicit table called Prediction. The django way of doing this would be to explicitly state the Many-to-Many on either side of the relationship and specify Prediction as the "through-model":
Shamelessly stolen example from this question:
class Category(models.Model):
name = models.CharField(max_length=255)
slug = models.SlugField(unique=True, max_length=255, blank=True,default=None)
desc = models.TextField(blank=True, null=True )
...
class Post(models.Model):
title = models.CharField(max_length=255)
pub_date = models.DateTimeField(editable=False,blank=True)
author = models.ForeignKey(User, null=True, blank=True)
categories = models.ManyToManyField(Category, blank=True, through='CatToPost')
...
class CatToPost(models.Model):
post = models.ForeignKey(Post)
category = models.ForeignKey(Category)
...
This shows a good way to set up the relationship.
Equally shamelessly stolen from the answer by #Amir Masnouri:
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = ('name','slug')
class PostSerializer(serializers.ModelSerializer):
class Meta:
model = Post
fields = ('id','{anything you want}','categories')
depth = 2
This shows a nice way of achieving the nested serialization behavior that you would like.
I've created a mixin and inherited from it in some models. The problem is when I create a schema migration, the mixin's fields are there.
class MyMixin(object):
a_field = models.CharField(max_length=30, blank=True)
another_field = models.DateTimeField(blank=True, null=True)
class Meta:
abstract = True
class MyModel(models.Model, myMixin):
...
Any ideas?
Seem to have got it working using the following
class MyMixin(models.Model):
a_field = models.CharField(max_length=30, blank=True)
another_field = models.DateTimeField(blank=True, null=True)
class Meta:
abstract = True
class MyModel(myMixin, models.Model):
...
The changes are:
MyMixin inherits Model rather than object (despite many discussions around the place saying that mixins for django should inherit object rather than Model)
the order of inheritance for MyModel - the mixin has to come first
i'm recently moving my db to a model Inheritance structure. Here an example:
Task model
STATUS_CHOISE = (('PR', 'In process'), ('ST', 'Stopped'), ('FN', 'Finished'), ('DL', 'Deleted'),)
class Task(models.Model):
owner = models.ForeignKey(User)
process = models.ForeignKey(Process)
title = models.CharField(max_length=200, default='')
description = models.CharField(max_length=1000, default='')
date_created = models.TimeField(auto_now_add=True, auto_now=False)
date_deadline = models.DateTimeField(default=lambda: (datetime.now() + timedelta(days=7)), auto_now_add=False)
parameters = jsonfield.JSONField()
objects = InheritanceManager()
status = models.CharField(max_length=2, choices=STATUS_CHOISE, default='ST')
here the HumanTask that extends Task
PLATFORMS = (('CC', 'CrowdComputer'), ('MT', 'Amazon Mechancial Turk'),)
class HumanTask(Task):
number_of_instances = models.IntegerField(default=1)
uuid = models.CharField(max_length=36, default='')
page_url = models.URLField(max_length=400, default='', null=True, blank=True)
platform = models.CharField(max_length=2,choices=PLATFORMS, default='CroCo')
validation=models.OneToOneField(ValidationTask)
reward = models.OneToOneField(Reward, null=True, blank=True)
now, how should i create the Form? Should i use ModelForm for both classes?
The point is: there are fields that have to be exclude
for example, TaskForm is:
class TaskForm(ModelForm):
owner = forms.ModelChoiceField(queryset=User.objects.all(),widget=forms.HiddenInput)
process = forms.ModelChoiceField(queryset=Process.objects.all(),widget=forms.HiddenInput)
class Meta:
model = Task
exclude = ('date_deadline', 'date_created','parameters','status','objects')
so what i want for the HumanTaskForm is that the exclude are inherited from the TaskForm
i tried with this
class HumanTaskForm(TaskForm):
class Meta:
model= HumanTask
exclude = 'uuid'
but does not work.
Summing up: is this correct? should i use Inheritance for forms? and, how can i have excluded fields, and others parameters, Inheritance?
If you want to leverage the exclude from TaskForm in HumanTaskForm and extend it, you can inherit the Meta class from TaskForm:
class HumanTaskForm(TaskForm):
class Meta(TaskForm.Meta):
model = HumanTask
exclude = TaskForm.Meta.exclude + ('uuid',)
You need to inherit the parent Meta as well as.
The child class will inherit/copy the parent Meta class. Any attribute explicitly set in the child meta will override the inherited version. To my knowledge there is no way to extend the parent Meta attributes (ie adding to 'exclude').
class AwesomeForm(forms.ModelForm):
class Meta:
model = AwesomeModel
exclude = ('title', )
class BrilliantForm(AwesomeForm)
class Meta(AwesomeForm):
model = BrilliantModel
.
print(AwesomeForm.Meta.model)
> AwesomeModel
print(BrilliantForm.Meta.model)
> BrilliantModel
print(AwesomeForm.Meta.exclude)
> ('title', )
print(BrilliantForm.Meta.exclude)
> ('title', )
You could do something like this:
class BrilliantForm(AwesomeForm)
class Meta(AwesomeForm):
model = BrilliantModel
exclude = AwesomeForm.Meta.exclude + ('uuid', )
.
print(BrilliantForm.Meta.exclude)
> ('title', 'uuid')
Django ContentTypes provides a GenericInlineFormSet, however the documentation does not explain how to use it, except for this test, which doesn't really explain it in a way I understand.
Please can you help me understand it?
Let's say I have the following classes
class Dog(models.Model):
name = models.CharField(max_length=64)
breed = models.CharField(blank=True, max_length=64)
class Meta:
verbose_name = 'Dog'
class Fish(models.Model):
name = models.CharField(max_length=64)
habitat = models.CharField(blank=True, max_length=64)
class Meta:
verbose_name = 'Fish'
class Pet(models.Model):
content_type = models.ForeignKey(
ContentType,
limit_choices_to={'model__in':('dog', 'fish')},
verbose_name='Species'
)
object_id = models.CharField(max_length=64, verbose_name='Animal')
object = generic.GenericForeignKey('content_type', 'object_id')
owner = models.ForeignKey(Owner)
class Meta:
unique_together = [("content_type", "object_id")]
What does the view look like to display a form for a Pet?
GenericInlineFormSet works just like a standard inline formset, except that it uses generic relations rather than standard foreign keys.