i have an UpdateView with a couple of forms and i'm trying to understand how to set the instance for the other form because the first form work just fine but the second form is always empty and i cant figure out how to set the instance for that modelform .
class ProfileUpdateView(UpdateView):
# model = User
queryset = User.objects.all()
form_class = UserForm
second_form_class = ClientForm
template_name = 'accounts/update.html'
def get_object(self):
user = get_object_or_404(User , username__iexact=self.kwargs.get('username'))
return user
def get_context_data(self, **kwargs):
user = self.object
profile = Client.objects.get(id = user.clients.id)
context = super(ProfileUpdateView, self).get_context_data(**kwargs)
if user.is_client and 'ClientForm' not in context:
context['client_form'] = self.second_form_class(self.request.GET, instance=profile )
return context
models
class User(AbstractUser):
gender_choice =(
('Male','Male'),
('Female','Female'),
)
is_artisan = models.BooleanField('artisan status', default=False)
is_client = models.BooleanField('client status', default=False)
avatar = models.ImageField(null=True ,blank=True)
birth_day = models.DateField(null=True,blank=True)
birth_location = models.CharField(max_length=30, null=True ,blank=True)
adresse = models.CharField(max_length=30, null=True ,blank=True)
gender = models.CharField(max_length=6,choices=gender_choice,)
phone = models.CharField(max_length=10 ,null=True ,blank=True)
class Client(models.Model):
client_choice = (
('erson','person'),
('company','company'),
)
client_type = models.CharField(max_length=10,choices=client_choice,)
user = models.OneToOneField(settings.AUTH_USER_MODEL,on_delete=models.CASCADE, related_name='clients')
forms
class UserForm(forms.ModelForm):
class Meta:
model = User
fields = ('first_name', 'last_name', 'email','avatar','adresse','birth_location','birth_day' ,'gender' ,'phone')
class ClientForm(forms.ModelForm):
class Meta:
model = Client
fields = ('client_type',)
the question now how/where can i set the instance for the second form and where is the first form instance is set .
Is that a typo in get_context_data? Should it be:
if user.is_client and 'client_form' not in context:
context['client_form'] = self.second_form_class(self.request.GET, instance=profile)
The first form is set in UpdateView's super class FormMixin.get_context_data (which in turn calls FormMixin.get_form()). Docs for FormMixin
Related
I want to filter skill_ids fields and create 3 "abstract" fields for every SkillType, but now it's not saving this hard_skills field in admin site.
Model
class Task(models.Model):
name = models.CharField(max_length=255)
category_id = models.ForeignKey('Category', on_delete=models.RESTRICT, null=True)
level_id = models.ForeignKey('Level', on_delete=models.RESTRICT, null=True)
permission_ids = models.ManyToManyField('Permission', blank=True)
skill_ids = models.ManyToManyField('Skill', blank=True)
Form
class TaskForm(ModelForm):
hard_skills = ModelMultipleChoiceField(Skill.objects.filter(skill_type=SkillType.HARD_SKILL),
widget=FilteredSelectMultiple("Hard Skills", False), required=False)
class Meta:
model = Task
exclude = ['skill_ids']
Admin
#admin.register(Task)
class TaskAdmin(admin.ModelAdmin):
list_per_page = 25
list_display = ['name', 'category_id', 'level_id', 'get_permissions']
list_filter = ['category_id']
filter_horizontal = ['permission_ids', 'skill_ids']
form = TaskForm
def save_model(self, request, obj, form, change):
for hard_skill in form.cleaned_data.get('hard_skills'):
obj.skill_ids.set(hard_skill)
super().save_model(request, obj, form, change)
ManyToManyField method set requires a list, so this should do:
obj.skill_ids.set(form.cleaned_data.get('hard_skills'))
I need to be able to set the KeyIndex field of the Settings model to a value that is equal to
lastExtension - firstExtension
How can i do that
this is the content of my model
models.py
class Settings(models.Model):
KeyIndex = models.CharField(max_length=150, blank=True, name='Key_Index')
firstExtension = models.CharField(max_length=15, blank=False, null=False, default='1000')
lastExtension = models.CharField(max_length=15, blank=False, null=False, default='1010')
def save(self, *args, **kwargs):
f = int(self.firstExtension)
l = int(self.lastExtension)
a = [0] * (l - f)
self.KeyIndex = str(a)
return super(Settings, self).save()
class KeyFiles(models.Model):
setting = models.ForeignKey(Settings, on_delete=models.CASCADE)
keyFile = models.FileField(upload_to='key File', null=True, blank=True, storage=CleanFileNameStorage,
validators=[FileExtensionValidator(allowed_extensions=['bin']), ])
this is the content of my form
forms.py
class ShowAdminForm(forms.ModelForm):
class Meta:
model = Settings
fields = '__all__'
files = forms.FileField(
widget=forms.ClearableFileInput(attrs={"multiple": True}),
label=_("Add key Files"),
required=False,validators=[FileExtensionValidator(allowed_extensions=['bin'])]
)
def save_keyFile(self, setting):
file = KeyFiles(setting=setting, keyFile=upload)
file.save()
and t
admin.py
class KeyFilesAdmin(admin.TabularInline):
model = KeyFiles
#admin.register(IPPhone_Settings)
class IPPhoneSettingsAdmin(admin.ModelAdmin):
form = ShowAdminForm
inlines = [KeyFilesAdmin]
def save_related(self, request, form, formsets, change):
super(IPPhoneSettingsAdmin, self).save_related(request, form, formsets, change)
My form sends data to django-rest-framework, but the form contains two fields, and I want to save 5 fields in the database, other fields I calculate on my own (they are not sent by the form). How can I add additional values before saving?
so, form send 'user' and 'comment' values, I want add 'article', 'ip_address' before save to DB
models.py
class Comments(models.Model):
article = models.ForeignKey(Articles, on_delete=models.CASCADE)
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
comment = models.TextField(verbose_name=_('Comment'))
submit_date = models.DateTimeField(_('Created'), auto_now_add=True)
ip_address = models.CharField(_('IP address'), max_length=50)
is_public = models.BooleanField(verbose_name=_('Publish'), default=False)
serializers.py
class CommentsSerializer(serializers.ModelSerializer):
user = serializers.ReadOnlyField(source='user.first_name')
class Meta:
model = Comments
fields = ('user', 'comment')
views.py
class AddCommentViewSet(viewsets.ModelViewSet):
queryset = Comments.objects.all()
serializer_class = CommentsSerializer
You have to override create() method:
class CommentsSerializer(serializers.ModelSerializer):
user = serializers.ReadOnlyField(source='user.first_name')
class Meta:
model = Comments
fields = ('user', 'comment')
def create(self, validated_data):
new_comment = models.Comment()
new_comment.user = validated_data['user']
new_comment.comment = validated_data['comment']
new_comment.article = get_your_article_somehow()
new_comment.ip_address = get_your_ip_address_somehow()
new_comment.save()
return new_comment
I am trying to update a field in Admin but it raises Validation Error from clean method which I have defined as follows in forms.py:
class BasePhoneFormSet(BaseInlineFormSet):
def clean(self):
super(BasePhoneFormSet, self).clean()
if any(self.errors):
return
phone_numbers = []
for form in self.forms:
if form.cleaned_data.get('number') in phone_numbers:
raise forms.ValidationError(
'Duplicate Entry')
phone_numbers.append(form.cleaned_data.get('number'))
PhoneFormSet = inlineformset_factory(
Post,
Phone,
formset=BasePhoneFormSet,
form=PostForm,
fields = ('number',),
can_delete=False, # admin still shows delete next to the phone number
extra=0,
validate_min=True,
min_num=1,
)
This code works in the views , but in the admin, I can't update or add any phone number since it raises the same ValidationError for duplicate entry.
here is my models.py
class Post(TimeStampedModel, models.Model):
unique_id = models.CharField(max_length=6, unique=True)
user = models.ForeignKey(User, related_name='posts')
city = models.ForeignKey(City, related_name='posts')
class Phone(TimeStampedModel, models.Model):
number = models.CharField(
validators=[phone_regex], max_length=15)
post = models.ForeignKey(Post)
And this is admin.py
class PhoneInline(admin.StackedInline):
model = Phone
formset = PhoneFormSet
class PostAdmin(admin.ModelAdmin):
inlines = [
PhoneInline,
]
I looked into BaseInlineFormSet in models.forms but I got confused more.
class PhoneInline(admin.StackedInline):
model = Phone
formset = BasePhoneFormSet
fields = ('number',)
can_delete = False
extra = 0
min_num = 1
I'm trying to create a form where the user can select multiple technician. When I add the line technician = forms.SelectMultiple(label='Technicians Involved') to my forms.py I get a big blank box with no data. How can I populate that box with the technicians from the User model?
models.py
class Incident(models.Model):
user_id = models.ForeignKey(User, related_name='user')
technician = models.ForeignKey(User, related_name='technician')
capa = models.CharField('capa number', max_length=9)
forms.py
class IncidentForm(forms.ModelForm):
###################### TRYING! ################################
technician = forms.SelectMultiple(label='Technicians Involved')
###############################################################
class Meta:
model = Incident
fields = [ 'user_id',
'technician',
'capa',
]
views.py
def report_incident(request):
template = "report.html"
if request.method == 'POST':
form = IncidentForm(request.POST)
if form.is_valid():
# Auto capturing logged in user
incident = form.save(False)
incident.user_id = request.user
incident.save()
return HttpResponseRedirect('/incidents/')
else:
form = IncidentForm() #an unbound form
return render(request, template, {'form': form})
************** UPDATE WITH CORRECTIONS I MADE BELOW *********************
models.py
class Incident(models.Model):
user_id = models.ForeignKey(User, related_name='user')
technician = models.ManyToManyField(User, related_name='technician')
capa = models.CharField('capa number', max_length=9)
forms.py
class IncidentForm(forms.ModelForm):
technician = forms.SelectMultiple()
class Meta:
model = Incident
fields = [ 'user_id',
'technician',
'capa',
]
views.py
No changes
admin.py
Changes made to view multiple technicians per incident in the admin interface.
class IncidentAdmin(admin.ModelAdmin):
list_display = ('id',
'user_id',
'capa',
'get_technicians'
)
def get_technicians(self):
return "\n".join([t.technicians for t in obj.technician.all()])
Try this out
class IncidentForm(forms.ModelForm):
technician = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple(), queryset=User.objects.all())
class Meta:
model = Incident
fields = [
'technician',
'capa',
]