I have something working but I am sure it's not the best way of doing it because I have duplicated code.
It's a widget to display checkboxes for groups that clients can belong to. A client can belong to multiple groups.
I am sure I have messed up the overloading of the widget somehow.
models.py
class Client(models.Model):
name = models.CharField(u'Name', max_length=250, unique=True)
groups = models.ManyToManyField('ClientGroup', related_name="client")
def __unicode__(self):
return self.name
class ClientGroup(models.Model):
name = models.CharField(u'Name', max_length=250, unique=True)
def __unicode__(self):
return self.name
forms.py
# -*- coding: utf-8 -*-
from django import forms
from models import ClientGroup
class ClientGroupForm(forms.ModelForm):
class Meta:
model = ClientGroup
fields = ('groups',)
groups = forms.ModelMultipleChoiceField(queryset=ClientGroup.objects.all(),
widget=forms.CheckboxSelectMultiple(),
label='',
required=False)
def __init__(self, client_id = None, *args, **kwargs):
super(ClientGroupForm, self).__init__(*args, **kwargs)
if client_id:
self.fields['groups'] = forms.ModelMultipleChoiceField(queryset = ClientGroup.objects.all(),
initial=ClientGroup.objects.filter(client = client_id),
widget=forms.CheckboxSelectMultiple(),
label='',
required=False)
def __unicode__(self):
return self.groups
views.py
def client(request, pk = 0):
client={}
if pk != 0:
client = Client.objects.get(pk = pk)
groupsForm = ClientGroupForm(pk)
context = {'client':client, 'groupsForm': groupsForm}
return render(request, 'client.html', context)
Can anyone show me a better way of coding the forms.py?
Thanks
You could replace
class ClientGroupForm(forms.ModelForm):
# stuff
def __init__(self, client_id = None, *args, **kwargs):
super(ClientGroupForm, self).__init__(*args, **kwargs)
if client_id:
self.fields['groups'] = forms.ModelMultipleChoiceField(queryset = ClientGroup.objects.all(),
initial=ClientGroup.objects.filter(client = client_id),
widget=forms.CheckboxSelectMultiple(),
label='',
required=False)
with
class ClientGroupForm(forms.ModelForm):
# stuff
def __init__(self, *args, **kwargs):
self.client_id = kwargs.get('client_id', None)
super(ClientGroupForm, self).__init__(*args, **kwargs)
if client_id:
self.fields['groups'].queryset = ClientGroup.objects.filter(client=client_id)
Related
class Post(models.Model):
cat_post = models.ForeignKey(Category, on_delete=models.CASCADE, blank=True,null=True)
top_post = models.ForeignKey(TopicsCategory, on_delete=models.CASCADE, blank=True,null=True)
sub_post = models.ForeignKey(SubTopicsCategory, on_delete=models.CASCADE, blank=True,null=True)
class CreatePostView(CreateView):
model = Post
template_name = 'blog/create.html'
form_class = CreatePostForm
def get_context_data(self, *args, **kwards):
print(self.kwargs)
context = super(CreatePostView, self).get_context_data(**kwards)
context['btn'] = 'Add'
return context
def form_valid(self, form, *args, **kwargs):
if self.kwargs.get('category_slug') and len(self.kwargs) == 1:
category = Category.objects.get(slug=self.kwargs['category_slug'])
form.instance.cat_post = category
return super(CreatePostView, self).form_valid(form)
# передача в форму kwargs view
def get_form_kwargs(self):
kwargs = super(CreatePostView, self).get_form_kwargs()
kwargs.update({'view_kwargs': self.kwargs})
return kwargs
def get_success_url(self):
return reverse('topics_category_list', kwargs={'category_slug': self.kwargs['category_slug'], })
class CreatePostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['name', 'text', 'discussion']
# widgets = {
# 'cat_post': forms.HiddenInput(),
# }
def __init__(self, *args, **kwargs):
self.request = kwargs.pop("view_kwargs")
super(CreatePostForm, self).__init__(*args, **kwargs)
def clean_name(self):
name = self.cleaned_data['name']
if self.request.get('category_slug') and len(self.request) == 1:
category = Category.objects.get(slug=self.request['category_slug'])
unique = Post.objects.filter(slug=slugify(self.cleaned_data['name']), cat_post=category.pk,discussion=False).exists()
if unique:
raise ValidationError(f'Post is not unique')
return name
**
I have duplicate sources in db here form_valid and clean_name.
How do I pass the form in the view form form_valid class instance that I got from the database to clean_name.
There will be posts for 2 models and requests will increase
I would like to use a custom form field with an UpdateView. My code so far is:
models.py
class CustomUser(AbstractUser):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
paper = models.BooleanField(default=False)
pronouns = models.CharField(max_length=50, blank=True)
def __str__(self):
return self.username
forms.py
class CustomUserProfileForm(forms.ModelForm):
pronouns = forms.CharField(label='Pronouns', required=True)
class Meta:
model = get_user_model()
fields = ('first_name', 'last_name')
def __init__(self, *args, **kwargs):
_pronoun_list = ('he/him/his', 'she/her/hers', 'they/them/theirs')
super(CustomUserProfileForm, self).__init__(*args, **kwargs)
self.fields['pronouns'].widget = ListTextWidget(
data_list=_pronoun_list, name='pronoun-list')
This form references ListTextWidget although I don't think it directly relates to my issue:
class ListTextWidget(forms.TextInput):
def __init__(self, data_list, name, *args, **kwargs):
super(ListTextWidget, self).__init__(*args, **kwargs)
self._name = name
self._list = data_list
self.attrs.update({'list': 'list__%s' % self._name})
def render(self, name, value, attrs=None, renderer=None):
text_html = super(ListTextWidget, self).render(
name, value, attrs=attrs)
data_list = '<datalist id="list__%s">' % self._name
for item in self._list:
data_list += '<option value="%s">' % item
data_list += '</datalist>'
return (text_html + data_list)
Views.py
class CustomUserProfileview(UpdateView):
model = CustomUser
form_class = CustomUserProfileForm
template_name = 'account/customuser_change_form.html'
success_url = reverse_lazy('home')
def form_valid(self, form):
user = self.request.user
pronouns = form.cleaned_data['pronouns']
user.pronouns = pronouns
user.save()
return super().form_valid(form)
The form is displayed as I would expect, where I can change the first name, last name and choose pronouns from a list. If I print(user) and print(pronouns) I get my expected results, but the pronouns field is not being saved to the user. Even if it did save, I get the feeling that I'm not leveraging the UpdateView correctly.
I want to use uniqueness validation in class-based views.
Here I have createView where I want to add part_no uniqueness validation at the time of form post.
How can we achieve this?
Any solutions.
Views.py
class SparePartsCreate(CreateView):
template = 'maint/spareparts_form.html'
model = SpareParts
fields = ['name', 'description', 'part_no']
success_url = reverse_lazy('spare_parts')
form.py
class SparePartForm(forms.ModelForm):
name = forms.CharField(required=True, label='Spare Part Name')
description = forms.CharField(required=True, label='Spare Part Description')
part_no = forms.CharField(required=True, label='Spare Part Number', max_length=6)
class Meta:
model = SpareParts
fields = ['name','description','part_no']
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super(SparePartForm, self).__init__(*args, **kwargs)
As we implement validation in function-based views in form.py under clean method.
For class-based views anything is there?
def clean_part_no(self):
part_no = self.cleaned_data.get('part_no')
qs = SpareParts.objects.filter(part_no=part_no)
if qs.exists():
raise forms.ValidationError('This part_no already taken, please use a different one.')
return part_no
either use this way in your forms.py or make it as unique=True in models.py file
class SparePartForm(forms.ModelForm):
name = forms.CharField(required=True, label='Spare Part Name')
description = forms.CharField(required=True, label='Spare Part Description')
part_no = forms.CharField(required=True, label='Spare Part Number', max_length=6)
class Meta:
model = SpareParts
fields = ['name','description','part_no']
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super(SparePartForm, self).__init__(*args, **kwargs)
def clean_part_no(self, value):
""" here you can validate the data """
if True:
return value
else:
raise forms.validationError("error message ")
Although it is in the title, I want to change the form dynamically with django.
But now I get an error.
I can't deal with it.
I was able to get user information, but if I filter it, it will be “cannot unpack non-iterable UPRM object”.
#forms.py
class RecordCreateForm(BaseModelForm):
class Meta:
model = URC
fields = ('UPRC','URN','UET','URT',)
def __init__(self, *args, **kwargs):
user = kwargs.pop('user')
super(RecordCreateForm,self).__init__(*args, **kwargs)
for field in self.fields.values():
field.widget.attrs['class'] = 'form-control'
self.fields['URN'].choices = UPRM.objects.filter(user=user)
#views.py
class RecordCreate(CreateView):
model = URC
form_class = RecordCreateForm
template_name = 'records/urcform.html'
success_url = reverse_lazy('person:home')
def get_form_kwargs(self):
kwargs = super(RecordCreate, self).get_form_kwargs()
# get users, note: you can access request using: self.request
kwargs['user'] = self.request.user
return kwargs
#models
class UPRM(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
URN = models.CharField( max_length=30,editable=True)
def __str__(self):
return self.URN
class URC(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
UPRC = models.CharField(max_length=300)
URN = models.ForeignKey(UPRM, on_delete=models.CASCADE)
def __str__(self):
return self.UPRC
cannot unpack non-iterable UPRM object
You should use queryset instead of choices here:
class RecordCreateForm(BaseModelForm):
class Meta:
model = URC
fields = ('UPRC','URN','UET','URT',)
def __init__(self, *args, **kwargs):
user = kwargs.pop('user')
super(RecordCreateForm,self).__init__(*args, **kwargs)
for field in self.fields.values():
field.widget.attrs['class'] = 'form-control'
self.fields['URN'].queryset = UPRM.objects.filter(user=user)
I created an update screen for django. However, although it redirects to successURL, the data has not been updated. I don't know why.
I need your help.
I will post it if necessary.
#view
class RecordDetailEdit(UpdateView,LoginRequiredMixin):
template_name = 'records/detail_edit.html'
model = URC
form_class = RecordDetailEditForm
pk_url_kwarg = 'id'
success_url = reverse_lazy('person:home')
def get_object(self):
return get_object_or_404(User, pk=self.request.user.user_id)
def get_form_kwargs(self):
kwargs = super(RecordDetailEdit, self).get_form_kwargs()
# get users, note: you can access request using: self.request
kwargs['user'] = self.request.user
return kwargs
#form
class RecordDetailEditForm(forms.ModelForm):
class Meta:
model = URC
fields = ('UPRC','URN','UET','URT')
def __init__(self, *args, **kwargs):
user = kwargs.pop('user')
super(RecordDetailEditForm, self).__init__(*args, **kwargs)
self.fields['URN'].queryset = UPRM.objects.filter(user=user)
#model
class URC(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
UPRC = models.CharField(max_length=300)
URN = models.ForeignKey(UPRM, on_delete=models.CASCADE)
UET = models.DurationField(editable=True)
URT = models.DateTimeField(default=timezone.now,editable=True)
group = models.ForeignKey(group, on_delete=models.CASCADE, null=True)
def __str__(self):
return self.UPRC
#url
path('<id>/edit/', views.RecordDetailEdit.as_view(), name='record_detail_edit'),
I changed it to the following.
def get_object(self, queryset=None):
obj = URC.objects.get(id=self.kwargs['id'])
return obj