I have some classes in models.py, and after adding one more I need to add one more attribute in to the already created class, I found in internet that the best way to do this is to use setattr()
function, so I made all and.. It seems work, no bugs, it is showing in the Admin site as <django.db.models.fields.related.OneToOneField>
, but there are no way to chose it when I trying to create or change this field, there aren't , is it a bug or I doing smth wrong?
Here is my code:
class PlayerInstance(models.Model):
#...
class Competition(models.Model):
#...
setattr(PlayerInstance, 'choice_to_competition', models.OneToOneField(
Competition,
default = 'for_nothoing',
on_delete=models.RESTRICT,
help_text='which competition is it taking part?',
))
And no, I didn't forget to add 'choice_to_competition' in to the list_display. Here 2 photos of Admin site: I made them, but I can't add them here, can't understand reason, but it is not really necessary.
I found in internet that the best way to do this is to use
setattr()
function, so I made all and.
No. For "ordinary" classes that might work. But Django's Model
has some advanced meta-logic, meaning attributes not passed when constructing the class, might end up not in the model.
What you need is to use the .contribute_to_class(…)
method, like:
models.OneToOneField(
Competition,
default='for_nothoing',
on_delete=models.RESTRICT,
help_text='which competition is it taking part?',
).contribute_to_class(PlayerInstance, 'choice_to_competition')
But, you don't need to do this trick to refer to a model not yet created. Indeed, for a ForeignKey
[Django-doc], OneToOneField
model field [Django-doc] and ManyToManyField
model field [Django-doc], you can use a string literal to refer to a model that has not yet been defined, with:
class PlayerInstance(models.Model):
choice_to_competition = models.OneToOneField(
'app_name.Competition',
default='for_nothoing',
on_delete=models.RESTRICT,
help_text='which competition is it taking part?',
)
# …
class Competition(models.Model):
# …
If the model has the same app label, you can even drop the app_label
:
class PlayerInstance(models.Model):
choice_to_competition = models.OneToOneField(
'Competition',
default='for_nothoing',
on_delete=models.RESTRICT,
help_text='which competition is it taking part?',
)
# …
class Competition(models.Model):
# …
Note: Models normally have no
Instance
suffix. An object from a class is always called an "instance", by naming the class…Instance
, one gets the impression that the variable is an instance of a class.