Combining PrimaryKeyRelatedField and Nested relationship functionality

777 views
Skip to first unread message

Michael Godshall

unread,
Jul 8, 2013, 3:04:44 PM7/8/13
to django-res...@googlegroups.com
I'm trying to figure out the best way to serialize a nested relationship for my Angular.js app.

class File(models.Model):
    """
    A file upload
    """
    name = models.CharField(max_length=255, help_text="Display name for the file. Defaults to the file name.")
    file = models.FileField(upload_to="uploads")
    file_type = models.CharField(max_length=50)
    user = models.ForeignKey(settings.AUTH_USER_MODEL)

class Entry(models.Model):
    """
    An entry will have 1 of the following fields: file, text, url
    """
    created_for = models.ForeignKey(settings.AUTH_USER_MODEL)
    created_by = models.ForeignKey(settings.AUTH_USER_MODEL)
    entry_type = models.ForeignKey('EntryType')
    file = models.ForeignKey('files.File', null=True, blank=True)
    text = models.TextField(blank=True)
    url = models.CharField(max_length=255, blank=True)

Basically, I want to create new Entries for existing Files using the file id (like a PrimaryKeyRelatedField), and get Entries with all the File fields included with the response, not just the id (like the nested relationship example).

I'm currently using the default ModelSerializer for the Entries. When I create a new entry with a file attachment, I set the pk to an existing file, and when I get entries, it returns the pk for the file. 
     
{
"id": 47, "created_for": 2, "created_by": 1, "entry_type": "document", "file": 18, "text": "", "url": "", ... },

However, when I get Entries, I want to pass the fields of the file, not just the id (like the nested relationship example), like this:

    {
        "id": 47, 
        "created_for": 2, 
        "created_by": 1, 
        "entry_type": "document", 
        "file": {
"id": 18,
"name": "My document",
"file": "path/to/my_document.doc"
"file_type": "application/msword",
"user": 1
}
,
"text": "", "url": "", ... },

So, how can I implement this nested serializer functionality for get requests, but still use the file pk when creating new Entries?  Or, perhaps there's a different implementation I should be pursuing altogether.

I would appreciate any direction you can provide.  Thanks!






Richard Wackerbarth

unread,
Jul 8, 2013, 3:14:36 PM7/8/13
to django-res...@googlegroups.com
One approach would be to use the Django proxy model to created separate representations of the model so that you can attach different serializers to the two cases.

--
You received this message because you are subscribed to the Google Groups "Django REST framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-rest-fram...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Michael Godshall

unread,
Jul 8, 2013, 6:32:27 PM7/8/13
to django-res...@googlegroups.com
Thanks for your reply, Richard.  I found a solution that allows me to use two different serializers for the same model (without using proxy).

# serializers.py

class FileSerializer(serializers.ModelSerializer):
    class Meta:
        model = File

class EntrySerializer(serializers.ModelSerializer):
    """ PK serializer for creating Entries """
    entry_type = serializers.SlugRelatedField(slug_field='slug')

    class Meta:
        model = Entry
        fields = ('id', 'created_for', 'created_by', 'entry_type', 'file', 'text', 'url', 'created_at', 'updated_at')

class EntryNestedFileSerializer(EntrySerializer):
    """ Nested serializer for getting Entries """
    file = FileSerializer()

# views.py
class EntryListAPI(generics.ListCreateAPIView):
    model = Entry

    def get_serializer_class(self):
        if self.request.method == 'POST':
            return EntrySerializer
        else:
            return EntryNestedFileSerializer

It is working great so far.  The only downside is that when you create a new Entry it returns a success response with the file as a pk instead of a dictionary.  I could change this by overriding the 'create' method for EntryListAPI and replacing the 'file' field (which I might do eventually), but for now I found it easier to handle this on the JavaScript side where I already have access to to the file object (I don't have access to this object when I GET the files, which is why I need the solution above).

Thanks again for your help!
To unsubscribe from this group and stop receiving emails from it, send an email to django-rest-framework+unsub...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages