Reputation: 2773
I have a basic model / form / views:
models.py
class Tag(models.Model):
name = models.CharField(max_length=100, unique=True)
forms.py
class TagForm(forms.ModelForm):
class Meta:
model = Tag
fields = '__all__'
views.py
class TagCreate(CreateView):
model = Tag
form_class = TagForm
success_url = reverse_lazy('view_somethin')
When using django-rest-frawework or Tag.objects.create(name="aagagaga"), the "name" field is passed to the __init__()
of Tag
, and i can do all hacks i want.
But when using the class based view, __init__()
is of course called but no args are passed to. However, in the save method, i can check that the name attribute is already set to the good value.
My question is, how and where the data are transfered to the model instance if in case of class based views nothing is passed to the __init__()
??
I try to dig in the source code with no success, i suspect some king of manager
If you want to reproduce the issue, here is the testing code:
class Tag(models.Model):
name = models.CharField(max_length=100, unique=True)
def __str__(self):
return f"Tag {self.name}"
def __init__(self, *args, **kwargs):
print(args)
print(kwargs)
super().__init__(*args, **kwargs)
print(self.__dict__)
def save(self, *args, **kwargs):
print(self.__dict__) # the filled attributes are here, but when were they filled ?
super().save(*args, **kwargs)
Tag.objects.create(name="aagagaga") # this call the __init__() with args as
# intended but when using the html view, nothing is passed
Upvotes: 1
Views: 67
Reputation: 2773
So i found a way, i don't exactly how it works internaly but i suppose Django modify the attributes of the model on the fly.
Actually, the form
stores a reference of the model instance in self.instance
So if you want to add/modify attributes like you would do in the __init__()
of the model, you can do it by overriding form_valid
of the CreateView
:
class TagCreate(CreateView):
model = Tag
form_class = TagForm
success_url = reverse_lazy('view_somethin')
def form_valid(self, form):
form.instance.new_attribute = "new_thing"
return super().form_valid(form)
Then it appear in the model.
class Tag(models.Model):
name = models.CharField(max_length=100, unique=True)
def save(self, *args, **kwargs):
print(self.__dict__) # new_attribute appeared
self.name += self.new_attribute
super().save(*args, **kwargs)
Of course the new attribute is not meant to be saved in the database, but can be a useful modifier, like the current user.
Upvotes: 1