I have a python 3.6 + django 1.10 + djangorestframework 3.6.4 project.
I have 2 Model classes called Report and ReportFile. I want to create the CRUD operations to get, post and put those files together with a report.
1 Report has a type (which doesn't really matter here) and can have many ReportFiles that the user should be able to upload.
The modelclasses look like this:
class Report(CreationModificationMixin):
report_type = models.ForeignKey(ReportType, on_delete=models.SET_NULL,
null=True, related_name='issues',
verbose_name='Report', editable=False)
name = models.CharField(max_length=50, blank=True)
class ReportFile(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4)
report = models.ForeignKey(Report, on_delete=models.CASCADE, related_name='files')
uploaded_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, related_name='uploads',
null=True)
file = models.FileField(upload_to=upload_report_to, max_length=500)
and the serializer class:
class ReportSerializer(serializers.ModelSerializer):
files = ReportFileSerializer(many=True)
formats = serializers.SerializerMethodField()
class Meta:
model = Report
fields = ('id', 'name', 'report_type', 'files')
def create(self, validated_data):
rfs_data = validated_data.pop('files')
rf = Report.objects.create(**validated_data)
for rf_data in rfs_data:
ReportFile.objects.create(Report=rf, **rf_data)
return rf
and the ViewSet:
class ReportViewSet(viewsets.ModelViewSet):
serializer_class = ReportSerializer
queryset = Report.objects.all().prefetch_related('report_type')
But I cannot manage to upload the files correctly. Because first I cannot manage to upload that correctly with Postman and I somehow also doubt that this is the correct way to go. Can somebody hint me how I should do this?
Thank you a lot!
Related
Hello I am very new to Django Rest Framework and I am having a hard time with the serializer. I extended the User Model using Abstract User. I inserted two new fields which are is_student and is_teacher then I set both of the values to false as default. I then put them in there own model then just applied a one-to-one relation for each of them to the user model. My problem is with the serializer. How do I make a serializer out of this. I want the student and teacher have relation with the user model as well as having the ability to do http actions such as get, post, put, etc.
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.conf import settings
# Create your models here.
class User(AbstractUser):
is_student = models.BooleanField(default=False)
is_teacher = models.BooleanField(default=False)
class Course(models.Model):
name = models.CharField(max_length=200)
description = models.TextField()
price = models.FloatField()
def __str__(self):
return self.name
class Student(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, primary_key=True)
age = models.IntegerField()
address = models.CharField(max_length=200)
def __str__(self):
return self.user.username
class Teacher(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, primary_key=True)
description = models.TextField()
course_teaching = models.ForeignKey(Course, on_delete=models.CASCADE)
students = models.ManyToManyField(Student)
def __str__(self):
return self.user.username
Check out an example of this type of serializer here: https://github.com/imagineai/create-django-app/blob/master/todoapp/serializers.py
*Update 1: Attempts with corresponding errors now shown in serializer code
*Update 2: I've narrowed the issue to a conflict with the JSON Api framework I'm using
I'm fairly new to Python and Django and I'm struggling quite a bit with relations. I'm able to create the relations in the database however I've been unable to serialize the models together for a response object, despite trying every method in the documentation which seems very straightforward. My goal is to return both models from an APIView on login and if this code doesn't error I get a response with just the user model. The errors vary based on the different techniques and are similar to what other users get when having trouble with relations, however their fixes haven't solved my problem.
I'm wondering if there's something obvious I'm not doing right. I'm happy to share more code but I'm really at a loss as to how to proceed.
Fyi: My models are in different apps which is why the fk reference is users.User
Models:
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(max_length=50, unique=True)
password = models.CharField(max_length=100)
name = models.CharField(max_length=50)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
has_business = models.BooleanField(default=False)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['password']
def get_full_name(self):
return self.name
def get_short_name(self):
return self.name
def __str__(self):
return self.email
class Business(models.Model):
name = models.CharField(max_length=50, unique=True)
address = models.CharField(max_length=100)
phone = models.CharField(max_length=20)
description = models.CharField(max_length=500)
user = models.ForeignKey(
'users.User',
related_name='business',
unique=False,
on_delete=models.CASCADE
)
has_driver = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
created = models.DateTimeField(auto_now_add=True)
Serializer:
class UserSerializer(serializers.ModelSerializer):
token = srs.SerializerMethodField()
biz = BusinessSerializer(many=True, read_only=True,
source='business.id')
error: just returns user model
biz = BusinessSerializer(read_only=True, many=True, source='business')
error: ForeignKey' object has no attribute
biz = serializers.RelatedField(many=True, read_only=True)
error: 'User' object has no attribute 'biz'
biz = serializers.ReadOnlyField(source='businesses.id')
error: RelatedManager object at 0x7fed496fe208> is not JSON
serializable
biz = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
error:'User' object has no attribute 'biz'
class Meta:
model = models.User
fields = ('id', 'email', 'password', 'name', 'token', 'has_business', 'biz')
extra_kwargs = {'password': {'write_only': True}}
def create(self, validated_data):
user = models.User(
email = validated_data['email'],
name = validated_data['name'],
phone = validated_data['phone'],
location = validated_data['location'],
)
user.set_password(validated_data['password'])
user.save()
return user
View:
class LoginUser(APIView):
permission_classes = (permissions.AllowAny,)
resource_name = 'users'
def post(self, request):
email = request.POST.get('email', False)
password = request.POST.get('password', False)
if(email and password):
lu = UserAuth()
authenticated_user = lu.auth(email=email, password=password)
if authenticated_user is not None:
if authenticated_user.is_active:
serializer = serializers.UserSerializer(authenticated_user, context={'request': request})
return Response(serializer.data, status=status.HTTP_200_OK)
You have to use the related_name in your serializer.
You can take a look here
In this example you can see that the Track Model (analog to your Business Model) has the field called album with related_name='tracks'
Then in the AlbumSerializer (the analog to your User Model):
class AlbumSerializer(serializers.ModelSerializer):
tracks = serializers.StringRelatedField(many=True)
class Meta:
model = Album
fields = ('album_name', 'artist', 'tracks')
So, in summary you have to use your related_name business
This is the example with a StringRelatedField, but you can of course return the complete object using this
Turns out I was using a beta version (pip install djangorestframework-jsonapi==2.0.0-beta.1) of the JSON API Framework and it wasn't handling relations very well. I picked the beta because it was the one the documentation lists which is kind of odd. You have to dig a bit for the more stable versions. I'm embarrassed to say how long that took me to figure out.
Here's the stable version as of this day: pip install djangorestframework-jsonapi==2.2.0
I want to have an is_active field for all the models in my application and when ever I create an api, I want to filter only the active ones and send the response. Is there a generic way to do this? As of now I am keeping a boolean field is_active and every time I retrieve the objects, I am writing a filter. below is the code :
My models.py
class Crew(models.Model):
crew_id = models.AutoField(primary_key=True)
crew_code = models.CharField(max_length=200, null=False, unique=True)
crew_name = models.CharField(max_length=200, null=False)
crew_password = models.CharField(max_length=200, null=False)
is_active = models.BooleanField(default=True)
My views.py :
#api_view(['GET'])
def get_crews(request):
c = Crew.objects.filter(is_active=True)
serializer = CrewSerializer(c, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
You can write custom model manager:
class IsActiveManager(models.Manager):
def get_queryset(self):
return super(IsActiveManager, self).get_queryset().filter(is_active=True)
class Crew(models.Model):
...
objects = IsActiveManager()
Now Crew.objects.all() will return only is_active record.
You can write a mixin in mixin.py file something like this
class TimeFieldsMixin(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
active = models.BooleanField(default=True, db_index=True)
class Meta:
abstract = True
And Import this in your models like this:
class User(TimeFieldsMixin):
// model fields
This will add this fields by default wherever you use this mixin.
Let me know if this is not clear.
Please note that if you have additional Model Managers:
The first manager listed in the model class definition is the one that is used for the admin site and a number of other operations.
I am trying to build a simple social network.
Say I have two models: Status and my custom UserProfile model to implement followers/followings feature:
from django.contrib.auth.models import User
class Status(models.Model):
user = models.ForeignKey(User, related_name='statuses')
title = models.CharField(max_length=50)
status = models.TextField()
created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True)
class Meta:
verbose_name = "Status"
verbose_name_plural = "Statuses"
ordering = ('-created',)
get_latest_by = 'created'
class UserProfile(models.Model):
user = models.OneToOneField(User, related_name='profile')
followings = models.ManyToManyField(
'self', related_name='followers', symmetrical=False, blank=True)
What is the most efficient way to access newsfeed i.e. recent statuses of all of my(User) followings?
I am new to Django. Any help will be much appreciated.
Simply filter Status queryset by users that you are following. Query above will show all statuses for all users followed by user.
Status.objects.filter(user__followers=user)
I have this model in Django, where a person has the same information from the user provided by Django plus a little bit more information. When I create a new person it requires to create a new user also, that's fine. But when I delete a person the user still remains on my database. What am I missing here ? I would like to delete the user too.
class Person(models.Model):
user = OneToOneField(User)
gender = CharField(max_length=1, choices=GenderChoices, blank=True, null=True)
birth_date = DateField(blank=True, null=True)
def __unicode__(self):
return self.user.username
Try to override the delete method on the model (code not tested):
class Person(models.Model):
user = OneToOneField(User)
gender = CharField(max_length=1, choices=GenderChoices, blank=True, null=True)
birth_date = DateField(blank=True, null=True)
def __unicode__(self):
return self.user.username
def delete():
theuser = User.objects.get(id=user)
theuser.delete()
I have found some relevant documentation about CASCADE usage in Django here.