I have two models: Feed and User
A User can create a Feed with a POST Method. Other Users can see this feed, and every time a user sees a feed, the feed object should update and save the user's id in 'seen_by_users'.
class User(models.Model):
registered = models.DateTimeField(auto_now_add=True)
last_login = models.DateTimeField(auto_now=True)
class Feed(models.Model):
owner = models.ForeignKey(User, blank=False, related_name='feed_owner') # required
feed_message = models.CharField(max_length=255, blank=False, default='')
created = models.DateTimeField(auto_now_add=True, blank=False) # required
seen_by_users = models.ForeignKey(User, blank=True, null=True, related_name='seen_by_users')
in serializers I have:
class FeedSerializer(serializers.ModelSerializer):
class Meta:
model = Feed
fields = ('id', 'owner', 'feed_message', 'created', 'seen_by_users')
def create(self, validated_data):
feed = Feed.objects.create(**validated_data)
return feed
def update(self, instance, validated_data):
instance.seen_by_users = validated_data.get('seen_by_users', instance.seen_by_users)
instance.save()
return instance
For now, I can just save one user Id to seen_by_users but,
how can I change or edit my Model or Serializer to adding an array of users to seen_by_users. It should work when I updating a Feed.
I'm using Django 1.7.1 with Django Rest Framework 3.0.
You could create some custom middleware for your app the sets a session with the user's id when they access the view for the feed.Then you can access the id in your view and save it to the database; you'll probably need a many-to-many relationship in your database; e.g. many users can view a feed and vice versa - Middleware info
You may consider creating a Signal for the updating of your database each time a user views a feed - Signals info
Related
The Viewset def list looks like this:
class ThreeDimensionalModelViewSet(viewsets.ViewSet):
serializer_class = ThreeDimensionalModelSerializer
queryset = ThreeDimensionalModel.objects.all()
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
def list(self, request):
models = ThreeDimensionalModel.objects.all()
serializer = ThreeDimensionalModelSerializer(models, many=True)
print(request.user.id)
return Response(serializer.data)
The serializer looks like this:
class ThreeDimensionalModelSerializer(serializers.ModelSerializer):
class Meta:
model = ThreeDimensionalModel
fields = ['File', 'Uploaded', 'Owner', 'Previous', 'SharedWithUser']
read_only_fields = ['Owner']
The model looks like this:
class ThreeDimensionalModel(models.Model):
File = models.FileField(upload_to='models')
Owner = models.ForeignKey('auth.User', on_delete=models.SET_NULL, null=True, related_name='Owner')
Uploaded = models.DateTimeField(auto_now_add=True)
Previous = models.ForeignKey("self", on_delete=models.SET_NULL, default=None, null=True)
SharedWithUser = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, related_name='SharedWithUser')
When a user requests models at /api/models it should only show the models that are the same owner Id as his.
If no additional data is sent with that request then obviously you can't filter by user.
The straightforward way to do it is that for logged in users the cookie will contain user information such as userId.
When your endpoint recognizes the user who made the requested is logged in, it will use that as the filter for the query instead of all() as seen in the Django docs
https://docs.djangoproject.com/en/3.2/topics/db/queries/#retrieving-specific-objects-with-filters
To summarize - if the user is not logged in (or supplies the information as part of the request in some way) then the request is anonymous and there is no way to know who made it
I have a ReportModel in my django app with 2 field create_user (represents the user that created the report) and write_user (represents the user that last modified the report). I want to automatically save that two fields according to the user that is logged in on django admin site . How do I do that?
Here is the definition of the model
class ReportModel(models.Model):
name = models.CharField(verbose_name=_("Nombre"), max_length=50, blank=False, null=False)
location = models.PointField(verbose_name=_("LocalizaciĆ³n"), srid=4326, blank=False, null=False)
report_type_id = models.ForeignKey("ReportTypeModel", verbose_name=_("Tipo"),
blank=True, null=True, on_delete=models.SET_NULL,
related_name="reports")
start_date = models.DateField(verbose_name=_("Fecha inicio"))
end_date = models.DateField(verbose_name=_("Fecha fin"))
create_user = models.ForeignKey(User, on_delete=models.CASCADE,
related_name='+', verbose_name=_('Creado por'), editable=False, null=True, blank=True)
write_user = models.ForeignKey(User, on_delete=models.CASCADE,
related_name='+', verbose_name=_('Modificado por'), editable=False, null=True, blank=True)
def __str__(self):
return self.name
you can override the create and update methods in your serializer. In the methods before you call the super class update and create methods, you can add the fiels by your self from the request.user
something like
def create(self, validated_data):
"""
Overriding the default create method of the Model serializer.
:param validated_data: data containing all the details of your model
:return: returns a successfully created record
"""
validated_data.update({"create_user": request.user})
# call super class create method here by passing the modified validated_data
return student
In order to capture/record the user who performed a create/update on a model in the django admin, override the save_model method on the admin view.
In the ReportModel admin view declared in admin.py file, override the save_model method as follows:
from models import ReportModel
from django.contrib import admin
#admin.register(ReportModel)
class ReportModelAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
if not obj.pk:
obj.create_user = request.user #create_user should only be set once
obj.write_user = request.user #write_user can be set at all times
super().save_model(request, obj, form, change)
Reference: How to associate model with current user while saving
I've created a Many-to-Many relationship for the model UserProfile, to enable users to grant access to a particular feature to one another. The relationship works as expected with the use of symmetrical=False to ensure a user access is one-way.
Model
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
phone = models.IntegerField(blank=True, null=True)
image = models.ImageField(upload_to='profile_image', default="default_thumbnail.jpg")
department = models.ForeignKey(DepartmentModel, on_delete=models.SET_NULL, null=True)
allow_booking_access = models.ManyToManyField("self", blank=True, symmetrical=False)
def __str__(self):
return self.user.username
class UserInline(admin.StackedInline):
model = UserProfile
can_delete = False
verbose_name_plural = 'UserAccounts'
class UserAccount(BaseUserAdmin):
inlines = (UserInline,)
I am able to query the users that a particular user wants to grant access to via: (for example id=1)
UserProfile.objects.get(id=1).allow_booking_access.all()
However, I would like to retrieve the users that have granted access to the particular user.
How would I do this?
Additional Information
Using Relation
Database Information
You can filter with:
UserProfile.objects.filter(allow_booking_access=my_user)
With your sample data, it will return the UserProfile with id=7 for this query.
or if you want to query in reverse:
UserProfile.objects.filter(userprofile=my_user)
With your sample data, it will return the UserProfiles with id=7, id=3, user=4 and user=7 for this query.
I am working on developing a Trello-like website with Django Rest Framework.
I want to add selected users to BoardAccess model, a through table for User model and Board model, two of which are in Many to Many relationship. Being added to BoardAccess table will mean that the respective users will be having access to matching boards.
Models.py
class Board(models.Model):
name = models.CharField(max_length=50)
access_granted = models.ManyToManyField(User, through='BoardAccess', related_name='access_boards')
team = models.ForeignKey(Team, on_delete=models.CASCADE) # a team can have many boards
class BoardAccess(models.Model):
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
board = models.ForeignKey('Board', on_delete=models.CASCADE)
For User, I am currently using Django's default Auth User model and extending it with a Profile model via OneToOne Field.
Serializers.py
class BoardAccessSerializer(serializers.ModelSerializer):
members = serializers.SerializerMethodField()
added_users = # ???
new_name = serializers.CharField(
write_only=True, required=False, source='name') # in case of requests for renaming the board
def get_members(self, instance):
members = User.objects.filter(profile__team=instance.team)
return UserBoardSerializer(members, many=True).data
I would like to know what field / relations / another serializer should be assigned to added_users, which I think should be write_only=True, in order to successfully de-serialize input from the client-side containing primary keys of selected users.
get_members() method is used to first display information of all team members, from which a client will select users to be added to the board.
Views.py
class BoardAccessRetrieveUpdateAPIView(generics.RetrieveUpdateAPIView):
serializer_class = BoardAccessSerializer
permission_classes = [IsAuthenticated]
def get_queryset(self):
team_id = self.kwargs.get('team_id')
team = get_object_or_404(Team, id=team_id)
queryset = Board.objects.select_related(
'team').prefetch_related(
'access_granted').filter(team=team)
return queryset
I am new to DRF, so there may be a lot of points to be improved from the above. I would really appreciate every help!!
You can override the update method in your serializer, and get the user ids from the client side from initial_data
def update(self, instance, validated_data):
// do the actions on create
users = self.initial_data.get('users')
instance.access_granted.add(*users)
instance.save()
return instance
Also when using ModelSerializer have to add Meta class:
class BoardAccessSerializer(serializers.ModelSerializer):
class Meta:
model = Board
fields = "__all__"
All my models on the database should be filtered by user, always. I created for all my models a field owner which I get the user from the request and fill it in when I'm creating the models.
When I go to all urls they are filtered correctly, as well as when I create them onto the database.
But the problem is when I use the html interface to insert a model on the database, all the related items (it doesn't matter the user) are listed on the foreign key field.
My view
class TransactionList(generics.ListCreateAPIView):
serializer_class = TransactionSerializer
permission_classes = (permissions.IsAuthenticated,)
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
def get_queryset(self):
return Transaction.objects.filter(owner=self.request.user)
My serializer
class TransactionSerializer(serializers.ModelSerializer):
class Meta:
model = Transaction
fields = ('id', 'date', 'description',
'value', 'account', 'envelope', 'bill',)
My model
class Transaction(models.Model):
date = models.DateField(auto_now=True)
description = models.CharField(max_length=100)
value = models.DecimalField(max_digits=10, decimal_places=2)
account = models.ForeignKey(Account, on_delete=models.DO_NOTHING)
envelope = models.ForeignKey(Envelope, on_delete=models.DO_NOTHING, null=True)
bill = models.ForeignKey(Bill, on_delete=models.DO_NOTHING, null=True)
owner = models.ForeignKey('auth.User', related_name='transactions')
For example, with those items when I open the page for inserting the data, all the other accounts (which are restricted for user, too) appear on the combo.
How do I filter related fields for the HTML forms?
And how do I validate if related objects are not from other user?