How to remove fields from serializer - django-rest-framework

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

Related

Django Crispy Form With Dynamically Defined Field

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'))

Updating object using super().update()

I have an object, whose attributes I would like to update. Right now, I am able to update a single attribute eg: name. But the object has several attributes which include name, contact_name, contact_email and contact_phone_number.The following is what I have at the moment.
In views.py
class MerchantViewSet(GetPrefixedIDMixin, viewsets.ModelViewSet):
"""POST support for /merchants/."""
print ("in MerchantViewSet")
queryset = models.Merchant.objects.all()
serializer_class = serializers.CreateMerchantSerializer
lookup_field = "id"
# lookup_value_regex = f"{models.Merchant.id_prefix}_[a-f0-9]{32}"
lookup_value_regex = ".*"
permission_classes = [permissions.MerchantPermission]
def get_queryset(self):
"""Filter the queryset based on the full merchant name or starting with a letter."""
queryset = models.Merchant.objects.all()
search_param = self.request.query_params.get("search", None)
if search_param:
if search_param.startswith("^"):
queryset = queryset.filter(name__istartswith=search_param[1:])
else:
queryset = queryset.filter(name__icontains=search_param)
return queryset
def update(self, request, *args, **kwargs):
request.data["user"] = request.user.id
print (self.get_object().name)
print (request.data)
merchant = self.get_object()
print (response)
print (merchant.name)
for merchants in models.Merchant.objects.all():
print (merchants.id)
if (merchants.id == merchant.id):
merchants.name = request.data["name"]
merchants.save()
I've tried using
response = super(MerchantViewSet, self).update(request, *args, **kwargs)
from what I read in the DRF documentations but using this just returns error 404 when I run my test. Do I simply have to do with I did with name in my code above, with the other attributes? Or is there a more streamlined way to do this?
This is my test:
class MerchantsViewSetTest(tests.BigETestCase): # noqa
#classmethod
def setUpClass(cls): # noqa
super(MerchantsViewSetTest, cls).setUpClass()
cls.application = tests.get_application()
tests.create_group("merchant")
cls.consumer_user = tests.create_consumer()
cls.admin = tests.create_administrator()
cls.merchant_geraldine = models.Merchant.objects.create(
name="Test Account 1",
contact_name="Geraldine Groves",
contact_email="geraldine#example.com",
contact_phone_number="+35310000000",
)
cls. merchant_barbara = models.Merchant.objects.create(
name="Account 2",
contact_name="Barbara",
contact_email="barbara#example.com",
contact_phone_number="+35310000432",
)
def test_edit_merchant(self): # noqa
url = reverse("bige_transactions:merchant-detail", kwargs={'id': self.merchant_geraldine.prefixed_id})
# payload
data = {"name": "Edited"}
# Put data
resp_data = self.put(url, data, user=self.admin, status_code=200)
# Check if data was updated
url = reverse("bige_transactions:merchant-list")
# Try without authenticated user
self.get(url, status_code=401)
# Try with authenticated admin user
resp_data = self.get(url, user=self.admin, status_code=200)
print (resp_data)

DRF getstream empty notifications

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?

Filtering with DjangoRestMultipleModels

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.

Django get_initial not working

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

Resources