I have one model name is cityform
i want to get url parmeter in this CityFrom hwo can i do this?
here is my url
path('state/city/<int:id>/', City.as_view(), name="city")
http://localhost:8000/country/state/city/3/
here is my form
class
CityFrom(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(CityFrom,self).__init__(*args, **kwargs)
print(args)
print(kwargs)
self.fields['state'] = forms.ModelChoiceField(
empty_label = 'Select',
queryset = State.objects.all()
)
class Meta:
model = City
fields = ('state', 'name')
in this form i want to access id = 3
here is my view
from django.views import View
class City(View):
def get(self, request, *args, **kwargs):
Forms = CityFrom()
return render(request, 'albums/add.html', {'Forms': Forms})
Pass url parameter as keyword argument from views.py as following.
form = CityFrom(id=kwargs.get("id"))
To get the id in your forms.py, use following code in your form's __init__ method.
self.id = kwargs.get('id')
Your form should look like this.
CityFrom(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.id = kwargs.get('id')
super(CityFrom,self).__init__(*args, **kwargs)
self.fields['state'] = forms.ModelChoiceField(
empty_label = 'Select',
queryset = State.objects.all()
)
class Meta:
model = City
fields = ('state', 'name')
* Call super after getting the id in your form as above. Here order of calling super is important.
Try
CityFrom(forms.ModelForm):
def __init__(self, *args, **kwargs):
self.id = kwargs.pop('id')
super(CityFrom,self).__init__(*args, **kwargs)
Related
I have a cbv create view that displays a modelform.
I want to preselect a foreignkey field which is displayed as select choice field.
My problem is that kwargs.get('building_id') in modelform returns None
class VlanCreateForm(ModelForm):
class Meta:
model = Vlan
fields = ['number','description','network','building']
def __init__(self, *args, **kwargs):
building_id = kwargs.get('building_id')
super().__init__(*args, **kwargs)
self.fields['building'].initial = building_id
building is a foreign key to buildings. If I put a constant like self.fields['building'].initial = 1 it is working
class VlanCreateView(CreateView):
model = Vlan
form_class = VlanCreateForm
and the url is
vlan/building/<int:building_id>/create
so I call it like
vlan/building/1/create
You'll need to define the building id in get_form_kwargs
class VlanCreateView(CreateView):
...
building_id=None
def dispatch(self, request, *args, **kwargs):
# Retrieves the building id from url
self.building_id=kwargs.get("building_id")
return super().dispatch(request, *args, **kwargs)
def get_form_kwargs(self, *args, **kwargs):
kwargs=super().get_form_kwargs(*args, **kwargs)
## Sends building id to the form
kwargs["building_id"]=self.building_id
return kwargs
class VlanCreateForm(ModelForm):
class Meta:
model = Vlan
fields = ['number','description','network','building']
def __init__(self, *args, **kwargs):
self.building_id = kwargs.get('building_id')
super().__init__(*args, **kwargs)
self.fields['building'].initial = self.building_id
def post_url(self):
return reverse('app_name:url_name',kwargs={'cg_id':self.building_id} )
In form post action use this post_url for submit form.
then you got the building_id in your view kwargs
I've tried everything I can find on the internet here, and nothing seems to work, so wondering if lots of the previous answers are for old versions. I'm on Django 2.2.9.
#models.py
class ParentModel(models.Model):
title = models.CharField()
class ChildModel(models.Model):
parent = models.ForeignKey(
ParentModel,
on_delete=models.CASCADE,
related_name='parent'
)
# admin.py
#admin.register(ParentModel)
class ParentModelAdmin(admin.ModelAdmin):
model = ParentModel
def get_queryset(self, request):
return ParentModel.objects.get_complete_queryset()
class ChildModelForm(forms.Form):
def __init__(self, u, *args, **kwargs):
super(ChildModelForm, self).__init__(*args, **kwargs)
self.fields['parent'].queryset = ParentModel.objects.get_complete_queryset()
class Meta:
model = ChildModel
fields = '__all__'
#admin.register(ChildModel)
class ChildModelAdmin(admin.ModelAdmin):
model = ChildModel
form = ChildModelForm
def formfield_for_foreignkey(self, db_field, request, **kwargs):
if db_field.name == "parent":
kwargs["queryset"] = ParentModel.objects.get_complete_queryset()
return super().formfield_for_foreignkey(db_field, request, **kwargs)
I have a manager query called get_complete_queryset on ParentModel that returns a broader set of Parents than the default queryset.
The setup above allows me to go to my ChildModelAdmin and select the 'hidden' Parents from the dropdown, but when I try and save it gives me this error:
parent instance with id 2 does not exist.
There must be some queryset the form is using to save the model that isn't overridden, but I can't find what it is.
You can override get_form method like this:
def get_form(self, request, obj, **kwargs):
form = super(<YourModelAdmin>,self).get_form(request, obj, **kwargs)
form.base_fields['<you_field>'] = forms.ModelChoiceField(queryset=<your_queryset>)
return form
I am trying to make the 'cost_name' field choices to be filtered based on the dynamic project_id.
models.py
class ProjectCost(models.Model):
project_name = models.ForeignKey(ProjectName, on_delete=models.CASCADE,null=True)
cost_name = models.CharField('Cost Name', max_length=50)
total_budget = models.DecimalField('Total Budget', max_digits=9,decimal_places=2)
forms.py
class CreateCostForm(forms.ModelForm):
def __init__(self,project_id,*args, **kwargs):
super(CreateCostForm, self).__init__(*args, **kwargs)
self.fields['cost_name'].queryset = ProjectCost.objects.filter(project_name_id=project_id)
class meta:
model = ProjectCost
When i hard-code the value of project_id like:
self.fields['project_name'].queryset = ProjectCost.objects.filter(project_name_id=4) or
ProjectCost.objects.filter(project_name_id= 8),
i get the correct filtered options on the form.So how can i make project_id dynamic?
i tried:
def __init__(self, *args, **kwargs):
project_id = kwargs.pop('project_id', None)
super(CreateCostForm, self).__init__(*args, **kwargs)
self.fields['cost_name'].queryset = ProjectCost.objects.filter(project_name_id=project_id)
But this returns 'None' for the value of 'project_id'. Any idea on how to fix this?
Thanks.
As you are sub-classing from CreateView, then there is a method call get_form_kwargs() to send data from View to Form. Just override it like this:
class YourView(CreateView):
...
def get_form_kwargs(self, *args, **kwargs):
form_kwargs = super(YourView, self).get_form_kwargs(*args, **kwargs)
form_kwargs['project_id'] = self.kwargs.get('project_id') # assuming you send the project_id through url ie path('project/<int:project_id>/create/', YourView.as_view())
return form_kwargs
In that way you will be get data in project_id in Form:
Class CreateCostForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
project_id = kwargs.pop('project_id', None)
It's possible to use variable inside forms.py? I'm using field with choices based on queryset from Platform model. My url and view contain this id but I don't know how to give this to forms.py to my queryset.
forms.py:
class OrderCreateForm(forms.ModelForm):
platform = forms.CharField(choices=Platform.objects.filter(client_id=variable_from_view_or_url).values_list('id', 'name').order_by('id'))
class Meta:
model = Order
fields = ('price', 'deadline', 'finished', 'client', 'platform')
view.py:
#user_passes_test(lambda u: u.is_staff, login_url='/account/login/')
def order_create(request, request_client_id):
dict = {}
dict['form_order'] = OrderCreateForm()
return render(request, 'panel/order/form.html', dict)
Yes and no.
The way you are doing it you can't but you can define the choices in the init method of the form
def __init__(self, client_id, *args, **kwargs):
super(OrderCreateForm, self).__init__(*args, **kwargs)
self.fields['platform'].choices = Platform.objects.filter(client_id=client_id).values_list('id', 'name').order_by('id')
then call it with an id
OrderCreateForm(request_client_id)
I have a model like so:
class GiveAbsolute(serializers.Field):
def to_native(self,value):
# this where it give an error (self doesn't have request)
# what i want it to give full url
# like: http://www.blabla.com/othermodel/1
return reverse('link_to_othermodel',
args=[value],
request=self.request)
class SomethingSerializer(serializers.ModelSerializer):
# field with foreign key
othermodel = GiveAbsolute(source="othermodel.id")
class Meta:
model=Something
fields("fields1","othermodel")
is there a way to achieve this ?
thanks
From the source
The request object is an entry of the context dictionary. ie.
request = self.context.get('request')
In your case, just do:
self.request = self.context.get('request')
then build the url
self.request.build_absolute_uri(reverse('some_url_name'))
Based on the answer of mariodev, here is a reusable solution for Models ; I use it to provide URLs to service (see them as metheds) on django models.
Reusable components
serializers.py
class RequestAwareSerializer(serializers.ModelSerializer):
"""
A serializer which fields can access the request object.
"""
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super(RequestAwareSerializer, self).__init__(*args, **kwargs)
class APIMethodField(serializers.Field):
""" To get the absolute URL of a method accessible via the API
"""
def __init__(self, url_action_name, *args, **kwargs):
self._url_name = url_action_name
super(APIMethodField, self).__init__(source='*', *args, **kwargs)
def to_native(self, obj):
"""
#param objid the ID of the object
#param method_url_name, the name of the url, as in urls.py
"""
return reverse_lazy(self._url_name, args=[obj.id],
request=self.parent.request)
views.py
class ChattyModelViewSet(ModelViewSet):
""" ModelViewSet which informs the serializer about the request
(abstract)
"""
def get_serializer(self, instance=None, data=None,
files=None, many=False, partial=False):
serializer_class = self.get_serializer_class()
context = self.get_serializer_context()
return serializer_class(instance, data=data, files=files, many=many,
partial=partial, context=context,
request=self.request)
Example use
urls.py
url(r'^v1/maildomain/(?P<maildomain_id>\d+)/check/$',
views.MailDomainDetail.as_view(), name='maildomain_dns_check')
serializers.py
class MailDomainSerializer(RequestAwareSerializer):
checkdns_url = APIMethodField(url_action_name='maildomain_dns_check')
class Meta:
model = MailDomain()
fields = ('name', 'checkdns_url')
views.py
class MailDomainView(ChattyModelViewSet):
model = MailDomain
serializer_class = MailDomainSerializer
The only thing in DRF, that has an access to request object is the view, so you need to figure out how to pass your request from view to serializer, for example in generic ListView you can use get_serializer.
Then, when you already have it in your serializer, you can use self.parent (which is a parent serializer) to capture it from the field itself:
class GiveAbsolute(serializers.Field):
def to_native(self,value):
return reverse('link_to_othermodel',
args=[value],
request=self.parent.request)
class SomethingSerializer(serializers.ModelSerializer):
# field with foreign key
othermodel = GiveAbsolute(source="othermodel.id")
class Meta:
model=Something
fields=("fields1","othermodel")
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request', None)
super(SomethingSerializer, self).__init__(*args, **kwargs)
class SomethingView(generics.ListAPIView):
model = Something
serializer_class = SomethingSerializer
def get_serializer(self, instance=None, data=None,
files=None, many=False, partial=False):
serializer_class = self.get_serializer_class()
context = self.get_serializer_context()
return serializer_class(instance, data=data, files=files, many=many,
partial=partial, context=context, request=self.request)