Django get_initial is not populating product field in the form. I am expecting a drop down, with the queryset results as defined in the get_initial overridden function.
class PurchaseRequestDetailForm(forms.ModelForm):
class Meta:
model = PurchaseRequestDetail
fields = ["product", "variations", "quantity", "fulfilled", "vat", "discount", "surcharges", "active"]
exclude = ("purchase_request", )
class PurchaseRequestDetailCreateView(CreateView):
model = PurchaseRequestDetail
form_class = PurchaseRequestDetailForm
template_name = "inventory/purchaserequestdetail_form.html"
def get_pr_obj(self):
pr_id = self.request.session["pr_id"]
return PurchaseRequest.objects.get(id=pr_id)
def get_initial(self):
initial = super(PurchaseRequestDetailCreateView, self).get_initial()
try:
pr_obj = self.get_pr_obj()
initial["product"] = pr_obj.vendor.vendors_products.all()
except KeyError:
pass
self.form_class(initial)
return initial
template:
<td>{{ form.product|css_class:"form-control" }}</td>
An easy way to set a ModelChoiceField queryset is to set the field attribute in the form init();
class PurchaseRequestDetailForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
# Get initial data passed from the view
self.product = None
if 'product' in kwargs['initial']:
self.product = kwargs['initial'].pop('product')
super(PurchaseRequestDetailForm, self).__init__(*args, **kwargs)
self.fields['product'].queryset = self.product
class Meta:
model = PurchaseRequestDetail
fields = ["product", "variations", "quantity", "fulfilled", "vat", "discount", "surcharges", "active"]
exclude = ("purchase_request", )
You should hook in to get_form_kwargs from ModelFormMixin to pass your data to the form.
class PurchaseRequestDetailCreateView(CreateView):
model = PurchaseRequestDetail
form_class = PurchaseRequestDetailForm
template_name = "inventory/purchaserequestdetail_form.html"
def get_pr_obj(self):
pr_id = self.request.session["pr_id"]
return PurchaseRequest.objects.get(id=pr_id)
def get_form_kwargs(self):
"""
Returns the keyword arguments for instantiating the form.
"""
kwargs = super(PurchaseRequestDetailCreateView, self).get_form_kwargs()
kwargs.update(
{'initial':
{'product': pr_obj.vendor.vendors_products.all()}
}
)
return kwargs
Related
from .models import Catagory, CatagoryItems, MiniItems
from rest_framework import serializers
class MiniItemsSerializer(serializers.ModelSerializer):
class Meta:
Mini = serializers.StringRelatedField(read_only=False,many=True)
model = MiniItems
fields ="__all__"
read_only_fields = ("Mini","id")
depth=2
def validate_url(self, value):
if value and len(value) > 0:
raise serializers.ValidationError('Error')
return value
def create(self, validated_data):
if "catagory" in validated_data:
del validated_data["catagory"]
return Message.objects.create(**validated_data)
class CatagoryItemsSerializer(serializers.ModelSerializer):
class Meta:
items = serializers.ListField(child=MiniItemsSerializer())
model = CatagoryItems
fields ="__all__"
read_only_fields = ("id","items")
# def validate_url(self, value):
# if value and len(value) > 0:
# raise serializers.ValidationError('Error')
# return value
# def create(self, validated_data):
# if "catagory" in validated_data:
# del validated_data["catagory"]
# return Message.objects.create(**validated_data)
class CatagorySerializer(serializers.ModelSerializer):
class Meta:
ser = serializers.SerializerMethodField('removt')
catagoryItems =serializers.SlugRelatedField(
many=True,
read_only=True,
slug_field='name'
)
id = serializers.Field()
model = Catagory
fields =("id","name","desc","status","catagoryItems",)
read_only_fields = ("catagoryItems",)
depth=1
def removet(self, *args, **kwargs):
super(CatagorySerializer, self).__init__(*args, **kwargs)
if 'catagory' in kwargs:
if 'request' in kwargs['catagory']:
tabs = kwargs['catagory']['request'].query_params.getlist('catagory', [])
if tabs:
# tabs = tabs.split(',')
# included = set(tabs)
existing = set(self.fields.keys())
for other in existing - included:
self.fields.pop(other)
You should use exclude, here are the docs
I would like to define a Django crispy form with two statically defined fields (name and description) and one dynamically defined field (enum_value). I do it like this:
class DataTypeForm(forms.Form):
name = forms.CharField()
description = forms.CharField(widget=forms.Textarea)
def __init__(self, *args, **kwargs):
self.mode = kwargs.pop('mode')
super(DataTypeForm, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.wrapper_class = 'row'
self.helper.label_class = 'col-md-2'
self.helper.field_class = 'col-md-8'
self.helper.add_input(Submit('submit', 'Submit'))
self.fields['enum_value'] = forms.CharField()
The dynanic field enum_value is defined in the last line. Unfortunately, this does not work as expected: the form is rendered with the two static fields (name and description) but the dynamic field enum_value is not visible. The problem seems to lie in the use of the FormHelper class. If I modify my example as follows:
class DataTypeForm(forms.Form):
name = forms.CharField()
description = forms.CharField(widget=forms.Textarea)
def __init__(self, *args, **kwargs):
self.mode = kwargs.pop('mode')
super(DataTypeForm, self).__init__(*args, **kwargs)
# self.helper = FormHelper(self)
# self.helper.wrapper_class = 'row'
# self.helper.label_class = 'col-md-2'
# self.helper.field_class = 'col-md-8'
# self.helper.add_input(Submit('submit', 'Submit'))
self.fields['enum_value'] = forms.CharField()
then, things work as expected and all three fields in my form are correctly rendered. Is there any way I can get the dynamically defined field correctly rendered even when using the FormHelper class?
Placing the dynamic field enum_value before the creation of the FormHelper should work.
class DataTypeForm(forms.Form):
name = forms.CharField()
description = forms.CharField(widget=forms.Textarea)
def __init__(self, *args, **kwargs):
self.mode = kwargs.pop('mode')
super(DataTypeForm, self).__init__(*args, **kwargs)
self.fields['enum_value'] = forms.CharField()
self.helper = FormHelper(self)
self.helper.wrapper_class = 'row'
self.helper.label_class = 'col-md-2'
self.helper.field_class = 'col-md-8'
self.helper.add_input(Submit('submit', 'Submit'))
I'm trying to get a proof of concept of Django Rest Framework on getstream working to power inapp notifications.
My code https://github.com/morenoh149/django-rest-framework-getstream
models.py
class Snippet(models.Model, Activity):
created_at = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=100, blank=True, default='')
code = models.TextField()
linenos = models.BooleanField(default=False)
language = models.CharField(
choices=LANGUAGE_CHOICES, default='python', max_length=100)
style = models.CharField(
choices=STYLE_CHOICES, default='friendly', max_length=100)
owner = models.ForeignKey(
'auth.User', related_name='snippets', on_delete=models.CASCADE)
highlighted = models.TextField()
#property
def activity_actor_attr(self):
return self.owner
#property
def activity_notify(self):
return [feed_manager.get_notification_feed(self.owner_id)]
class Meta:
ordering = ('created_at', )
def save(self, *args, **kwargs):
"""
Use the `pygments` library to create a highlighted HTML
representation of the code snippet.
"""
lexer = get_lexer_by_name(self.language)
linenos = self.linenos and 'table' or False
options = self.title and {'title': self.title} or {}
formatter = HtmlFormatter(
style=self.style, linenos=linenos, full=True, **options)
self.highlighted = highlight(self.code, lexer, formatter)
super(Snippet, self).save(*args, **kwargs)
serializers.py
from django.contrib.auth.models import User from rest_framework import serializers
from snippets.models import Snippet
class SnippetSerializer(serializers.HyperlinkedModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')
highlight = serializers.HyperlinkedIdentityField(
view_name='snippet-highlight', format='html')
class Meta:
model = Snippet
fields = ('url', 'id', 'highlight', 'owner', 'title', 'code',
'linenos', 'language', 'style')
class ActivitySerializer(serializers.Serializer):
id = serializers.UUIDField()
foreign_id = serializers.CharField()
verb = serializers.CharField()
time = serializers.DateTimeField()
def __init__(self, *args, **kwargs):
object_serializer = kwargs.pop("object_serializer", None)
actor_serializer = kwargs.pop("actor_serializer", None)
super().__init__(self, *args, **kwargs)
if object_serializer:
self.fields["object"] = object_serializer()
else:
self.fields["object"] = serializers.CharField()
if actor_serializer:
self.fields["actor"] = actor_serializer()
else:
self.fields["actor"] = serializers.CharField()
class AggregatedSerializer(ActivitySerializer):
group = serializers.CharField()
activities = ActivitySerializer(many=True)
class NotificationSerializer(AggregatedSerializer):
is_seen = serializers.BooleanField()
is_read = serializers.BooleanField()
def get_activity_serializer(data, object_serializer=None, actor_serializer=None, **kwargs):
kwargs["object_serializer"] = object_serializer
kwargs["actor_serializer"] = actor_serializer
serializer = ActivitySerializer
if "is_seen" in data:
serializer = NotificationSerializer
elif "activities" in data:
serializer = AggregatedSerializer
return serializer(data, **kwargs)
views.py
class NotificationViewSet(viewsets.ViewSet):
"""
This viewset returns a notifications feed for the logged in user.
The feed contains events for when a relevant snippet is created.
"""
serializer_class = NotificationSerializer
def list(self, request):
feeds = feed_manager.get_news_feeds(self.request.user.id)
activities = feeds.get('timeline_aggregated').get()['results']
enriched_activities = enricher.enrich_aggregated_activities(activities)
serializer = get_activity_serializer(enriched_activities, SnippetSerializer, None, many=True)
return Response(serializer.data)
How do I get the /notifications/ endpoint to return the notifications for the signed in user?
In my app, i have a chained dropdown in which i am getting the second dropdown via jquery ajax, which works well.So i am trying to edit this saved data and load it back to an edit form, but the dropdown is showing empty. This is what i have done so far
Here is my model.py
class SchoolFees(models.Model):
fid = models.ForeignKey(FacultyData, on_delete= models.SET_NULL, null=True)
did = models.ForeignKey(DepartmentData, on_delete= models.SET_NULL, null=True)
sid = models.ForeignKey(SessionData, on_delete= models.SET_NULL, null=True)
amount = models.CharField(max_length=30)
def __str__(self):
return self.amount
forms.py
class FeesCreationForm(forms.ModelForm):
fid = forms.ModelChoiceField(queryset=FacultyData.objects.all(), empty_label="--Select Faculty--",
widget=forms.Select(attrs={'class': 'form-control'}))
did = forms.ModelChoiceField(queryset=DepartmentData.objects.all(), empty_label="--Select Faculty First--",
widget=forms.Select(attrs={'class': 'form-control'}))
sid = forms.ModelChoiceField(queryset=SessionData.objects.all(), empty_label="--Select Session--",
widget=forms.Select(attrs={'class': 'form-control'}))
class Meta:
model = models.SchoolFees
fields = ['sid', 'fid', 'did', 'amount']
widgets = {
'amount': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Enter Amount'})
}
def __init__(self, *args, **kwargs):
super(FeesCreationForm, self).__init__(*args, **kwargs)
self.fields['did'].queryset = DepartmentData.objects.none()
# Get did queryset for the selected fid
if 'fid' in self.data:
try:
fd = int(self.data.get('fid'))
self.fields['did'].queryset = DepartmentData.objects.filter(fid_id=fd).order_by('id')
except (ValueError, TypeError):
pass # invalid input from the client; ignore and use empty queryset
Here is my view.py
def edit_fee(request, pk):
app = settings.CONFIG
post = get_object_or_404(SchoolFees, pk=pk)
if request.method == 'POST':
form = FeesCreationForm(request.POST, instance=post)
if form.is_valid():
form.save()
messages.add_message(request, messages.WARNING, "Fees record updated successfully")
return redirect('bursary:create_fee')
else:
# bring edit form out
form = FeesCreationForm(instance=post)
table = FeesTable(SchoolFees.objects.all())
RequestConfig(request, paginate={'per_page': 10}).configure(table)
context = {"form": form, "fees": table, 'app': app}
return render(request, 'editfee.html', context)
I expect that the saved value is pass to the dropdown with other form fields which are already showing
After going through this post, i was able to solve it when reading the comments. All i needed was to add a backward relationship to my init function.
class FeesCreationForm(forms.ModelForm):
fid = forms.ModelChoiceField(queryset=FacultyData.objects.all(), empty_label="--Select Faculty--",
widget=forms.Select(attrs={'class': 'form-control'}))
did = forms.ModelChoiceField(queryset=DepartmentData.objects.all(), empty_label="--Select Faculty First--",
widget=forms.Select(attrs={'class': 'form-control'}))
sid = forms.ModelChoiceField(queryset=SessionData.objects.all(), empty_label="--Select Session--",
widget=forms.Select(attrs={'class': 'form-control'}))
class Meta:
model = models.SchoolFees
fields = ['sid', 'fid', 'did', 'amount']
widgets = {
'amount': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Enter Amount'})
}
def __init__(self, *args, **kwargs):
super(FeesCreationForm, self).__init__(*args, **kwargs)
self.fields['did'].queryset = DepartmentData.objects.none()
# Get did queryset for the selected fid
if 'fid' in self.data:
try:
fd = int(self.data.get('fid'))
self.fields['did'].queryset = DepartmentData.objects.filter(fid_id=fd).order_by('id')
except (ValueError, TypeError):
pass # invalid input from the client; ignore and use empty queryset
elif self.instance.pk:
self.fields['did'].queryset = self.instance.fid.departmentdata_set.order_by('id')
#backward relation - for this faculty selected, check its deparm
#every department has its faculty
# #in other word, which dept has their foreign key pointing to the current instance of faculty
According to the relevant documentation "Django Rest Frameworks default Filter Backends work out of the box" with DjangoRestMultipleModels. So, I'd expect the following code to work:
class AllModelSummary(MultipleModelAPIView):
filter_backends = (SearchFilter,DjangoFilterBackend,)
search_fields = ('name','description',)
#filter_fields = ('is_foo','is_bar',) # Everything breaks when this is uncommmented
flat = True
def get_queryList(self):
queryList = (
(Foo.objects.all(), FooSerializerMiniList),
(Bar.objects.all(), BarSerializerMiniList)
)
return queryList
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
Here's an example of one of those serializers:
class BarSerializerMiniList(serializers.ModelSerializer):
is_foo = serializers.SerializerMethodField()
is_bar = serializers.SerializerMethodField()
def get_is_foo(self,obj):
return False
def get_is_bar(self,obj):
return True
class Meta:
model = Bar
fields = ('pk','name','description','is_bar','is_foo')
The search fields do exactly what they're supposed to do, but if I define filter_fields in the API then I am greeted by this:
'Meta.fields' contains fields that are not defined on this FilterSet: is_foo, is_bar
Any suggestions as to what might be going wrong here would be welcome.
In the end I had to work around the issue as follows:
class AllModelSummary(MultipleModelAPIView):
...
def get_querylist(self):
types = self.request.query_params['types']
queryList = ()
if types:
for t in types.split(','):
if t == 'foo':
queryList = queryList + ((Foo.objects.all(), FooSerializerMiniList),)
elif t == 'bar':
queryList = queryList + ((Bar.objects.all(), BarSerializerMiniList),)
else:
queryList = (
(Foo.objects.all(), FooSerializerMiniList),
(Bar.objects.all(), BarSerializerMiniList),
)
return queryList
Then, appending ?types=foo,bar to the URL does the trick.