Currently, I'm having a problem when overriding a form field value on my (Django==4.0.3) django admin form. The objective is : I have a specific user table that I'm connecting to AWS Cognito. And when the admin creates a new user in django, the system must create a request to create a new Cognito user. Once the Cognito user is created it generates a "sub" code, and then the sub should be saved in django
Code Follows
Model
class BuyerUser(BaseModel):
buyer = models.ForeignKey(
Buyer, on_delete=models.RESTRICT, related_name="%(class)s_buyer"
)
cognito_sub = models.CharField(max_length=50)
given_name = models.CharField(max_length=50)
family_name = models.CharField(max_length=50)
preferred_username = models.CharField(max_length=50)
email = models.EmailField(blank=False)
terms_conditions_accepted_datetime = models.DateTimeField(null=True, blank=True)
def __str__(self):
return self.preferred_username
admin
class BuyerUsers(admin.ModelAdmin):
list_display = ('id', 'buyer', 'given_name', 'family_name', 'preferred_username', 'available')
list_filter = ('buyer', 'available',)
list_display_links = ('id', 'preferred_username',)
search_fields = ('buyer__name', 'preferred_username', 'available')
list_per_page = 20
form = BuyerUserChangeForm
add_form = BuyerUserAddForm # It is not a native django field. I created this field and use it in get_form method.
def get_form(self, request, obj=None, **kwargs):
"""
Use special form during foo creation
"""
defaults = {}
if obj is None:
defaults['form'] = self.add_form
defaults.update(kwargs)
return super().get_form(request, obj, **defaults)
admin.site.register(BuyerUser, BuyerUsers)
and my forms
class BuyerUserAddForm(forms.ModelForm):
grupo = forms.CharField()
def __init__(self, data=None, files=None, auto_id='id_%s', prefix=None,
initial=None, error_class=ErrorList, label_suffix=None,
empty_permitted=False, instance=None, use_required_attribute=None,
renderer=None):
super().__init__(data, files, auto_id, prefix, initial, error_class, label_suffix, empty_permitted, instance,
use_required_attribute, renderer)
self.cognito_sub = None
def save(self, commit=True):
grupo = self.cleaned_data.get('grupo', None)
self.given_name = self.cleaned_data.get('given_name', None)
self.family_name = self.cleaned_data.get('family_name', None)
self.preferred_username = self.cleaned_data.get('preferred_username', None)
self.email = self.cleaned_data.get('email', None)
cognito = CognitoDriver()
sub = cognito.parse_user(
cognito.create_user(self.preferred_username, self.email)["User"]
)["Sub"]
self.cognito_sub = sub
cognito.add_group(self.preferred_username, grupo)
return super(BuyerUserAddForm, self).save(commit=commit)
class Meta:
model = BuyerUser
# fields = '__all__'
exclude = ['terms_conditions_accepted_datetime']
class BuyerUserChangeForm(forms.ModelForm):
class Meta:
model = BuyerUser
fields = '__all__'elf.cognito_sub = sub
cognito.add_group(self.preferred_username, grupo)
return super(BuyerUserAddForm, self).save(commit=commit)
class Meta:
model = BuyerUser
# fields = '__all__'
exclude = ['terms_conditions_accepted_datetime']
class BuyerUserChangeForm(forms.ModelForm):
class Meta:
model = BuyerUser
fields = '__all__'
create
Change
This cognito sub field should have its value override after cognito-user is created. as it should be happening in the following code
cognito = CognitoDriver()
sub = cognito.parse_user(
cognito.create_user(self.preferred_username, self.email)["User"]
)["Sub"]
self.cognito_sub = sub
In fact, this cognito-user is being created and the sub is correct. the BIG PROBLEM is: this sub is not saved. It is getting only the value from the form. I've tried to hide sub field using exclude = ['cognito_sub','terms_conditions_accepted_datetime'] but only happens to save a empty value.
You may ask why I use Forms instead of simply override model.Save() method and the answer is: I need the grupo field, but this field must be persisted in DB. It only exists in Cognito.
CodePudding user response:
You have to assign the value to form.instance
instead of directly to the form itself.
class BuyerUserAddForm(forms.ModelForm):
grupo = forms.CharField()
# ...
def save(self, commit=True):
grupo = self.cleaned_data.get('grupo', None)
self.preferred_username = self.cleaned_data.get('preferred_username', None)
self.email = self.cleaned_data.get('email', None)
cognito = CognitoDriver()
sub = cognito.parse_user(
cognito.create_user(self.preferred_username, self.email)["User"])["Sub"]
self.instance.cognito_sub = sub
cognito.add_group(self.preferred_username, grupo)
return super(BuyerUserAddForm, self).save(commit=commit)
You might even want to disable the input field completly using the disabled
attribute. https://docs.djangoproject.com/en/4.0/ref/forms/fields/#disabled
class BuyerUserAddForm(forms.ModelForm):
cognito_sub = forms.CharField(disabled=True)
# ...