Queryset in __init__ Form Django - python

class PaymentSelectForm(forms.Form):
date_from = forms.DateField()
date_to = forms.DateField()
website = ModelChoiceField()
paymentmethod = forms.ChoiceField(choices=PAYCODE_CHOICES)
def __init__(self, *args, **kwargs):
super(PaymentSelectForm, self).__init__(*args, **kwargs)
applyClassConfig2FormControl(self)
self.fields['website'].queryset=Website.objects.all()
I have errors: TypeError: __init__() missing 1 required positional argument: 'queryset'. How can I use Queryset in __init__ Form?

Unless there is some information you are currently hiding, you better declare the queryset in the declaration of the ModelChoiceField:
class PaymentSelectForm(forms.Form):
date_from = forms.DateField()
date_to = forms.DateField()
website = ModelChoiceField(queryset=Website.objects.all())
paymentmethod = forms.ChoiceField(choices=PAYCODE_CHOICES)
def __init__(self, *args, **kwargs):
super(PaymentSelectForm, self).__init__(*args, **kwargs)
applyClassConfig2FormControl(self)
In case the queryset is dynamic (this is not the case here), you can set it to None initially, and then overwrite it in the __init__ function:
class PaymentSelectForm(forms.Form):
date_from = forms.DateField()
date_to = forms.DateField()
website = ModelChoiceField(queryset=None)
paymentmethod = forms.ChoiceField(choices=PAYCODE_CHOICES)
def __init__(self, *args, **kwargs):
super(PaymentSelectForm, self).__init__(*args, **kwargs)
applyClassConfig2FormControl(self)
self.fields['website'].queryset=Website.objects.all()
But this is usually the case if for instance the queryset depends on parameters that are passed to the form, or it depends on other tables (and it can not be written into an SQL query elegantly).

Use widget.choices
def __init__(self, *args, **kwargs):
super(PaymentSelectForm, self).__init__(*args, **kwargs)
applyClassConfig2FormControl(self)
self.fields['website'].widget.choices=(
(choice.pk, choice) for choice in Website.objects.all()
)

Related

Django create form field with a model of the current user

I have a simple app, where a user has multiple businesses, and each business has multiple products, what I´m trying to do is a make product creatView, where i can select a business from the ones owned by the current user. I tryed editing the init() method of the ModelForm like this:
class Producto_Form(forms.ModelForm):
class Meta:
model = Producto_Model
fields = ("Nombre_Producto","Negocio","Descripcion_Producto",'Precio_Producto','Tags',"Foto")
def __init__(self, *args, **kwargs):
super(Producto_Form, self).__init__(*args, **kwargs)
self.fields['Negocio'].queryset = Negocio_Model.objects.all().filter(Administrador_id=kwargs['user'].id)
and then i changed the get_form_kwargs from the create product view like this:
class crear_producto(LoginRequiredMixin, CreateView):
template_name = "tienda/crear_producto.html"
form_class= Producto_Form
success_url = reverse_lazy('tienda_app:crear_producto')
login_url = reverse_lazy('register_app:logIn')
def get_form_kwargs(self, *args, **kwargs):
kwargs = super().get_form_kwargs(*args, **kwargs)
kwargs['user'] = self.request.user
return kwargs
I was following this question but I keep getting the error __init__() got an unexpected keyword argument 'user'
So everything is almost fine but you must pass the user variable to the form init as the kwargs, also, on the queryset dont call it like kwargs['user'] and just call user, something like this:
def __init__(self, user, *args, **kwargs):
super(Producto_Form, self).__init__(*args, **kwargs)
self.fields['Negocio'].queryset = Negocio_Model.objects.all().filter(Administrador_id=user.id)
also I changed the super() constructor on the get_form_kwargslike this:
def get_form_kwargs(self, *args, **kwargs):
kwargs = super(crear_producto, self).get_form_kwargs(*args, **kwargs)
kwargs['user'] = self.request.user
return kwargs

Form Problems - Setting Initial Value

I am trying to set the initial value of a field on a form. The field is not part of the model, but when I try and set it to a value the field is blank. From my research it could be because the form is "bound" which makes some sense to me, but in this case the field is not part of the model.
My form:
#Form for editing profile
class CatForm(forms.ModelForm):
pictureid = forms.CharField()
class Meta:
model = Cat
fields = ['name']
def __init__(self, *args, **kwargs):
picid = kwargs.pop("pictureid")
print(picid)
super(CatForm, self).__init__(*args, **kwargs)
self.fields['pictureid'] = forms.CharField(initial=picid, required=False)
The model:
class Cat(models.Model):
name = models.CharField(max_length=34,null=False)
From the view it is called like this:
catform = CatForm(request.POST, pictureid=instance.id)
I was expecting it to set the field to the value of the initial attribute, but it doesn't. I have tried testing it by directly adding a string, but doesn't set.
This is what seems to be working for me:
class CatForm(forms.ModelForm):
class Meta:
model = Cat
fields = ['name']
def __init__(self, *args, **kwargs):
picid = kwargs.pop("pictureid")
super(CatForm, self).__init__(*args, **kwargs)
self.fields['pictureid'] = forms.CharField(initial=picid)
I also needed to drop the "request.POST" from the call to this when initiating the form.
If you want to render the pictureid in GET request, then you can try like this:
catform = CatForm(initial={'pictureid': instance.id})
For GET request, you don't need to override the __init__ method.
But, if you want to use the Catform in POST request, to use the value of pictureid somewhere else(lets say in save method), then you will need to override __init__ method here.
class CatForm(forms.ModelForm):
pictureid = forms.CharField()
class Meta:
model = Cat
fields = ['name']
def __init__(self, *args, **kwargs):
picid = kwargs.pop("pictureid")
print(picid)
super(CatForm, self).__init__(*args, **kwargs)
self.pictureid = picid
def save(self, *args, **kwargs):
print(self.pictureid) # if you want to use it in save method
return super().save(*args, **kwargs)

Django Crispy form set model field as required

I have a modelform in which I want to set required attribute to True for email validation
field:-email
class RegisterMyBuisinessForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.helper = FormHelper()
self.helper.form_method = 'post'
self.helper.form_action = '/registermybuisness/'
Field('email', type='email')
self.helper.add_input(Submit('submit', 'Submit',css_class="btn c-theme-btn c-btn-square c-btn-bold c-btn-uppercase"))
super(RegisterMyBuisinessForm, self).__init__(*args, **kwargs)
class Meta:
model = RegistermyBusiness
fields = ['name','email', 'org_name', 'contact','business_description','store_address','message','store_landmark','business_type','city']
I tried
self.fields['email'].required=True
this resulted in class RegisterMyBuisinessForm doesnot have fields error
You can alter self.fields['email'] in the __init__ method. You need to call super() first.
class RegisterMyBuisinessForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
...
super(RegisterMyBuisinessForm, self).__init__(*args, **kwargs)
self.fields['email'].required = True
...

Django TypeError

I get an error with model like this:
class Project(models.Model): # Should Rename to Project Name
project_name = models.CharField(max_length=50)
frequency = models.PositiveIntegerField(blank=True)
related_tests = models.ManyToManyField(TestType)
creation_date = models.DateField()
def __init__(self, *args, **kwargs):
super().__init__(self, *args, **kwargs)
self.creation_date = datetime.date.today()
Error: int() argument must be a string, a bytes-like object or a number, not 'Project'
When I comment out,
creation_date = models.DateField()
def __init__(self, *args, **kwargs):
super().__init__(self, *args, **kwargs)
self.creation_date = datetime.date.today()
...the code works.
My question is, what is prompting the error?
You don't need to pass self to __init__ with super:
super().__init__(*args, **kwargs)
Or in python 2, you should do:
super(Project, self).__init__(*args, **kwargs)

Creating a dynamic choice field

I'm having some trouble trying to understand how to create a dynamic choice field in django. I have a model set up something like:
class rider(models.Model):
user = models.ForeignKey(User)
waypoint = models.ManyToManyField(Waypoint)
class Waypoint(models.Model):
lat = models.FloatField()
lng = models.FloatField()
What I'm trying to do is create a choice Field whos values are the waypoints associated with that rider (which would be the person logged in).
Currently I'm overriding init in my forms like so:
class waypointForm(forms.Form):
def __init__(self, *args, **kwargs):
super(joinTripForm, self).__init__(*args, **kwargs)
self.fields['waypoints'] = forms.ChoiceField(choices=[ (o.id, str(o)) for o in Waypoint.objects.all()])
But all that does is list all the waypoints, they're not associated with any particular rider. Any ideas? Thanks.
you can filter the waypoints by passing the user to the form init
class waypointForm(forms.Form):
def __init__(self, user, *args, **kwargs):
super(waypointForm, self).__init__(*args, **kwargs)
self.fields['waypoints'] = forms.ChoiceField(
choices=[(o.id, str(o)) for o in Waypoint.objects.filter(user=user)]
)
from your view while initiating the form pass the user
form = waypointForm(user)
in case of model form
class waypointForm(forms.ModelForm):
def __init__(self, user, *args, **kwargs):
super(waypointForm, self).__init__(*args, **kwargs)
self.fields['waypoints'] = forms.ModelChoiceField(
queryset=Waypoint.objects.filter(user=user)
)
class Meta:
model = Waypoint
There's built-in solution for your problem: ModelChoiceField.
Generally, it's always worth trying to use ModelForm when you need to create/change database objects. Works in 95% of the cases and it's much cleaner than creating your own implementation.
the problem is when you do
def __init__(self, user, *args, **kwargs):
super(waypointForm, self).__init__(*args, **kwargs)
self.fields['waypoints'] = forms.ChoiceField(choices=[ (o.id, str(o)) for o in Waypoint.objects.filter(user=user)])
in a update request, the previous value will lost!
You can declare the field as a first-class attribute of your form and just set choices dynamically in __init__:
class WaypointForm(forms.Form):
waypoints = forms.ChoiceField(choices=[])
def __init__(self, user, *args, **kwargs):
super().__init__(*args, **kwargs)
waypoint_choices = [(o.id, str(o)) for o in Waypoint.objects.filter(user=user)]
self.fields['waypoints'].choices = waypoint_choices
This approach also works with a ModelChoiceField.
This approach is superior if you are using a ModelForm, and want to override choices of an autogenerated field.
How about passing the rider instance to the form while initializing it?
class WaypointForm(forms.Form):
def __init__(self, rider, *args, **kwargs):
super(joinTripForm, self).__init__(*args, **kwargs)
qs = rider.Waypoint_set.all()
self.fields['waypoints'] = forms.ChoiceField(choices=[(o.id, str(o)) for o in qs])
# In view:
rider = request.user
form = WaypointForm(rider)
If you need a dynamic choice field in django admin; This works for django >=2.1.
class CarAdminForm(forms.ModelForm):
class Meta:
model = Car
def __init__(self, *args, **kwargs):
super(CarForm, self).__init__(*args, **kwargs)
# Now you can make it dynamic.
choices = (
('audi', 'Audi'),
('tesla', 'Tesla')
)
self.fields.get('car_field').choices = choices
car_field = forms.ChoiceField(choices=[])
#admin.register(Car)
class CarAdmin(admin.ModelAdmin):
form = CarAdminForm
Hope this helps.
Underneath working solution with normal choice field.
my problem was that each user have their own CUSTOM choicefield options based on few conditions.
class SupportForm(BaseForm):
affiliated = ChoiceField(required=False, label='Fieldname', choices=[], widget=Select(attrs={'onchange': 'sysAdminCheck();'}))
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
grid_id = get_user_from_request(self.request)
for l in get_all_choices().filter(user=user_id):
admin = 'y' if l in self.core else 'n'
choice = (('%s_%s' % (l.name, admin)), ('%s' % l.name))
self.affiliated_choices.append(choice)
super(SupportForm, self).__init__(*args, **kwargs)
self.fields['affiliated'].choices = self.affiliated_choice
As pointed by Breedly and Liang, Ashok's solution will prevent you from getting the select value when posting the form.
One slightly different, but still imperfect, way to solve that would be:
class waypointForm(forms.Form):
def __init__(self, user, *args, **kwargs):
self.base_fields['waypoints'].choices = self._do_the_choicy_thing()
super(waypointForm, self).__init__(*args, **kwargs)
This could cause some concurrence problems, though.

Categories