I have token auth implemented in django and my models looks like-
class Portfolio(models.Model):
owner = models.ForeignKey(User, verbose_name='User', null=True)
company = models.TextField(null=True)
volume = models.IntegerField(blank=True)
date = models.DateField(null=True)
And to save in this model, I have the following in views-
arr = []
contents = request.data
user = User.objects.filter(username=request.user)
user_is = User(username=user)
for i in range(0, len(portfolio_contents)):
line = portfolio_contents[i].split(",")
get_isin = Endday.objects.get(company=line[0])
datestuff = line[2]
datestuff = datestuff[0:10]
arr.append(Portfolio(owner=user_is, company=line[0], volume=line[1], date=datestuff))
Portfolio.objects.bulk_create(arr)
This code saves the data but when I try to see the data, I get this-
[
{
"company": "BAL",
"volume": 1425,
"date": "2014-02-19",
"owner": null
},
{
"company": "RLD",
"volume": 2245,
"date": "2014-02-19",
"owner": null
},
Owner should not be null because if I try to print(user.username), it prints <QuerySet [<User: ku>]>.
What seems to be the problem?
It's because you didn't save your user e.g. it doesn't have an id in database.
Also you need a User instance and not QuerySet which you'll get from calling User.objects.filter(username=request.user).
Try to:
user_is = User.objects.get(username=request.user.username)
Your user_is is a User model instance which is not saved in the database:
user_is = User(username=user) # ??? username != user
Why not do:
user_is = User.objects.get(username=request.user.username)
Or make owner=request.user in the ForeignKey field in your loop.
Related
models.py
class Sequence(models.Model):
category_id = models.ForeignKey(SequenceCategory, on_delete=models.CASCADE)
description = models.TextField()
code = models.CharField(max_length=50)
total_divisions = models.IntegerField()
status = models.BooleanField(default=True)
def __str__(self):
return self.code
class SequenceValue(models.Model):
TYPE_CHOICES =(
('N', 'Numeric'),
('A', 'Alphabet')
)
sequence_id = models.ForeignKey(Sequence, on_delete=models.CASCADE, blank=True, null=True, related_name='Sequence_details')
type = models.CharField(max_length=100, choices=TYPE_CHOICES)
value = models.CharField(max_length=50)
starting_value = models.CharField(max_length=50, null=True, blank=True)
increment_value = models.CharField(max_length=50, null=True, blank=True)
def __str__(self):
return self.value
serializers.py
class SequenceValueSerializer(serializers.ModelSerializer):
class Meta:
model = SequenceValue
# fields = '__all__'
exclude = ['sequence_id']
class SequenceSerializer(serializers.ModelSerializer):
Sequence_details = SequenceValueSerializer()
class Meta:
model = Sequence
fields = '__all__'
def create(self, validate_data):
Sequence_details_data = validate_data.pop('Sequence_details')
sequence_id = Sequence.objects.create(**validate_data)
SequenceValue.objects.create(sequence_id=sequence_id, **Sequence_details_data)
return sequence_id
views.py
class SequenceCreate(ListCreateAPIView):
queryset = Sequence.objects.all()
serializer_class = SequenceSerializer
Why do I get the error? When I refer to n number of articles I got a solution that put many=True something like this.
Sequence_details = SequenceValueSerializer(many=True)
But when I make changes on that then I can't get the Sequence details fields. How can I fix this issue? Can you give a solution, please?
Actual error-
Got AttributeError when attempting to get a value for field type on serializer SequenceValueSerializer.
The serializer field might be named incorrectly and not match any attribute or key on the RelatedManager instance.
Original exception text was: 'RelatedManager' object has no attribute 'type'.
Data Passess
Data - {
"Sequence_details": [{
"type": "N",
"value": "123",
"starting_value": "1",
"increment_value": "1"
}],
"description": "asd",
"code": "qwe",
"total_divisions": 2,
"status": false,
"category_id": 3
}
Actual eroor screenshot
Adding many=True works because your request data passes Sequence_details as a list. In order to use it in your serializer, you can just iterate through the field and create your objects like this:
class SequenceSerializer(serializers.ModelSerializer):
Sequence_details = SequenceValueSerializer(many=True)
class Meta:
model = Sequence
fields = '__all__'
def create(self, validate_data):
Sequence_details_data = validate_data.pop('Sequence_details')
sequence_id = Sequence.objects.create(**validate_data)
for details in Sequence_details_data
SequenceValue.objects.create(sequence_id=sequence_id, **details)
return sequence_id
But if you don't want to do this, you can remove many=True and keep your serializer as is, but ensure that Sequence_details in your request data is not a list:
{
"Sequence_details": {
"type": "N",
"value": "123",
"starting_value": "1",
"increment_value": "1"
},
"description": "asd",
"code": "qwe",
"total_divisions": 2,
"status": false,
"category_id": 3
}
I can't comment so I will just mention it here :). type is actually a function in python which tells you about the class type of argument. I am not sure if this the issue but the can you try by renaming type to _type or something of your choice.
I'm adding 'added' field to check which categories User's Post(Outfit) is added to. It sounds horrible, so let's dive in to the code.
I want to optimize get_categories(self, obj) function.
class CategorySerializer(serializers.ModelSerializer):
added = serializers.BooleanField()
class Meta:
model = Category
fields = (
'id',
'name',
'added'
)
class OutfitDetailSerializer(serializers.ModelSerializer):
def get_categories(self, obj):
user = self.context['request'].user
categories = Category.objects.filter(owner=user)
added = categories.extra(select={'added': '1'}).filter(outfits__pk=obj.pk)
added = list(added.values('added', 'name', 'id'))
added_f = categories.extra(select={'added': '0'}).exclude(outfits__pk=obj.pk)
added_f = list(added_f.values('added', 'name', 'id'))
categories = added + added_f
return CategorySerializer(categories, many=True).data
The output is below!
"categories": [{
"id": 1,
"name": "Gym",
"added": true
}, {
"id": 2,
"name": "School",
"added": false
}, {
"id": 3,
"name": "hollymo",
"added": true
}, {
"id": 4,
"name": "Normal",
"added": false
}, {
"id": 6,
"name": "New Category",
"added": false
}
]
Here is models.py
class Outfit(models.Model):
...
user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True)
content = models.CharField(max_length=30)
...
class Category(models.Model):
name = models.CharField(max_length=20)
owner = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True)
outfits = models.ManyToManyField(Outfit, related_name="categories", blank=True)
main_img = models.ImageField(
upload_to=upload_location_category,
null=True,
blank=True)
...
here the repo for test
If i get you right, you can get necessary data with django raw sql:
q = """\
SELECT yourappname_category.id,
yourappname_category.name,
COUNT(outfit_id) > 0 as added
FROM yourappname_category
LEFT JOIN yourappname_category_outfits
ON yourappname_category.id = yourappname_category_outfits.category_id
AND yourappname_category_outfits.outfit_id=%s
WHERE yourappname_category.owner_id=%s
GROUP BY yourappname_category.id, yourappname_category.name"""
categories = Category.objects.raw(q, [obj.id, user.id])
results = [{'id': c.id, 'name': c.name, 'added': c.added} for c in categories]
If I understand your use case correctly you just want "to check which categories User's Post(Outfit) is added to". For that you would only need to return the ones with added = true right? and then you could leave the added key out.
as in:
"categories": [{
"id": 1,
"name": "Gym"
}, {
"id": 3,
"name": "hollymo"
}
]
If so, you could just use:
import Category from category.models
class CategoriesSerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = ('id', 'name')
class OutfitDetailSerializer(serializers.ModelSerializer):
categories = CategoriesSerializer(many=True)
If instead your use case is to show a list of all categories and then do something with just the ones that the current outfit is added to, I'd suggest doing 2 API calls instead of your current logic; One with the answer I supplied above and one to get all categories. Then do that 'added' logic in your front-end as its presentation layer logic imo.
I'd certainly try to avoid doing raw SQL queries in Django, it cuts the purpose of migrations and is rarely necessary.
I'll try to make this as simple as I can:
I have 2 models
from django.db import models
class OrderDetail(models.Model):
product = models.CharField(max_length=100)
price = models.CharField(max_length=50)
class Order(models.Model):
url = models.CharField(max_length=255, unique=True)
loaded_info = models.BooleanField(default=False)
status = models.CharField(max_length=100, null=True)
details = models.OneToOneField(OrderDetail)
And I whish to save using a dict like this:
data = {
"order": {
"url": "http://stackoverflow.com/",
"loaded_info": True,
"status": "complete",
"details": {
"product": "Fresh answer",
"price": "50 points"
}
}
}
I'd like to do something close to:
order = Order(**data).save()
And get Order and OrderDetail saved using a single line.
Have a look at https://docs.djangoproject.com/en/1.9/topics/serialization/
In this case, you would do something like:
qs = Order.objects.select_related('details').get(pk=1)
data = serializers.serialize("json", qs)
My REST API is functioning correctly, but the output is all id numbers. How can I get 'role_type' to display the name instead of the ID number?
Output:
{"count": 2, "next": null, "previous": null, "results": [{"user": {"username": "smithb", "first_name": "Bob", "last_name": "Smith"}, "role_type": 2, "item": 1}, {"user": {"username": "jjones", "first_name": "Jane", "last_name": "Jones"}, "role_type": 2, "item": 1}]}
serializers.py
class RoleSerializer(serializers.ModelSerializer):
user = PersonShortSerializer(many=False, read_only=True)
class Meta:
model = Role
fields = 'user', 'role_type', 'item'
def get_role_type(self, obj):
return obj.name
models.py
class Role(models.Model):
role_type = models.ForeignKey('RoleType')
user = models.ForeignKey(Person)
item = models.ForeignKey('Assets.Item')
class RoleType(models.Model):
name = models.CharField(max_length=255)
permissions = models.ManyToManyField(RolePermission,
blank=True, null=True)
def __unicode__(self):
return self.name
Take a look at the different types of serializer relationship fields.
In particular RelatedField should do what you need as it'll represent the target of the relationship using its unicode value.
class RoleSerializer(serializers.ModelSerializer):
user = PersonShortSerializer(many=False, read_only=True)
role_type = serializers.RelatedField()
class Meta:
model = Role
fields = ('user', 'role_type', 'item')
Also note that RelatedField is a read only field, as there's no way to determine the appropriate model instance given the unicode representation. If you did need it to be writable you might want to look at implementing a custom relational field.
I have been struggling to add many-to-many relation in the django serializer than be accessed through the view.
I created 2 classes in the model file "MODISLevel1" & "FileProperties". Where MODISLevel1 has a field called "filesProperties" pointing to the "FileProperties" class.
The model looks like:
class FileProperties(models.Model):
FileName = models.CharField(blank=True, max_length=1000)
FileID = models.CharField(blank=True, max_length=1000)
FileSize = models.CharField(blank=True, max_length=1000)
Updated = models.CharField(blank=True, max_length=1000)
GeoBox = models.CharField(blank=True, max_length=1000)
def __str__(self):
return self.FileName
class Meta:
ordering = ('FileName',)
class MODISLevel1(models.Model):
ProductLevel = models.CharField(max_length=7,
choices=ProductLevelsChoices,
default='MOD03')
SpacecraftType = models.CharField(max_length=5,
choices=SpacecraftTypeChoices,
default='Terra')
StartTimespan = models.TextField()
EndTimespan = models.TextField()
AOI = models.TextField()
DegreeNumbers = models.TextField()
filesProperties = models.ManyToManyField(FileProperties)
def __str__(self):
return self.ProductLevel
class Meta:
ordering = ('ProductLevel',)
As for the serializer I checked http://django-rest-framework.org/api-guide/relations.html#nested-relationships which tells that nested relationships should be created in the following way:
class FilePropertiesSerializer(serializers.ModelSerializer):
class Meta:
model = FileProperties
fields = ('id', 'FileName', 'FileID', 'FileSize', 'Updated', 'GeoBox')
class MODISLevel1Serializer(serializers.ModelSerializer):
filesProperties = FilePropertiesSerializer(many=True)
class Meta:
model = MODISLevel1
fields = ('id', 'ProductLevel', 'SpacecraftType', 'StartTimespan', 'EndTimespan', 'AOI', 'DegreeNumbers', 'filesProperties')
for the the view file I tried different ways to make it work but with no success.
1-Creating an instance from the Model "MODISLevel1", filling its fields, saving it, then filling the m2m field through iteration:
modisLevel1 = MODISLevel1()
modisLevel1.ProductLevel = productLevel
modisLevel1.SpacecraftType = spacecraftType
modisLevel1.StartTimespan = startTimespan
modisLevel1.EndTimespan = endTimespan
modisLevel1.AOI = AOI
modisLevel1.DegreeNumbers = degreeNumbers
modisLevel1.save()
#Inside a loop
f = FileProperties()
f.FileID = fileID
f.FileName = fileName
f.Updated = updated
f.GeoBox = geoBox
f.FileSize = fileSize
f.save()
modisLevel1.filesProperties.add(f)
serializer = MODISLevel1Serializer(data=modisLevel1)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
the error that i got is:
{
"non_field_errors": [
"Invalid data"
]
}
but for sure it's added in the database as I executed the save command "modisLevel1.save()", but that's not what I need.
2-Creating a json file and appending the 'filesProperties' to it through the iteration:
jsonFile = {u"ProductLevel": productLevel, u"SpacecraftType": spacecraftType, u"StartTimespan": startTimespan,
u"EndTimespan":endTimespan, u"AOI": AOI, u"DegreeNumbers": u"POINT(22.5,28.34) POINT(28.64,28.34) POINT(29.4,19.16) POINT(19.19,19.3067)",
u"filesProperties": [] }
#inside the loop
jsonFile["filesProperties"].append({u"FileName":fileName, u"FileID":fileID, u"FileSize":fileSize, u"Updated":updated, u"GeoBox":geoBox})
serializer = MODISLevel1Serializer(data=jsonFile)
and this one throws an error that the base model has to have a value before setting the m2m field:
Cannot add "": instance is on database "default", value is on database "None"
3-Create a dict and parse the Model to this dictionary, and then convert the FileProperties to the dictionary and append it to the previously created one:
modisLevel1 = MODISLevel1()
modisLevel1.ProductLevel = productLevel
modisLevel1.SpacecraftType = spacecraftType
modisLevel1.StartTimespan = startTimespan
modisLevel1.EndTimespan = endTimespan
modisLevel1.AOI = AOI
modisLevel1.DegreeNumbers = degreeNumbers
modisLevel1.save()
dict = model_to_dict(modisLevel1)
#FIXME!
dict['filesProperties'] = [{"FileName": "fileName", "FileID": "fileID", "FileSize": "fileSize", "Updated": "updated", "GeoBox": "geoBox"},
{"FileName": "fileName", "FileID": "fileID", "FileSize": "fileSize", "Updated": "updated", "GeoBox": "geoBox"},
{"FileName": "fileName", "FileID": "fileID", "FileSize": "fileSize", "Updated": "updated", "GeoBox": "geoBox"}]
serializer = MODISLevel1Serializer(data=dict)
and this one throws the same error as the previous one.
I did check some other posts that might be close to this issue, but none of them did work with me:
django rest nested relation in post/put
My json post request looks like the following:
[
{
"ProductLevel": "MOD03",
"SpacecraftType": "Terra",
"StartTimespan": "2013.11.02",
"EndTimespan": "2013.11.02",
"AOI": "swath",
"DegreeNumbers": "POINT(22.5,28.34) POINT(28.64,28.34) POINT(29.4,19.16) POINT(19.19,19.3067)"
}
]
Please notice that in the 'view.py' file I am able to store values in the database but if I bypass the serializer, like the examples that I've shown above.
So did somebody been through the same problem and know how to get this fixed? will be appreciated!