django rest framework: Dynamic serializer and ViewSet - serialization

I'm new to django and django rest framework as a disclaimer.
I have a Model that contains metadata columns like last modified date and last modified user. This data should be available in the API for viewing but will be set automatically by the backend and hence must not be required for creation/update. As far as I understood I can create a dynamic serializer as shown in the docs.
However how can I use a dynamic serialize on a ViewSet? Or is that simply not possible?

If you want the last modified date and last modified user to be read only, you do not need to create a DynamicSerializer. All you need to do is to set the fields as read_only on the serializer.
class MyModelSerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
fields = (fields exposed to the API)
read_only_fields = ("last_modified_date", "last_modified_user")
After creating the serializer, it must be added to the ViewSet
class MyModelViewSet(viewsets.ModelViewSet):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer

Related

How should I pass a raw query response to a Serializer class?

I am trying to fetch data using raw sql query but I am facing issues when I am trying to pass the raw sql response to the Serializer class.
Serializer
class User_Serializer(serializers.ModelSerializer):
class Meta:
model = Users
fields = '__all__'
View
class UserView(APIView):
def get(self, request, emailId, format=None):
with connection.cursor() as cursor:
cursor.execute("SELECT * FROM users")
resRow = cursor.fetchone()
serializerResponse = User_Serializer(resRow)
return Response(serializerResponse.data)
I realise that the Serializer class cannot work with the ModelSerialzier class in this scenerio. How should I build my Serializer considering the fact that I need to post and save data to the concerned model using this Serializer class.
Instead of creating a connection manually use your model manager's raw method. It will return a RawQuerySet instance and will be iterable just like regular QuerySet. Also all the records that was fetched from db will be a model instance. You can use it like:
users = User.objects.raw("SELECT * FROM users_user")
serializer = UserSerializer(users, many=True)
serializer.data
Don't forget to check out raw sql documentation.

What is the best way to get all linked instances of a models in Django?

I am trying to create a messaging system in Django, and I came across an issue: How could I efficiently find all messages linked in a thread?
Let's imagine I have two models:
class Conversation(models.Model):
sender = models.ForeignKey(User)
receiver = models.ForeignKey(User)
first_message = models.OneToOneField(Message)
last_message = models.OneToOneField(Message)
class Message(models.Model):
previous = models.OneToOneField(Message)
content = models.TextField()
(code not tested, I'm sure it wouldn't work as is)
Since it is designed as a simple linked list, is it the only way to traverse it recursively?
Should I try to just get the previous of the previous until I find the first, or is there a way to query all of them more efficiently?
I use Rest Framework serializer with depth. So If you have serializer with Depth value to 3. I will fetch the full model of whatever the foreign key available until three parents.
https://www.django-rest-framework.org/api-guide/serializers/#specifying-nested-serialization
class AppliedSerializer(serializers.ModelSerializer):
class Meta:
model = Applied
fields = ("__all__")
depth = 3

Wagtail: Extend page model

I have created in the past multiple pages for Wagtail.
Example:
class PlainPage(Page):
body = StreamField(BasicStreamBlock, null=True, blank=True)
content_panels = Page.content_panels + [
StreamFieldPanel('body'),
]
Now I would like to an extend all this pages by giving them the possibility to set them to no-index.
For this reason I would like to add a boolean field to the promote_panel.
What would be the best way adding this feature to all pages I have already created?
no_index = models.BooleanField(default=False)
promote_panels = Page.promote_panels + [
FieldPanel('no_index'),
]
What would be the correct Wagtail way, to extend all my Page classes with this code?
Using Django's Class Mixins, it is possible to add fields to all existing models without too much hassle.
1. Create a Mixin
First - create a new CustomPageMixin (name this whatever you want) that extends the Page model and has the meta abstract=True set.
class CustomPageMixin(Page):
class Meta:
abstract=True
no_index = models.BooleanField(default=False)
# adding to content_panels on other pages will need to use THIS promote_panels
# e.g. promote_panels = CustomPageMixin.promote_panels + [...]
promote_panels = Page.promote_panels + [
FieldPanel('no_index'),
]
2. Update ALL existing page models
Update all your models in use to use the mixin, instead of extending the Page class, they will actually extend your mixin directly.
from ... import CustomPageMixin
class StandardPage(CustomPageMixin):
#...
class HomePage(CustomPageMixin):
#...
3. Run Migrations
Note: This will add the no_index field to ALL pages that now extend your new mixin.
./manage.py makemigrations
./manage.py migrate
Potential Issues with this approach
This may not be the best way to do this, as it is a bit indirect and hard to understand at first glance.
This does not actually change the Page model fields, so it will only be available when you access the actual specific models' instance via Page.specific
It will be a bit more tricky to use this for special Page types such as AbstractEmailForm.

Django REST framework flat, read-write serializer

In Django REST framework, what is involved in creating a flat, read-write serializer representation? The docs refer to a 'flat representation' (end of the section http://django-rest-framework.org/api-guide/serializers.html#dealing-with-nested-objects) but don't offer examples or anything beyond a suggestion to use a RelatedField subclass.
For instance, how to provide a flat representation of the User and UserProfile relationship, below?
# Model
class UserProfile(models.Model):
user = models.OneToOneField(User)
favourite_number = models.IntegerField()
# Serializer
class UserProfileSerializer(serializers.ModelSerializer):
email = serialisers.EmailField(source='user.email')
class Meta:
model = UserProfile
fields = ['id', 'favourite_number', 'email',]
The above UserProfileSerializer doesn't allow writing to the email field, but I hope it expresses the intention sufficiently well. So, how should a 'flat' read-write serializer be constructed to allow a writable email attribute on the UserProfileSerializer? Is it at all possible to do this when subclassing ModelSerializer?
Thanks.
Looking at the Django REST framework (DRF) source I settled on the view that a DRF serializer is strongly tied to an accompanying Model for unserializing purposes. Field's source param make this less so for serializing purposes.
With that in mind, and viewing serializers as encapsulating validation and save behaviour (in addition to their (un)serializing behaviour) I used two serializers: one for each of the User and UserProfile models:
class UserSerializer(serializer.ModelSerializer):
class Meta:
model = User
fields = ['email',]
class UserProfileSerializer(serializer.ModelSerializer):
email = serializers.EmailField(source='user.email')
class Meta:
model = UserProfile
fields = ['id', 'favourite_number', 'email',]
The source param on the EmailField handles the serialization case adequately (e.g. when servicing GET requests). For unserializing (e.g. when serivicing PUT requests) it is necessary to do a little work in the view, combining the validation and save behaviour of the two serializers:
class UserProfileRetrieveUpdate(generics.GenericAPIView):
def get(self, request, *args, **kwargs):
# Only UserProfileSerializer is required to serialize data since
# email is populated by the 'source' param on EmailField.
serializer = UserProfileSerializer(
instance=request.user.get_profile())
return Response(serializer.data)
def put(self, request, *args, **kwargs):
# Both UserSerializer and UserProfileSerializer are required
# in order to validate and save data on their associated models.
user_profile_serializer = UserProfileSerializer(
instance=request.user.get_profile(),
data=request.DATA)
user_serializer = UserSerializer(
instance=request.user,
data=request.DATA)
if user_profile_serializer.is_valid() and user_serializer.is_valid():
user_profile_serializer.save()
user_serializer.save()
return Response(
user_profile_serializer.data, status=status.HTTP_200_OK)
# Combine errors from both serializers.
errors = dict()
errors.update(user_profile_serializer.errors)
errors.update(user_serializer.errors)
return Response(errors, status=status.HTTP_400_BAD_REQUEST)
First: better handling of nested writes is on it's way.
Second: The Serializer Relations docs say of both PrimaryKeyRelatedField and SlugRelatedField that "By default this field is read-write..." — so if your email field was unique (is it?) it might be you could use the SlugRelatedField and it would just work — I've not tried this yet (however).
Third: Instead I've used a plain Field subclass that uses the source="*" technique to accept the whole object. From there I manually pull the related field in to_native and return that — this is read-only. In order to write I've checked request.DATA in post_save and updated the related object there — This isn't automatic but it works.
So, Fourth: Looking at what you've already got, my approach (above) amounts to marking your email field as read-only and then implementing post_save to check for an email value and perform the update accordingly.
Although this does not strictly answer the question - I think it will solve your need. The issue may be more in the split of two models to represent one entity than an issue with DRF.
Since Django 1.5, you can make a custom user, if all you want is some method and extra fields but apart from that you are happy with the Django user, then all you need to do is:
class MyUser(AbstractBaseUser):
favourite_number = models.IntegerField()
and in settings: AUTH_USER_MODEL = 'myapp.myuser'
(And of course a db-migration, which could be made quite simple by using db_table option to point to your existing user table and just add the new columns there).
After that, you have the common case which DRF excels at.

How to display only specific columns of a table in entity framework?

how to display the some specific columns of table instead of whole table in entity framework.
using (DataEntities cxt = new DataEntities())
{
notes note = cxt.notes.Where(no => no.id == accID).SingleOrDefault();
return notes;
}
For this purpose, I would suggest you to make use of ViewModel like following :-
notes note = cxt.notes.SingleOrDefault(no => no.id == accID);
var model = new YourViewModel // Your viewModel class
{
ID = note.ID,
PropertyOne = note.PropertyOne, // your ViewModel Property
PropertyTwo = note.PropertyTwo
};
You can do this with QueryView.
This implies editing your model directly in XML as there is no designer support for this, but you will get an independant entity with less fields than the original one.
Advantages:
You can then query data base for this truncated entity directly (you will get only fields you need from the data base - no need to get whole entity from DB and trancate it in code)
It is good in scenarios where you want to send this truncated entity to the
client
with WCF to minimize traffic (e.g. when building big lists on client
that basically need only name and ID and no other entity specific
information).
Disadvantages:
This QueryView-based entity is read only. To make it writeable you will have to add r/w functionality yourself