Is it possible to add authentication on the basis of single model? - python

models.py:
import datetime
from django.db import models
from pygments.lexers import get_all_lexers
LEXERS = [item for item in get_all_lexers() if item[1]]
class Classname(models.Model):
class_name = models.CharField(max_length=8)
def __str__(self):
return self.class_name
class Sectionname(models.Model):
class_name = models.ForeignKey(Classname)
section_name = models.CharField(max_length=1, default='A')
def __str__(self):
return self.section_name
class Teachername(models.Model):
classname = models.ForeignKey(Classname, verbose_name='class Name')
secname = models.ForeignKey(Sectionname, verbose_name='sectionname')
teachname = models.CharField(max_length=50, verbose_name='teacher Name')
def __str__(self):
return self.teachname
class Attendancename(models.Model):
teacher_name = models.ForeignKey(Teachername)
date = models.DateField('Date')
intime = models.TimeField('IN-TIME')
outtime = models.TimeField('OUT-TIME')
def hours_conversion(self):
tdelta = (datetime.datetime.combine(datetime.date.today(),self.outtime) - datetime.datetime.combine(datetime.date.today(),self.intime))
hours, minutes = tdelta.seconds//3600, (tdelta.seconds//60)%60
return '{0}hrs {1}mins'.format(hours, minutes)
def __str__(self):
return "%s" %self.teacher_name
serializers.py:
from django.forms import widgets
from rest_framework import serializers
from .models import Classname, Sectionname, Teachername, Attendancename
class ClassSerializer(serializers.ModelSerializer):
class Meta:
model = Classname
fields = ('id', 'class_name',)
class SectionSerializer(serializers.ModelSerializer):
class Meta:
model = Sectionname
fields = ('id', 'class_name', 'section_name')
class TeacherSerializer(serializers.ModelSerializer):
class Meta:
model = Teachername
fields = ('id', 'classname', 'secname', 'teachname')
class AttendanceSerializer(serializers.ModelSerializer):
class Meta:
model = Attendancename
fields = ('id', 'teacher_name', 'date', 'intime', 'outtime')
I want to add owner field in my models to enforce DRF authentication system. Is it necessary to add 'owner' field to all my models above?
I'm following a tutorial on django-rest-framework I have several models as above. Is it possible to make a single model for this authentication purpose and to set permissions in serializers file as per that model & to access all models on the basis of that single model?

I want to add owner field in my models to enforce DRF authentication system
You don't need the owner field to "enforce" the authentication.
How to enable and handle authentication in DRF is explained here in all details: http://www.django-rest-framework.org/api-guide/authentication/
The owner field is only interesting for certain permission cases.
If you look at the docs, you'll see that DRF already ships with permissions for common cases like IsAuthenticated, IsAdmin and many more. Depending on the state of a user (logged in / logged out) he or she might see certain resources or not.
However, if you want to set object level permissions you need the owner field (or something comparable).
How else can you tell if a certain user is really associated with a certain object?
For all this the default User model (from django.contrib.auth) should be completely sufficient and I see no need for any extra models assuming you use one of the standard Authentication Backends which set request.user to an instance of User.

Related

Django REST: Custom field, list may not be empty

I'm trying to add the employees field to my custom user model in Django REST 2.2. This is how I implemented my custom user (first answer). The employees field is just a list of custom users (so it's related to itself, with a many-to-many relationship).
When I try to add a custom user model from the django interface, it says "this list may not be empty". How can I make it so it can be empty? I thought that's what I added "required=False" for.
users/models.py
class CustomUser(AbstractUser):
employees = models.ManyToManyField("self", related_name='employees')
users/serializers.py (CustomRegisterSerializer is used for registering with rest-auth, CustomUserSerializer is used to view and edit)
class CustomRegisterSerializer(RegisterSerializer):
employees = serializers.RelatedField(many=True, required=False, queryset=CustomUser.objects.all())
def get_cleaned_data(self):
data_dict = super().get_cleaned_data()
data_dict['employees'] = self.validated_data.get('employees', '')
return data_dict
class CustomUserSerializer(serializers.ModelSerializer):
class Meta:
model = CustomUser
fields = ('id', 'email', 'employees')
users/views.py
class CustomUserViewSet(viewsets.ModelViewSet):
queryset = CustomUser.objects.all()
serializer_class = CustomUserSerializer

500 error: null value in column "timeline_id" violates not-null constraint

I'm currently a student and am trying to create a full stack web application with python/django and React. While building my back-end I have run into a problem where, when posting an object containing an association, the association's id is lost between the response payload and the database. I know that the state is updating as it should and that other objects that don't use associations on the back-end can be created without a problem. I assume my mistake has to be somewhere in the models or serializers that I made, but so far I haven't found it.
500 error message:
Integrity error at "api/v1/event"
null value in column "timeline_id" violates not-null constraint
DETAIL: failing row contains (index_id, junk_data, junk_data, 1, null)
my models:
from django.db import models
class Timeline(models.Model):
name = models.CharField(max_length=50, default='n/a')
def __str__(self):
return self.name
class Event(models.Model):
name = models.CharField(max_length=25, default='n/a')
description = models.CharField(max_length=150, default='n/a')
coordinate = models.IntegerField(default=0)
timeline = models.ForeignKey(Timeline, on_delete=models.CASCADE, related_name="events")
def __str__(self):
return self.name
class Note(models.Model):
article = models.TextField(default='n/a')
event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name='notes')
# event = models.ManyToManyField(Event)
def __str__(self):
return self.article
my views:
from rest_framework import viewsets
from .serializers import TimelineSerializer, EventSerializer, NoteSerializer
from .models import Timeline, Event, Note
class TimelineView(viewsets.ModelViewSet):
queryset = Timeline.objects.all()
serializer_class = TimelineSerializer
class EventView(viewsets.ModelViewSet):
queryset = Event.objects.all()
serializer_class = EventSerializer
class NoteView(viewsets.ModelViewSet):
queryset = Note.objects.all()
serializer_class = NoteSerializer
my serializers:
from rest_framework import serializers
from .models import Timeline, Note, Event
class NoteSerializer(serializers.ModelSerializer):
class Meta:
model = Note
fields = ('id', 'title', 'article')
class EventSerializer(serializers.ModelSerializer):
notes = NoteSerializer(many=True, read_only=True)
class Meta:
model = Event
fields = ('id', 'name', 'description', 'coordinate', 'notes')
class TimelineSerializer(serializers.ModelSerializer):
events = EventSerializer(many=True, read_only=True)
class Meta:
model = Timeline
fields = ('id', 'name', 'events')
Link to the github repo:
https://github.com/dantehollo/world_builder_site
I am using python 3.6.8 on linux (ubuntu 18.04.3)
I tried to be as specific and brief as possible. If there is something missing let me know and I will post it as soon as I see the request. Any help with what this is, why it happened and how to avoid it again is greatly appreciated, thank you.
According to your Event model timeline attribute (which is also a foreign key) is required and can not be null. And you forgot to add this timeline into fields of EventSerializer:
class EventSerializer(serializers.ModelSerializer):
notes = NoteSerializer(many=True, read_only=True)
class Meta:
model = Event
fields = ('id', 'name', 'description', 'coordinate', 'notes', 'timeline')
Now if you do not send timeline in the request, DRF will give ValidationError that you have to include it.

Django rest framework displaying specific field of a model

In my model:
from django.contrib.auth.models import User
class Restaurant(models.Model):
manager = models.ForeignKey(User, on_delete=models.PROTECT,
null=True, blank=False, related_name="manager")
in my serializers.py
class RestaurantSerializer(CoreHyperlinkedModelSerializer):
class Meta:
model = Restaurant
in my views.py
class RestaurantViewSet(viewsets.ModelViewSet):
queryset = Restaurant.objects.order_by('id').all()
serializer_class = RestaurantSerializer
on my list:
the manager is displaying as <rest_framework.relations.PKOnlyObject object at 0x9f7040xbc208>
How can I display it as normal data like its username?
You want to use a 'SlugRelatedField'.
There are a few ways you can go, but if you just want to show a username, all you need is this
from rest_framework import serializers
class RestaurantSerializer(serializers.ModelSerializer):
manager = serializers.CharField(source="manager.username")
class Meta:
model = Restaurant
if you inherit from ModelSerializer and skip the manager field, it will use user PK as the value of the manager field by default.
a slightly more involved way would be to define a separate serializer for User and then embed it in RestaurantSerializer.
from rest_framework import serializers
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
class RestaurantSerializer(serializers.ModelSerializer):
manager = UserSerializer()
class Meta:
model = Restaurant
And if you really want to use hyperlinked serializer, you need to do quite a bit of work. You need to read this part carefully http://www.django-rest-framework.org/api-guide/serializers/#how-hyperlinked-views-are-determined

How to serialize hierarchical relationship in Django REST

I have a Django model that is hierarchical using django-mptt, which looks like:
class UOMCategory(MPTTModel, BaseModel):
"""
This represents categories of different unit of measurements.
"""
name = models.CharField(max_length=50, unique=True)
description = models.CharField(max_length=50, unique=True)
parent = TreeForeignKey('self', null=True, blank=True, related_name='%(app_label)s_%(class)s_sub_uom_categories')
The problem now is I created a REST API using Django REST Framework; how do I make sure that parent field returns serialized data?
Here is the Model Serializer:
class UOMCategorySerializer(BaseModelSerializer):
"""
REST API Serializer for UOMCategory model
"""
class Meta:
model = UOMCategory
In DRF you can use a serializer as a field in another serializer. However, recursion is not possible.
Tom Christie posted a solution on another question (Django rest framework nested self-referential objects). His solution will also work with your problem.
In your UOMCategorySerializer.Meta class you specify the fields you want to use, also list the parent and/or children field(s) there. Then you use Tom Christies solution.
In your case this would give:
class UOMCategorySerializer(ModelSerializer):
class Meta:
model = UOMCategory
fields = ('name', 'description', 'parent', 'children')
Tom Christies solution: By specifying what field to use for parent and/or children, you avoid using too much (and possibily endless) recursion:
UOMCategorySerializer.base_fields['parent'] = UOMCategorySerializer()
UOMCategorySerializer.base_fields['children'] = UOMCategorySerializer(many=True)
The above works for me in a similar situation.
Simple DRF API view using MPTT cache and DRF serializer.
from rest_framework import serializers
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response
from events.models import Category
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = (
"name",
"slug",
)
class CategoryTreeView(GenericAPIView):
serializer_class = CategorySerializer
def get(self, request, *args, **kwargs):
root_nodes = Category.objects.all().get_cached_trees()
data = []
for n in root_nodes:
data.append(self.recursive_node_to_dict(n))
return Response(data)
def recursive_node_to_dict(self, node):
result = self.get_serializer(instance=node).data
children = [self.recursive_node_to_dict(c) for c in node.get_children()]
if children:
result["children"] = children
return result

Django Admin: Ordering of ForeignKey and ManyToManyField relations referencing User

I have an application that makes use of Django's UserProfile to extend the built-in Django User model. Looks a bit like:
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
# Local Stuff
image_url_s = models.CharField(max_length=128, blank=True)
image_url_m = models.CharField(max_length=128, blank=True)
# Admin
class Admin: pass
I have added a new class to my model:
class Team(models.Model):
name = models.CharField(max_length=128)
manager = models.ForeignKey(User, related_name='manager')
members = models.ManyToManyField(User, blank=True)
And it is registered into the Admin:
class TeamAdmin(admin.ModelAdmin):
list_display = ('name', 'manager')
admin.site.register(Team, TeamAdmin)
Alas, in the admin inteface, when I go to select a manager from the drop-down box, or set team members via the multi-select field, they are ordered by the User numeric ID. For the life of me, I can not figure out how to get these sorted.
I have a similar class with:
class Meta:
ordering = ['name']
That works great! But I don't "own" the User class, and when I try this trick in UserAdmin:
class Meta:
ordering = ['username']
I get:
django.core.management.base.CommandError: One or more models did not validate:
events.userprofile: "ordering" refers to "username", a field that doesn't exist.
user.username doesn't work either. I could specify, like image_url_s if I wanted to . . . how can I tell the admin to sort my lists of users by username? Thanks!
This
class Meta:
ordering = ['username']
should be
ordering = ['user__username']
if it's in your UserProfile admin class. That'll stop the exception, but I don't think it helps you.
Ordering the User model as you describe is quite tricky, but see http://code.djangoproject.com/ticket/6089#comment:8 for a solution.
One way would be to define a custom form to use for your Team model in the admin, and override the manager field to use a queryset with the correct ordering:
from django import forms
class TeamForm(forms.ModelForm):
manager = forms.ModelChoiceField(queryset=User.objects.order_by('username'))
class Meta:
model = Team
class TeamAdmin(admin.ModelAdmin):
list_display = ('name', 'manager')
form = TeamForm
This might be dangerous for some reason, but this can be done in one line in your project's models.py file:
User._meta.ordering=["username"]
For me, the only working solution was to use Proxy Model. As stated in the documentation, you can create own proxy models for even built-in models and customize anything like in regular models:
class OrderedUser(User):
class Meta:
proxy = True
ordering = ["username"]
def __str__(self):
return '%s %s' % (self.first_name, self.last_name)
After that, in your model just change Foreign Key to:
user = models.OneToOneField(OrderedUser, unique=True)
or even more suitable
user = models.OneToOneField(OrderedUser, unique = True, parent_link = True)

Categories