Fixtures data for model containing images, files and tags - django

I am using Djano 3.1, Python 3.6, easy-thumbnails 2.7 and django-taggit 1.3
I want to create a fixtures data file for my model.
Here is my (simplified) model:
myapp/models.py
class Post(models.Model):
featured_image = ThumbnailerImageField(upload_to='uploads/post/featured_image', blank=True, null=True)
content = models.CharField(max_text=1000, null=False, blank=False)
tags = TaggableManager()
class PostFileAttachment(models.Model):
post = models.ForeignKey(Post, related_name='attachments', on_delete = mFixtures data for model containing images and filesodels.CASCADE)
file = models.FileField(upload_to="uploads/post/attachments")
class PostImageGallery(models.Model):
post = models.ForeignKey(Post, related_name='pictures', on_delete = models.CASCADE)
description = models.CharField(max_length=100, blank=True, null=True, default='')
image = models.ImageField(upload_to='uploads/blogpost/gallery')
myapp/fixtures/sample_data.json
[
{
"model": "myapp.Post",
"pk": 1,
"fields": {
"featured_image": ???
"content": "This is where the content goes"
"tags": ???
}
},
{
"model": "myapp.PostFileAttachment",
"pk": 1,
"fields": {
"post": 1
"file": ???
}
},
{
"model": "myapp.PostImageGallery",
"pk": 1,
"fields": {
"post": 1
"description": "File description",
"image": ???
}
}
]
How do I specify files in my JSON fixtures file?

if you try via admin interface to save a Post with an image e.g image.png and then you look the database, you will find that the post's image was saved with its relative path : uploads/post/featured_image/image.png, so in your fixture you need to specify that path.
in your myapp/fixtures/sample_data.json fixture file it should be like
[
{
"model": "myapp.Post",
"pk": 1,
"fields": {
"featured_image": "uploads/post/featured_image/FEATURED_IMAGE.EXT",
"content": "This is where the content goes",
}
},
{
"model": "myapp.PostFileAttachment",
"pk": 1,
"fields": {
"post": 1,
"file": "uploads/post/attachments/ATTACHMENT.EXT",
}
},
{
"model": "myapp.PostImageGallery",
"pk": 1,
"fields": {
"post": 1,
"description": "File description",
"image": "uploads/blogpost/gallery/IMAGE.EXT",
}
}
]

Related

django-filters returns two the same models when an instance of a model has the same value

Here is my code;
models.py
class Home(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return str(self.user)
class GeneralHomeFeatures(models.Model):
home = models.ForeignKey(
Home, on_delete=models.CASCADE, related_name="general_home_features"
)
home_feature = models.CharField(max_length=100, null=True, blank=True)
def __str__(self):
return str(self.home)
serializer.py
class GeneralHomeFeaturesSerializer(serializers.ModelSerializer):
class Meta:
model = GeneralHomeFeatures
exclude = ["home"]
filterset.py
class HomeFilter(filters.FilterSet):
home_feature = filters.CharFilter(field_name="general_home_features__home_feature", lookup_expr="icontains")
class Meta:
model = Home
fields = [
"home_feature",
]
once I give GeneralHomeFeatures class the same value twice, once filtered, it returns the same instance twice. Example; I make a request to this url - http://localhost:8000/api/homes/?home_feature=Pool and it returns this;
[
{
"id": 1,
"user": "cliffaust",
"general_home_features": [
{
"id": 1,
"home_feature": "Pool"
},
{
"id": 2,
"home_feature": "Children Play Ground"
},
{
"id": 7,
"home_feature": "Pool"
}
],
},
{
{
"id": 1,
"user": "cliffaust",
"general_home_features": [
{
"id": 1,
"home_feature": "Pool"
},
{
"id": 2,
"home_feature": "Children Play Ground"
},
{
"id": 7,
"home_feature": "Pool"
}
],
},
{
"id": 3,
"user": "cliffaust",
"general_home_features": [
{
"id": 4,
"home_feature": "Pool"
},
{
"id": 6,
"home_feature": "Children Play Ground"
}
],
}
]
because home_feature of GeneralHomeFeatures has two the same value(pool), it seems like django-filter is returning the same instance twice(based on the serializer id).
I don't know if this is a fault in my code, or its just how it works. Also, is they a better way of doing something like this?

Django: Make a GET Request to a URL that is advanced

So I have Chat Rooms and I have Messages. Then I have two urls: /messages and /rooms. And these display all your rooms and messages. Also a message can be assigned to a room. So in the Room API I have the messages assigned to that room.
Let's say that the room is called 'Room1' and the messages are 'hey', 'yo' and 'wassup'. If I make a request to just /messages I will get all of the messages. Let's say that only two of the messages are assigned to 'Room1' and the other message is assigned to another room not named.
I want a way to make a get request and only get those two messages assigned to 'Room1 with id = 3' (localhost:8000/rooms/3/messages) instead of: (localhost:8000/messages).
This is an example of when I make a get request to /rooms/3/
{
"id": 3,
"name": "Room 1",
"members": [
{
"id": 1,
"username": "william"
},
{
"id": 2,
"username": "eric"
},
{
"id": 3,
"username": "ryan"
}
],
"messages": [
{
"id": 7,
"content": "hej",
"date": "2019-07-08",
"sender": {
"id": 1,
"username": "william"
}
},
{
"id": 8,
"content": "yoyo",
"date": "2019-07-08",
"sender": {
"id": 2,
"username": "eric"
}
},
{
"id": 9,
"content": "tjo bror",
"date": "2019-07-08",
"sender": {
"id": 3,
"username": "ryan"
}
},
{
"id": 10,
"content": "hej jag heter Eric och jag gar pa polhemskolan i lund och jag ar 17 ar gammal",
"date": "2019-07-08",
"sender": {
"id": 2,
"username": "eric"
}
},
{
"id": 11,
"content": "vi vet hahah",
"date": "2019-07-09",
"sender": {
"id": 1,
"username": "william"
}
},
{
"id": 12,
"content": "amen sluta",
"date": "2019-07-09",
"sender": {
"id": 2,
"username": "eric"
}
}
]
}
This is what I want to get in response if I do rooms/3/messages:
"messages": [
{
"id": 7,
"content": "hej",
"date": "2019-07-08",
"sender": {
"id": 1,
"username": "william"
}
},
{
"id": 8,
"content": "yoyo",
"date": "2019-07-08",
"sender": {
"id": 2,
"username": "eric"
}
},
{
"id": 9,
"content": "tjo bror",
"date": "2019-07-08",
"sender": {
"id": 3,
"username": "ryan"
}
},
{
"id": 10,
"content": "hej jag heter Eric och jag gar pa polhemskolan i lund och jag ar 17 ar gammal",
"date": "2019-07-08",
"sender": {
"id": 2,
"username": "eric"
}
},
{
"id": 11,
"content": "vi vet hahah",
"date": "2019-07-09",
"sender": {
"id": 1,
"username": "william"
}
},
{
"id": 12,
"content": "amen sluta",
"date": "2019-07-09",
"sender": {
"id": 2,
"username": "eric"
}
}
]
}
Django Models:
class UserProfile(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
class Meta:
verbose_name_plural = 'All Users'
def __str__(self):
return self.user.username
#receiver(post_save, sender=User)
def create_user_data(sender, update_fields, created, instance, **kwargs):
if created:
user = instance
profile = UserProfile.objects.create(user=user)
class Message(models.Model):
sender = models.ForeignKey(UserProfile, on_delete=models.CASCADE, related_name="sendermessage")
content = models.CharField(max_length=500)
date = models.DateField(default=date.today)
canview = models.ManyToManyField(UserProfile, blank=True, related_name="messagecanview")
class Meta:
verbose_name_plural = 'Messages'
def __str__(self):
return "{sender}".format(sender=self.sender)
class Room(models.Model):
name = models.CharField(max_length=50)
members = models.ManyToManyField(UserProfile, blank=True)
messages = models.ManyToManyField(Message, blank=True)
class Meta:
verbose_name_plural = 'Rooms'
def __str__(self):
return "{name}".format(name=self.name)enter code here
Django Serializers:
class UserProfileSerializer(serializers.ModelSerializer):
username = serializers.CharField(source='user.username')
class Meta:
model = UserProfile
fields = ('id', 'username')
class MessageSerializer(serializers.ModelSerializer):
sender = UserProfileSerializer()
class Meta:
model = Message
fields = ('id', 'content', 'date', 'sender')
class RoomSerializer(serializers.ModelSerializer):
messages = MessageSerializer(many=True)
members = UserProfileSerializer(many=True)
class Meta:
model = Room
fields = ('id', 'name', 'members', 'messages')
Django Views:
class UserProfileView(viewsets.ModelViewSet):
http_method_names = ['get', 'post', 'put', 'delete', 'patch']
queryset = UserProfile.objects.all()
serializer_class = UserProfileSerializer
class MessageView(viewsets.ModelViewSet):
http_method_names = ['get', 'post', 'put', 'delete', 'patch']
queryset = Message.objects.all()
serializer_class = MessageSerializer
class UserMessageView(MessageView):
def get_queryset(self):
return Message.objects.filter(canview__user=self.request.user)
class RoomView(viewsets.ModelViewSet):
http_method_names = ['get', 'post', 'put', 'delete', 'patch']
queryset = Room.objects.all()
serializer_class = RoomSerializer
class UserRoomView(RoomView):
def get_queryset(self):
return Room.objects.filter(members__user=self.request.user)
Django Urls:
router = routers.DefaultRouter()
router.register('users', views.UserProfileView),
router.register('rooms', views.UserRoomView),
router.register('messages', views.UserMessageView),
urlpatterns = [
path('', include(router.urls)),
]
To get all Messages assigned to a room, let's:
Install django-filter:
pip install django-filter
Modify the Room model to specify a related_name:
class Room(models.Model):
name = models.CharField(max_length=50)
members = models.ManyToManyField(UserProfile, blank=True)
messages = models.ManyToManyField(Message, blank=True, related_name='rooms')
# ^^^^^^^^^^^^^^^^^^^^^^
Enable filtering for the rooms related field:
import django_filters
import rest_framework.filters
[...]
class MessageView(viewsets.ModelViewSet):
# vvvvvvvvvvv I don't think this line is needed vvvvvvvvvvvvvv
# http_method_names = ['get', 'post', 'put', 'delete', 'patch']
queryset = Message.objects.all()
serializer_class = MessageSerialize
filter_backends = (
django_filters.rest_framework.DjangoFilterBackend,
rest_framework.filters.OrderingFilter,
)
filter_fields = ['rooms']
Then, you can request all messages for that room with a GET to:
localhost:8000/messages/?rooms=3
Comment question:
You also need to expose the Message object's sender field. Currently it is aliased:
class MessageSerializer(serializers.ModelSerializer):
# vvvv vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
sender_obj = UserProfileSerializer(source='sender', read_only=True)
class Meta:
model = Message
fields = ('id', 'content', 'date', 'sender', 'sender_obj')
# ^^^^^^^^^^^^^^
Then you can POST to /message with the data {"content": "blah", "date": "2019-07-09","sender": 1}

Serializer remove parent field django

{
"episode": {
"id": 6,
"channel_id": 2,
"channel": {
"id": 2,
"tags": [
"new"
]
},
{
"episode": {
"id": 7,
"channel_id": 3,
"channel": {
"id": 2,
"tags": [
"new"
]
}
},
Hey I am new to Django. I am wondering how to remove episode parent written in the serializer response and directly go into the id, channel. Episode is not useful for me here. I have a model that sets the priority of these episodes. Have excluded the priority and id field but don't know how to remove episode parent.
class TrendingEpisode(models.Model):
episode = models.ForeignKey(Episode, null=False, blank=False, on_delete=models.CASCADE)
priority = models.IntegerField(null=False, blank=False)
class Episode(models.Model):
channel = models.ForeignKey(Channel, on_delete=models.CASCADE)
tags = models.ManyToManyField(EpisodeTag)
#some other fields
Why do you use TrendingEpisode with foreignkey? Just use Episode only.
class Episode(models.Model):
channel = models.ForeignKey(Channel, on_delete=models.CASCADE)
tags = models.ManyToManyField(EpisodeTag)
#some other fields
Then you can get your serialized data like below
{
"id": 6,
"channel_id": 2,
"channel": {
"id": 2,
"tags": [
"new"
]
},
}

Distinct field Rest Framework Django

I need to make a distinct with a field of my model and not how to make
My model is:
class CheckList(CoreModel):
date = models.DateTimeField(default=datetime.now, blank=True, null=True, verbose_name=_('Date'))
establishment = models.ForeignKey(Establishment, related_name="checklists", on_delete=models.CASCADE, null=True, verbose_name=_('Establishment'))
user = models.ForeignKey(ITManager, related_name="checklists", on_delete=models.CASCADE, null=True, verbose_name=_('User'))
class Meta:
verbose_name_plural = _("Checklist")
verbose_name = _("Checklists")
def __str__(self):
return str(self.date)
My serializer and view:
class CheckListSerializer(BulkSerializerMixin, serializers.ModelSerializer):
user = ITManagerSerializer()
class Meta:
model = CheckList
list_serializer_class = BulkListSerializer
fields = ['id', 'user', 'establishment', 'date']
class ChecklistBulkViewSet(BulkModelViewSet):
queryset = CheckList.objects.values('establishment', 'user', 'date').distinct()
model = CheckList
serializer_class = CheckListSerializer
filter_class = ChecklistFilter
The api return me:
"results": [
{
"id": 1,
"user": {
"id": 3,
"first_name": "Andres",
"last_name": "Gallardo",
"rut": "21312",
"email": null,
"user_name": "andres",
"password": null,
"user": 4,
"country": [],
"active": true
},
"establishment": 3,
"date": "2016-06-14T15:15:00Z"
},
{
"id": 2,
"user": {
"id": 2,
"first_name": "Ramiro",
"last_name": "Gutierrez",
"rut": "15616+",
"email": null,
"user_name": null,
"password": null,
"user": 2,
"country": [
{
"id": 1,
"name": "Argentina",
"code_area": null
}
],
"active": false
},
"establishment": 3,
"date": "2016-06-09T15:40:04Z"
}]
I need you just leave me an establishment with the same id
any suggestions??
Thanks !

how to use backward relation in django tastypie

this is my model
class Nisit(models.Model):
and this
class Page(models.Model):
followingNisit = models.ManyToManyField(Nisit,blank=True)
this is my resource
class NisitResource(ModelResource):
page = fields.ToManyField('chula.api.PageResource','page_set',null=True)
class Meta:
queryset = Nisit.objects.all()
resource_name = 'nisit'
filtering = {
'page' : ALL_WITH_RELATIONS,
'id' : ALL,
}
class PageResource(ModelResource):
followingNisit = fields.ToManyField(NisitResource, 'followingNisit',null=True)
reporter = fields.ManyToManyField(ReporterResource,'reporter')
followers_count = fields.CharField(attribute='followers_count')
class Meta:
queryset = Page.objects.all()
resource_name = 'page'
authorization= Authorization()
filtering = {
'id':ALL,
'followingNisit': ALL_WITH_RELATIONS,
}
It's ok when I request -------127.0.0.1:8000/api/v2/page/?format=json&followingNisit__id=1
But In the opposite way ,when i request ---------127.0.0.1:8000/api/v2/nisit/?format=json&page__id=1, I will get this error
{"error_message": "Cannot resolve keyword 'page_set' into field. Choices are: displayName, facebook, faculty, friend, id, major, n_id, name, page, password, picture, reporter, year_in_school", "traceback": "Traceback (most recent call last):\n\n File \"D:\\Study\\SeniorProject\\Code\\mysite\\tastypie\\resources.py\", line 202, in wrapper\n response = callback(request, *args, **kwargs)\n\n File \"D:\\Study\\SeniorProject\\Code\\mysite\\tastypie\\resources.py\", line 441, in dispatch_list\n return self.dispatch('list', request, **kwargs)\n\n File \"D:\\Study\\SeniorProject\\Code\\mysite\\tastypie\\resources.py\", line 474, in dispatch\n response = method(request, **kwargs)\n\n File \"D:\\Study\\SeniorProject\\Code\\mysite\\tastypie\\resources.py\", line 1127, in get_list\n objects = self.obj_get_list(request=request, **self.remove_api_resource_names(kwargs))\n\n File \"D:\\Study\\SeniorProject\\Code\\mysite\\tastypie\\resources.py\", line 1890, in obj_get_list\n base_object_list = self.apply_filters(request, applicable_filters)\n\n File \"D:\\Study\\SeniorProject\\Code\\mysite\\tastypie\\resources.py\", line 1862, in apply_filters\n return self.get_object_list(request).filter(**applicable_filters)\n\n File \"C:\\Python27\\lib\\site-packages\\django\\db\\models\\query.py\", line 624, in filter\n return self._filter_or_exclude(False, *args, **kwargs)\n\n File \"C:\\Python27\\lib\\site-packages\\django\\db\\models\\query.py\", line 642, in _filter_or_exclude\n clone.query.add_q(Q(*args, **kwargs))\n\n File \"C:\\Python27\\lib\\site-packages\\django\\db\\models\\sql\\query.py\", line 1250, in add_q\n can_reuse=used_aliases, force_having=force_having)\n\n File \"C:\\Python27\\lib\\site-packages\\django\\db\\models\\sql\\query.py\", line 1122, in add_filter\n process_extras=process_extras)\n\n File \"C:\\Python27\\lib\\site-packages\\django\\db\\models\\sql\\query.py\", line 1316, in setup_joins\n \"Choices are: %s\" % (name, \", \".join(names)))\n\nFieldError: Cannot resolve keyword 'page_set' into field. Choices are: displayName, facebook, faculty, friend, id, major, n_id, name, page, password, picture, reporter, year_in_school\n"}
I have also been struggling with the same FieldError thrown from setup_joins, and I think I just solved my issue. I was trying to filter through a Many-to-Many relationship, and could never get the "_set" in fields.ToManyField() to work. After debugging the TastyPie code in the error case and in a working simple filter, I realized it may be possible to bypass the need for the intermediary resource altogether.
Here is what worked for me, I hope it helps in your situation. Since I don't know your model setup, I'll make up a similar example.
First, the models:
### models.py ###
from django.db import models
class Ingredient(models.Model):
name = models.CharField(max_length=100)
description = models.TextField()
def __unicode__(self):
return '%s' % (self.name)
class RecipeIngredient(models.Model):
recipe = models.ForeignKey('Recipe')
ingredient = models.ForeignKey('Ingredient')
weight = models.IntegerField(null = True, blank = True)
def __unicode__(self):
return '%s: %s' % (self.recipe, self.ingredient)
class Recipe(models.Model):
title = models.CharField(max_length=100)
ingredients = models.ManyToManyField(Ingredient, through='RecipeIngredient')
def __unicode__(self):
return '%s' % (self.title)
And here are the ModelResources:
### api.py ###
from tastypie.resources import ModelResource, ALL, ALL_WITH_RELATIONS
from tastypie import fields
from some_app.models import Ingredient, Recipe
class IngredientResource(ModelResource):
class Meta:
queryset = Ingredient.objects.all()
resource_name = 'ingredient'
filtering = {
'name': ALL,
}
class RecipeResource(ModelResource):
ingredients = fields.ToManyField(
'some_app.api.IngredientResource',
'ingredients',
full=True)
class Meta:
queryset = Recipe.objects.all()
resource_name = 'recipe'
filtering = {
'title': ALL,
'ingredients': ALL_WITH_RELATIONS,
}
Notice I do not have a RecipeIngredientResource, I hook directly to the IngredientResource, which works because the Recipe model includes the ManyToManyField ingredients with the option through='RecipeIngredient'
An example URL to filter all recipes for a particular ingredient then looks like:
http://localhost:8000/api/recipes/recipe/?ingredients__name=blueberry
And, for completeness, here's a fixture for a Django app named 'some_app' to save time entering data for anyone wanting to implement this example:
[
{
"pk": 1,
"model": "some_app.ingredient",
"fields": {
"name": "apple",
"description": "a tempting fruit"
}
},
{
"pk": 2,
"model": "some_app.ingredient",
"fields": {
"name": "cherry",
"description": "a red fruit"
}
},
{
"pk": 3,
"model": "some_app.ingredient",
"fields": {
"name": "blueberry",
"description": "a blue fruit"
}
},
{
"pk": 4,
"model": "some_app.ingredient",
"fields": {
"name": "flour",
"description": "used for baking and stuff"
}
},
{
"pk": 5,
"model": "some_app.ingredient",
"fields": {
"name": "sugar",
"description": "makes stuff sweet"
}
},
{
"pk": 1,
"model": "some_app.recipeingredient",
"fields": {
"recipe": 1,
"weight": 3,
"ingredient": 1
}
},
{
"pk": 2,
"model": "some_app.recipeingredient",
"fields": {
"recipe": 1,
"weight": 2,
"ingredient": 4
}
},
{
"pk": 3,
"model": "some_app.recipeingredient",
"fields": {
"recipe": 1,
"weight": 4,
"ingredient": 5
}
},
{
"pk": 4,
"model": "some_app.recipeingredient",
"fields": {
"recipe": 2,
"weight": 8,
"ingredient": 2
}
},
{
"pk": 5,
"model": "some_app.recipeingredient",
"fields": {
"recipe": 2,
"weight": 4,
"ingredient": 4
}
},
{
"pk": 6,
"model": "some_app.recipeingredient",
"fields": {
"recipe": 2,
"weight": 6,
"ingredient": 5
}
},
{
"pk": 7,
"model": "some_app.recipeingredient",
"fields": {
"recipe": 3,
"weight": 15,
"ingredient": 3
}
},
{
"pk": 8,
"model": "some_app.recipeingredient",
"fields": {
"recipe": 3,
"weight": 5,
"ingredient": 4
}
},
{
"pk": 9,
"model": "some_app.recipeingredient",
"fields": {
"recipe": 3,
"weight": 6,
"ingredient": 5
}
},
{
"pk": 1,
"model": "some_app.recipe",
"fields": {
"title": "Apple Pie"
}
},
{
"pk": 2,
"model": "some_app.recipe",
"fields": {
"title": "Cherry Pie"
}
},
{
"pk": 3,
"model": "some_app.recipe",
"fields": {
"title": "Blueberry Pie"
}
}
]
This is the thing, if django tastypie works very similar to django (as anyone could expect) you are using a bad keyword, in you case, It wouldn't be page_set, use just page instead and it will work.
I recommend to you using a plural in the field name
pages = fields.ToManyField('chula.api.PageResource','page_set',null=True)
so the forward relation is pages and the backward relation is page_set I cant remember which now. But anyway it will look nicer.