2013-11-17 22:26:41 +04:00
<!DOCTYPE html>
< html lang = "en" >
2014-07-15 18:02:49 +04:00
2014-11-25 19:04:38 +03:00
< head >
< meta http-equiv = "Content-Type" content = "text/html; charset=UTF-8" >
< meta charset = "utf-8" >
2015-05-15 11:19:49 +03:00
< title > Serializer relations - Django REST framework< / title >
2014-11-25 19:04:38 +03:00
< link href = "../../img/favicon.ico" rel = "icon" type = "image/x-icon" >
2018-10-11 16:48:33 +03:00
< link rel = "canonical" href = "https://www.django-rest-framework.org/api-guide/relations/" / >
2014-11-25 19:04:38 +03:00
< meta name = "viewport" content = "width=device-width, initial-scale=1.0" >
< meta name = "description" content = "Django, API, REST, Serializer relations" >
< meta name = "author" content = "Tom Christie" >
<!-- Le styles -->
< link href = "../../css/prettify.css" rel = "stylesheet" >
< link href = "../../css/bootstrap.css" rel = "stylesheet" >
< link href = "../../css/bootstrap-responsive.css" rel = "stylesheet" >
< link href = "../../css/default.css" rel = "stylesheet" >
<!-- Le HTML5 shim, for IE6 - 8 support of HTML5 elements -->
<!-- [if lt IE 9]>
< script src = "http://html5shim.googlecode.com/svn/trunk/html5.js" > < / script >
<![endif]-->
< script type = "text/javascript" >
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-18852272-2']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script');
ga.type = 'text/javascript';
ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
})();
< / script >
< style >
2016-05-26 13:48:39 +03:00
#sidebarInclude img {
margin-bottom: 10px;
}
#sidebarInclude a.promo {
2014-11-25 19:04:38 +03:00
color: black;
2016-05-26 13:48:39 +03:00
}
2014-11-25 19:04:38 +03:00
@media (max-width: 767px) {
div.promo {
display: none;
}
}
< / style >
< / head >
< body onload = "prettyPrint()" class = "-page" >
2013-11-17 22:26:41 +04:00
< div class = "wrapper" >
2014-11-25 19:04:38 +03:00
< div class = "navbar navbar-inverse navbar-fixed-top" >
2013-11-17 22:26:41 +04:00
< div class = "navbar-inner" >
< div class = "container-fluid" >
2017-05-12 19:15:00 +03:00
< a class = "repo-link btn btn-primary btn-small" href = "https://github.com/encode/django-rest-framework/tree/master" > GitHub< / a >
2019-07-15 22:12:34 +03:00
< a class = "repo-link btn btn-inverse btn-small " rel = "next" href = "../validators/" >
2014-11-25 19:04:38 +03:00
Next < i class = "icon-arrow-right icon-white" > < / i >
< / a >
2019-07-15 22:12:34 +03:00
< a class = "repo-link btn btn-inverse btn-small " rel = "prev" href = "../fields/" >
2014-11-25 19:04:38 +03:00
< i class = "icon-arrow-left icon-white" > < / i > Previous
< / a >
2015-06-04 17:37:22 +03:00
< a id = "search_modal_show" class = "repo-link btn btn-inverse btn-small" href = "#mkdocs_search_modal" data-toggle = "modal" data-target = "#mkdocs_search_modal" > < i class = "icon-search icon-white" > < / i > Search< / a >
2013-11-17 22:26:41 +04:00
< a class = "btn btn-navbar" data-toggle = "collapse" data-target = ".nav-collapse" >
< span class = "icon-bar" > < / span >
< span class = "icon-bar" > < / span >
< span class = "icon-bar" > < / span >
< / a >
2018-10-11 16:48:33 +03:00
< a class = "brand" href = "https://www.django-rest-framework.org/" > Django REST framework< / a >
2013-11-17 22:26:41 +04:00
< div class = "nav-collapse collapse" >
2014-11-25 19:04:38 +03:00
<!-- Main navigation -->
< ul class = "nav navbar-nav" >
2015-06-04 17:37:22 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../.." > Home< / a >
2015-06-04 17:37:22 +03:00
< / li >
2013-11-17 22:26:41 +04:00
< li class = "dropdown" >
2014-11-25 19:31:00 +03:00
< a href = "#" class = "dropdown-toggle" data-toggle = "dropdown" > Tutorial < b class = "caret" > < / b > < / a >
2013-11-17 22:26:41 +04:00
< ul class = "dropdown-menu" >
2014-11-25 19:04:38 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../tutorial/quickstart/" > Quickstart< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../tutorial/1-serialization/" > 1 - Serialization< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../tutorial/2-requests-and-responses/" > 2 - Requests and responses< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../tutorial/3-class-based-views/" > 3 - Class based views< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../tutorial/4-authentication-and-permissions/" > 4 - Authentication and permissions< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../tutorial/5-relationships-and-hyperlinked-apis/" > 5 - Relationships and hyperlinked APIs< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../tutorial/6-viewsets-and-routers/" > 6 - Viewsets and routers< / a >
2016-07-14 15:05:57 +03:00
< / li >
2013-11-17 22:26:41 +04:00
< / ul >
< / li >
2014-11-25 19:04:38 +03:00
< li class = "dropdown active" >
2013-11-17 22:26:41 +04:00
< a href = "#" class = "dropdown-toggle" data-toggle = "dropdown" > API Guide < b class = "caret" > < / b > < / a >
< ul class = "dropdown-menu" >
2014-11-25 19:04:38 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../requests/" > Requests< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../responses/" > Responses< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../views/" > Views< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../generic-views/" > Generic views< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../viewsets/" > Viewsets< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../routers/" > Routers< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../parsers/" > Parsers< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../renderers/" > Renderers< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../serializers/" > Serializers< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../fields/" > Serializer fields< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li class = "active" >
2019-07-15 22:12:34 +03:00
< a href = "./" > Serializer relations< / a >
2014-11-25 19:04:38 +03:00
< / li >
2014-12-01 15:20:07 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../validators/" > Validators< / a >
2014-12-01 15:20:07 +03:00
< / li >
2014-11-25 19:04:38 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../authentication/" > Authentication< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../permissions/" > Permissions< / a >
2014-11-25 19:04:38 +03:00
< / li >
2018-10-11 16:48:33 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../caching/" > Caching< / a >
2018-10-11 16:48:33 +03:00
< / li >
2014-11-25 19:04:38 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../throttling/" > Throttling< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../filtering/" > Filtering< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../pagination/" > Pagination< / a >
2014-11-25 19:04:38 +03:00
< / li >
2015-03-06 15:05:16 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../versioning/" > Versioning< / a >
2015-03-06 15:05:16 +03:00
< / li >
2014-11-25 19:04:38 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../content-negotiation/" > Content negotiation< / a >
2014-11-25 19:04:38 +03:00
< / li >
2014-12-18 18:42:42 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../metadata/" > Metadata< / a >
2014-12-18 18:42:42 +03:00
< / li >
2016-07-07 11:41:32 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../schemas/" > Schemas< / a >
2016-07-07 11:41:32 +03:00
< / li >
2014-11-25 19:04:38 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../format-suffixes/" > Format suffixes< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../reverse/" > Returning URLs< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../exceptions/" > Exceptions< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../status-codes/" > Status codes< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../testing/" > Testing< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../settings/" > Settings< / a >
2014-11-25 19:04:38 +03:00
< / li >
2013-11-17 22:26:41 +04:00
< / ul >
< / li >
2014-11-25 19:04:38 +03:00
2013-11-17 22:26:41 +04:00
< li class = "dropdown" >
< a href = "#" class = "dropdown-toggle" data-toggle = "dropdown" > Topics < b class = "caret" > < / b > < / a >
< ul class = "dropdown-menu" >
2014-11-25 19:04:38 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../topics/documenting-your-api/" > Documenting your API< / a >
2014-11-25 19:04:38 +03:00
< / li >
2016-07-07 11:41:32 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../topics/api-clients/" > API Clients< / a >
2016-07-07 11:41:32 +03:00
< / li >
2015-03-06 15:05:16 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../topics/internationalization/" > Internationalization< / a >
2015-03-06 15:05:16 +03:00
< / li >
2014-11-25 19:04:38 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../topics/ajax-csrf-cors/" > AJAX, CSRF & CORS< / a >
2014-11-25 19:04:38 +03:00
< / li >
2015-10-28 14:35:39 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../topics/html-and-forms/" > HTML & Forms< / a >
2015-10-28 14:35:39 +03:00
< / li >
2014-11-25 19:04:38 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../topics/browser-enhancements/" > Browser Enhancements< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../topics/browsable-api/" > The Browsable API< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../topics/rest-hypermedia-hateoas/" > REST, Hypermedia & HATEOAS< / a >
2014-11-25 19:04:38 +03:00
< / li >
2018-10-11 16:48:33 +03:00
< / ul >
< / li >
< li class = "dropdown" >
< a href = "#" class = "dropdown-toggle" data-toggle = "dropdown" > Community < b class = "caret" > < / b > < / a >
< ul class = "dropdown-menu" >
2014-11-25 19:04:38 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../community/tutorials-and-resources/" > Tutorials and Resources< / a >
2019-07-15 14:38:39 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../community/third-party-packages/" > Third Party Packages< / a >
2017-02-25 22:59:44 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../community/contributing/" > Contributing to REST framework< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../community/project-management/" > Project management< / a >
2014-11-25 19:04:38 +03:00
< / li >
2014-12-18 16:49:50 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../community/release-notes/" > Release Notes< / a >
2014-12-18 16:49:50 +03:00
< / li >
2017-03-09 17:59:14 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../community/3.10-announcement/" > 3.10 Announcement< / a >
2017-03-09 17:59:14 +03:00
< / li >
2018-10-18 13:50:44 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../community/3.9-announcement/" > 3.9 Announcement< / a >
2018-10-18 13:50:44 +03:00
< / li >
2014-11-25 19:04:38 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../community/3.8-announcement/" > 3.8 Announcement< / a >
2014-11-25 19:04:38 +03:00
< / li >
2014-12-01 15:20:07 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../community/3.7-announcement/" > 3.7 Announcement< / a >
2014-12-01 15:20:07 +03:00
< / li >
2015-08-06 16:31:52 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../community/3.6-announcement/" > 3.6 Announcement< / a >
2015-08-06 16:31:52 +03:00
< / li >
2015-10-28 14:35:39 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../community/3.5-announcement/" > 3.5 Announcement< / a >
2015-10-28 14:35:39 +03:00
< / li >
2016-07-14 15:05:57 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../community/3.4-announcement/" > 3.4 Announcement< / a >
2016-07-14 15:05:57 +03:00
< / li >
2016-10-20 18:31:37 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../community/3.3-announcement/" > 3.3 Announcement< / a >
2016-10-20 18:31:37 +03:00
< / li >
2017-03-09 17:59:14 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../community/3.2-announcement/" > 3.2 Announcement< / a >
2017-03-09 17:59:14 +03:00
< / li >
2017-10-06 15:06:25 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../community/3.1-announcement/" > 3.1 Announcement< / a >
2017-10-06 15:06:25 +03:00
< / li >
2018-04-03 16:54:40 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../community/3.0-announcement/" > 3.0 Announcement< / a >
2018-04-03 16:54:40 +03:00
< / li >
2014-11-25 19:04:38 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../community/kickstarter-announcement/" > Kickstarter Announcement< / a >
2014-11-25 19:04:38 +03:00
< / li >
2016-05-26 13:48:39 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../community/mozilla-grant/" > Mozilla Grant< / a >
2016-05-26 13:48:39 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../community/funding/" > Funding< / a >
2016-05-26 13:48:39 +03:00
< / li >
2014-11-25 19:04:38 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../community/jobs/" > Jobs< / a >
2014-11-25 19:04:38 +03:00
< / li >
2013-11-17 22:26:41 +04:00
< / ul >
< / li >
2014-11-25 19:04:38 +03:00
2013-11-17 22:26:41 +04:00
< / ul >
2014-11-25 19:04:38 +03:00
< / div >
<!-- /.nav - collapse -->
2013-11-17 22:26:41 +04:00
< / div >
< / div >
< / div >
< div class = "body-content" >
< div class = "container-fluid" >
2014-11-25 19:04:38 +03:00
<!-- Search Modal -->
2015-06-04 17:37:22 +03:00
< div id = "mkdocs_search_modal" class = "modal hide fade" tabindex = "-1" role = "dialog" aria-labelledby = "myModalLabel" aria-hidden = "true" >
2014-11-25 19:04:38 +03:00
< div class = "modal-header" >
< button type = "button" class = "close" data-dismiss = "modal" aria-hidden = "true" > × < / button >
< h3 id = "myModalLabel" > Documentation search< / h3 >
< / div >
< div class = "modal-body" >
2015-08-06 16:31:52 +03:00
< form role = "form" autocomplete = "off" >
2015-06-04 17:37:22 +03:00
< div class = "form-group" >
< input type = "text" name = "q" class = "form-control" placeholder = "Search..." id = "mkdocs-search-query" >
< / div >
< / form >
< div id = "mkdocs-search-results" > < / div >
2014-11-25 19:04:38 +03:00
< / div >
< div class = "modal-footer" >
< button class = "btn" data-dismiss = "modal" aria-hidden = "true" > Close< / button >
< / div >
< / div >
2013-11-17 22:26:41 +04:00
< div class = "row-fluid" >
< div class = "span3" >
< div id = "table-of-contents" >
< ul class = "nav nav-list side-nav well sidebar-nav-fixed" >
2014-11-25 19:04:38 +03:00
< li class = "main" >
2019-07-15 22:12:34 +03:00
< a href = "../../#serializer-relations" > Serializer relations< / a >
2014-11-25 19:04:38 +03:00
< / li >
2014-12-01 15:20:07 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../#inspecting-relationships" > Inspecting relationships.< / a >
2014-12-01 15:20:07 +03:00
< / li >
2014-11-25 19:04:38 +03:00
< li class = "main" >
2019-07-15 22:12:34 +03:00
< a href = "../../#api-reference" > API Reference< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../#stringrelatedfield" > StringRelatedField< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../#primarykeyrelatedfield" > PrimaryKeyRelatedField< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../#hyperlinkedrelatedfield" > HyperlinkedRelatedField< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../#slugrelatedfield" > SlugRelatedField< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../#hyperlinkedidentityfield" > HyperlinkedIdentityField< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li class = "main" >
2019-07-15 22:12:34 +03:00
< a href = "../../#nested-relationships" > Nested relationships< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../#example" > Example< / a >
2014-11-25 19:04:38 +03:00
< / li >
2016-09-29 23:29:51 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../#writable-nested-serializers" > Writable nested serializers< / a >
2016-09-29 23:29:51 +03:00
< / li >
2015-08-06 16:31:52 +03:00
2014-11-25 19:04:38 +03:00
< li class = "main" >
2019-07-15 22:12:34 +03:00
< a href = "../../#custom-relational-fields" > Custom relational fields< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../#example_1" > Example< / a >
2014-11-25 19:04:38 +03:00
< / li >
2015-08-06 16:31:52 +03:00
< li class = "main" >
2019-07-15 22:12:34 +03:00
< a href = "../../#custom-hyperlinked-fields" > Custom hyperlinked fields< / a >
2015-08-06 16:31:52 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../#example_2" > Example< / a >
2015-08-06 16:31:52 +03:00
< / li >
2014-11-25 19:04:38 +03:00
< li class = "main" >
2019-07-15 22:12:34 +03:00
< a href = "../../#further-notes" > Further notes< / a >
2014-11-25 19:04:38 +03:00
< / li >
2014-12-01 15:20:07 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../#the-queryset-argument" > The queryset argument< / a >
2014-12-01 15:20:07 +03:00
< / li >
2015-08-11 18:21:50 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../#customizing-the-html-display" > Customizing the HTML display< / a >
2015-08-11 18:21:50 +03:00
< / li >
2015-08-24 13:04:47 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../#select-field-cutoffs" > Select field cutoffs< / a >
2015-08-24 13:04:47 +03:00
< / li >
2014-11-25 19:04:38 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../#reverse-relations" > Reverse relations< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../#generic-relationships" > Generic relationships< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../#manytomanyfields-with-a-through-model" > ManyToManyFields with a Through Model< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li class = "main" >
2019-07-15 22:12:34 +03:00
< a href = "../../#third-party-packages" > Third Party Packages< / a >
2014-11-25 19:04:38 +03:00
< / li >
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../#drf-nested-routers" > DRF Nested Routers< / a >
2014-11-25 19:04:38 +03:00
< / li >
2016-03-14 10:52:29 +03:00
< li >
2019-07-15 22:12:34 +03:00
< a href = "../../#rest-framework-generic-relations" > Rest Framework Generic Relations< / a >
2016-03-14 10:52:29 +03:00
< / li >
2014-11-25 19:04:38 +03:00
2016-05-26 13:48:39 +03:00
< div class = "promo" >
< hr / >
< div id = "sidebarInclude" >
< / div >
2014-11-25 19:04:38 +03:00
< / ul >
2014-01-03 17:26:35 +04:00
2013-11-17 22:26:41 +04:00
< / div >
< / div >
< div id = "main-content" class = "span9" >
2014-11-25 19:04:38 +03:00
2015-06-04 17:37:22 +03:00
2018-10-16 15:02:48 +03:00
< a class = "github" href = "https://github.com/encode/django-rest-framework/tree/master/rest_framework/relations.py" >
< span class = "label label-info" > relations.py< / span >
2015-06-04 17:37:22 +03:00
< / a >
2014-11-25 19:04:38 +03:00
2015-11-04 17:59:23 +03:00
< h1 id = "serializer-relations" > < a class = "toclink" href = "#serializer-relations" > Serializer relations< / a > < / h1 >
2013-11-17 22:26:41 +04:00
< blockquote >
2019-01-16 16:29:55 +03:00
< p > Data structures, not algorithms, are central to programming.< / p >
< p > — < a href = "http://users.ece.utexas.edu/~adnan/pike.html" > Rob Pike< / a > < / p >
2013-11-17 22:26:41 +04:00
< / blockquote >
< p > Relational fields are used to represent model relationships. They can be applied to < code > ForeignKey< / code > , < code > ManyToManyField< / code > and < code > OneToOneField< / code > relationships, as well as to reverse relationships, and custom relationships such as < code > GenericForeignKey< / code > .< / p >
< hr / >
< p > < strong > Note:< / strong > The relational fields are declared in < code > relations.py< / code > , but by convention you should import them from the < code > serializers< / code > module, using < code > from rest_framework import serializers< / code > and refer to fields as < code > serializers.< FieldName> < / code > .< / p >
< hr / >
2015-11-04 17:59:23 +03:00
< h4 id = "inspecting-relationships" > < a class = "toclink" href = "#inspecting-relationships" > Inspecting relationships.< / a > < / h4 >
2014-12-01 15:20:07 +03:00
< p > When using the < code > ModelSerializer< / code > class, serializer fields and relationships will be automatically generated for you. Inspecting these automatically generated fields can be a useful tool for determining how to customize the relationship style.< / p >
< p > To do so, open the Django shell, using < code > python manage.py shell< / code > , then import the serializer class, instantiate it, and print the object representation…< / p >
< pre > < code > > > > from myapp.serializers import AccountSerializer
> > > serializer = AccountSerializer()
2019-01-16 16:29:55 +03:00
> > > print(repr(serializer))
2014-12-01 15:20:07 +03:00
AccountSerializer():
id = IntegerField(label='ID', read_only=True)
name = CharField(allow_blank=True, max_length=100, required=False)
owner = PrimaryKeyRelatedField(queryset=User.objects.all())
< / code > < / pre >
2015-11-04 17:59:23 +03:00
< h1 id = "api-reference" > < a class = "toclink" href = "#api-reference" > API Reference< / a > < / h1 >
2013-11-17 22:26:41 +04:00
< p > In order to explain the various types of relational fields, we'll use a couple of simple models for our examples. Our models will be for music albums, and the tracks listed on each album.< / p >
2014-11-25 19:04:38 +03:00
< pre > < code > class Album(models.Model):
2013-11-17 22:26:41 +04:00
album_name = models.CharField(max_length=100)
artist = models.CharField(max_length=100)
class Track(models.Model):
2016-11-01 14:32:46 +03:00
album = models.ForeignKey(Album, related_name='tracks', on_delete=models.CASCADE)
2013-11-17 22:26:41 +04:00
order = models.IntegerField()
title = models.CharField(max_length=100)
duration = models.IntegerField()
class Meta:
2019-07-15 14:38:39 +03:00
unique_together = ['album', 'order']
2015-05-14 12:03:42 +03:00
ordering = ['order']
2013-11-17 22:26:41 +04:00
2019-03-03 22:21:22 +03:00
def __str__(self):
2013-11-17 22:26:41 +04:00
return '%d: %s' % (self.order, self.title)
< / code > < / pre >
2015-11-04 17:59:23 +03:00
< h2 id = "stringrelatedfield" > < a class = "toclink" href = "#stringrelatedfield" > StringRelatedField< / a > < / h2 >
2019-03-03 22:21:22 +03:00
< p > < code > StringRelatedField< / code > may be used to represent the target of the relationship using its < code > __str__< / code > method.< / p >
2013-11-17 22:26:41 +04:00
< p > For example, the following serializer.< / p >
2014-11-25 19:04:38 +03:00
< pre > < code > class AlbumSerializer(serializers.ModelSerializer):
2014-12-01 15:20:07 +03:00
tracks = serializers.StringRelatedField(many=True)
2013-11-17 22:26:41 +04:00
class Meta:
model = Album
2019-07-15 14:38:39 +03:00
fields = ['album_name', 'artist', 'tracks']
2013-11-17 22:26:41 +04:00
< / code > < / pre >
< p > Would serialize to the following representation.< / p >
2014-11-25 19:04:38 +03:00
< pre > < code > {
2013-11-17 22:26:41 +04:00
'album_name': 'Things We Lost In The Fire',
'artist': 'Low',
'tracks': [
'1: Sunflower',
'2: Whitetail',
'3: Dinosaur Act',
...
]
}
< / code > < / pre >
< p > This field is read only.< / p >
< p > < strong > Arguments< / strong > :< / p >
< ul >
< li > < code > many< / code > - If applied to a to-many relationship, you should set this argument to < code > True< / code > .< / li >
< / ul >
2015-11-04 17:59:23 +03:00
< h2 id = "primarykeyrelatedfield" > < a class = "toclink" href = "#primarykeyrelatedfield" > PrimaryKeyRelatedField< / a > < / h2 >
2013-11-17 22:26:41 +04:00
< p > < code > PrimaryKeyRelatedField< / code > may be used to represent the target of the relationship using its primary key.< / p >
< p > For example, the following serializer:< / p >
2014-11-25 19:04:38 +03:00
< pre > < code > class AlbumSerializer(serializers.ModelSerializer):
2013-11-17 22:26:41 +04:00
tracks = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
class Meta:
model = Album
2019-07-15 14:38:39 +03:00
fields = ['album_name', 'artist', 'tracks']
2013-11-17 22:26:41 +04:00
< / code > < / pre >
< p > Would serialize to a representation like this:< / p >
2014-11-25 19:04:38 +03:00
< pre > < code > {
2016-10-14 16:33:49 +03:00
'album_name': 'Undun',
'artist': 'The Roots',
2013-11-17 22:26:41 +04:00
'tracks': [
89,
90,
91,
...
]
}
< / code > < / pre >
< p > By default this field is read-write, although you can change this behavior using the < code > read_only< / code > flag.< / p >
< p > < strong > Arguments< / strong > :< / p >
< ul >
2014-12-01 15:20:07 +03:00
< li > < code > queryset< / code > - The queryset used for model instance lookups when validating the field input. Relationships must either set a queryset explicitly, or set < code > read_only=True< / code > .< / li >
2013-11-17 22:26:41 +04:00
< li > < code > many< / code > - If applied to a to-many relationship, you should set this argument to < code > True< / code > .< / li >
2014-12-01 15:20:07 +03:00
< li > < code > allow_null< / code > - If set to < code > True< / code > , the field will accept values of < code > None< / code > or the empty string for nullable relationships. Defaults to < code > False< / code > .< / li >
2015-06-23 14:05:53 +03:00
< li > < code > pk_field< / code > - Set to a field to control serialization/deserialization of the primary key's value. For example, < code > pk_field=UUIDField(format='hex')< / code > would serialize a UUID primary key into its compact hex representation.< / li >
2013-11-17 22:26:41 +04:00
< / ul >
2015-11-04 17:59:23 +03:00
< h2 id = "hyperlinkedrelatedfield" > < a class = "toclink" href = "#hyperlinkedrelatedfield" > HyperlinkedRelatedField< / a > < / h2 >
2013-11-17 22:26:41 +04:00
< p > < code > HyperlinkedRelatedField< / code > may be used to represent the target of the relationship using a hyperlink.< / p >
< p > For example, the following serializer:< / p >
2014-11-25 19:04:38 +03:00
< pre > < code > class AlbumSerializer(serializers.ModelSerializer):
2014-12-01 15:20:07 +03:00
tracks = serializers.HyperlinkedRelatedField(
many=True,
read_only=True,
view_name='track-detail'
)
2013-11-17 22:26:41 +04:00
class Meta:
model = Album
2019-07-15 14:38:39 +03:00
fields = ['album_name', 'artist', 'tracks']
2013-11-17 22:26:41 +04:00
< / code > < / pre >
< p > Would serialize to a representation like this:< / p >
2014-11-25 19:04:38 +03:00
< pre > < code > {
2013-11-17 22:26:41 +04:00
'album_name': 'Graceland',
'artist': 'Paul Simon',
'tracks': [
'http://www.example.com/api/tracks/45/',
'http://www.example.com/api/tracks/46/',
'http://www.example.com/api/tracks/47/',
...
]
}
< / code > < / pre >
< p > By default this field is read-write, although you can change this behavior using the < code > read_only< / code > flag.< / p >
2015-08-06 16:31:52 +03:00
< hr / >
< p > < strong > Note< / strong > : This field is designed for objects that map to a URL that accepts a single URL keyword argument, as set using the < code > lookup_field< / code > and < code > lookup_url_kwarg< / code > arguments.< / p >
< p > This is suitable for URLs that contain a single primary key or slug argument as part of the URL.< / p >
< p > If you require more complex hyperlinked representation you'll need to customize the field, as described in the < a href = "#custom-hyperlinked-fields" > custom hyperlinked fields< / a > section, below.< / p >
< hr / >
2013-11-17 22:26:41 +04:00
< p > < strong > Arguments< / strong > :< / p >
< ul >
2018-10-11 16:48:33 +03:00
< li > < code > view_name< / code > - The view name that should be used as the target of the relationship. If you're using < a href = "https://www.django-rest-framework.org/api-guide/routers#defaultrouter" > the standard router classes< / a > this will be a string with the format < code > < modelname> -detail< / code > . < strong > required< / strong > .< / li >
2014-12-01 15:20:07 +03:00
< li > < code > queryset< / code > - The queryset used for model instance lookups when validating the field input. Relationships must either set a queryset explicitly, or set < code > read_only=True< / code > .< / li >
2013-11-17 22:26:41 +04:00
< li > < code > many< / code > - If applied to a to-many relationship, you should set this argument to < code > True< / code > .< / li >
2014-12-01 15:20:07 +03:00
< li > < code > allow_null< / code > - If set to < code > True< / code > , the field will accept values of < code > None< / code > or the empty string for nullable relationships. Defaults to < code > False< / code > .< / li >
2013-11-17 22:26:41 +04:00
< li > < code > lookup_field< / code > - The field on the target that should be used for the lookup. Should correspond to a URL keyword argument on the referenced view. Default is < code > 'pk'< / code > .< / li >
2014-12-01 15:20:07 +03:00
< li > < code > lookup_url_kwarg< / code > - The name of the keyword argument defined in the URL conf that corresponds to the lookup field. Defaults to using the same value as < code > lookup_field< / code > .< / li >
2013-11-17 22:26:41 +04:00
< li > < code > format< / code > - If using format suffixes, hyperlinked fields will use the same format suffix for the target unless overridden by using the < code > format< / code > argument.< / li >
< / ul >
2015-11-04 17:59:23 +03:00
< h2 id = "slugrelatedfield" > < a class = "toclink" href = "#slugrelatedfield" > SlugRelatedField< / a > < / h2 >
2013-11-17 22:26:41 +04:00
< p > < code > SlugRelatedField< / code > may be used to represent the target of the relationship using a field on the target.< / p >
< p > For example, the following serializer:< / p >
2014-11-25 19:04:38 +03:00
< pre > < code > class AlbumSerializer(serializers.ModelSerializer):
2014-12-01 15:20:07 +03:00
tracks = serializers.SlugRelatedField(
many=True,
read_only=True,
slug_field='title'
)
2013-11-17 22:26:41 +04:00
class Meta:
model = Album
2019-07-15 14:38:39 +03:00
fields = ['album_name', 'artist', 'tracks']
2013-11-17 22:26:41 +04:00
< / code > < / pre >
< p > Would serialize to a representation like this:< / p >
2014-11-25 19:04:38 +03:00
< pre > < code > {
2013-11-17 22:26:41 +04:00
'album_name': 'Dear John',
'artist': 'Loney Dear',
'tracks': [
'Airport Surroundings',
'Everything Turns to You',
'I Was Only Going Out',
...
]
}
< / code > < / pre >
< p > By default this field is read-write, although you can change this behavior using the < code > read_only< / code > flag.< / p >
< p > When using < code > SlugRelatedField< / code > as a read-write field, you will normally want to ensure that the slug field corresponds to a model field with < code > unique=True< / code > .< / p >
< p > < strong > Arguments< / strong > :< / p >
< ul >
< li > < code > slug_field< / code > - The field on the target that should be used to represent it. This should be a field that uniquely identifies any given instance. For example, < code > username< / code > . < strong > required< / strong > < / li >
2014-12-01 15:20:07 +03:00
< li > < code > queryset< / code > - The queryset used for model instance lookups when validating the field input. Relationships must either set a queryset explicitly, or set < code > read_only=True< / code > .< / li >
2013-11-17 22:26:41 +04:00
< li > < code > many< / code > - If applied to a to-many relationship, you should set this argument to < code > True< / code > .< / li >
2014-12-01 15:20:07 +03:00
< li > < code > allow_null< / code > - If set to < code > True< / code > , the field will accept values of < code > None< / code > or the empty string for nullable relationships. Defaults to < code > False< / code > .< / li >
2013-11-17 22:26:41 +04:00
< / ul >
2015-11-04 17:59:23 +03:00
< h2 id = "hyperlinkedidentityfield" > < a class = "toclink" href = "#hyperlinkedidentityfield" > HyperlinkedIdentityField< / a > < / h2 >
2013-11-17 22:26:41 +04:00
< p > This field can be applied as an identity relationship, such as the < code > 'url'< / code > field on a HyperlinkedModelSerializer. It can also be used for an attribute on the object. For example, the following serializer:< / p >
2014-11-25 19:04:38 +03:00
< pre > < code > class AlbumSerializer(serializers.HyperlinkedModelSerializer):
2013-11-17 22:26:41 +04:00
track_listing = serializers.HyperlinkedIdentityField(view_name='track-list')
class Meta:
model = Album
2019-07-15 14:38:39 +03:00
fields = ['album_name', 'artist', 'track_listing']
2013-11-17 22:26:41 +04:00
< / code > < / pre >
< p > Would serialize to a representation like this:< / p >
2014-11-25 19:04:38 +03:00
< pre > < code > {
2013-11-17 22:26:41 +04:00
'album_name': 'The Eraser',
'artist': 'Thom Yorke',
'track_listing': 'http://www.example.com/api/track_list/12/',
}
< / code > < / pre >
< p > This field is always read-only.< / p >
< p > < strong > Arguments< / strong > :< / p >
< ul >
2018-10-11 16:48:33 +03:00
< li > < code > view_name< / code > - The view name that should be used as the target of the relationship. If you're using < a href = "https://www.django-rest-framework.org/api-guide/routers#defaultrouter" > the standard router classes< / a > this will be a string with the format < code > < model_name> -detail< / code > . < strong > required< / strong > .< / li >
2013-11-17 22:26:41 +04:00
< li > < code > lookup_field< / code > - The field on the target that should be used for the lookup. Should correspond to a URL keyword argument on the referenced view. Default is < code > 'pk'< / code > .< / li >
2015-01-10 12:41:12 +03:00
< li > < code > lookup_url_kwarg< / code > - The name of the keyword argument defined in the URL conf that corresponds to the lookup field. Defaults to using the same value as < code > lookup_field< / code > .< / li >
2013-11-17 22:26:41 +04:00
< li > < code > format< / code > - If using format suffixes, hyperlinked fields will use the same format suffix for the target unless overridden by using the < code > format< / code > argument.< / li >
< / ul >
< hr / >
2015-11-04 17:59:23 +03:00
< h1 id = "nested-relationships" > < a class = "toclink" href = "#nested-relationships" > Nested relationships< / a > < / h1 >
2013-11-17 22:26:41 +04:00
< p > Nested relationships can be expressed by using serializers as fields.< / p >
< p > If the field is used to represent a to-many relationship, you should add the < code > many=True< / code > flag to the serializer field.< / p >
2015-11-04 17:59:23 +03:00
< h2 id = "example" > < a class = "toclink" href = "#example" > Example< / a > < / h2 >
2013-11-17 22:26:41 +04:00
< p > For example, the following serializer:< / p >
2014-11-25 19:04:38 +03:00
< pre > < code > class TrackSerializer(serializers.ModelSerializer):
2013-11-17 22:26:41 +04:00
class Meta:
model = Track
2019-07-15 14:38:39 +03:00
fields = ['order', 'title', 'duration']
2013-11-17 22:26:41 +04:00
class AlbumSerializer(serializers.ModelSerializer):
2014-12-01 15:20:07 +03:00
tracks = TrackSerializer(many=True, read_only=True)
2013-11-17 22:26:41 +04:00
class Meta:
model = Album
2019-07-15 14:38:39 +03:00
fields = ['album_name', 'artist', 'tracks']
2013-11-17 22:26:41 +04:00
< / code > < / pre >
< p > Would serialize to a nested representation like this:< / p >
2015-08-06 16:31:52 +03:00
< pre > < code > > > > album = Album.objects.create(album_name="The Grey Album", artist='Danger Mouse')
> > > Track.objects.create(album=album, order=1, title='Public Service Announcement', duration=245)
< Track: Track object>
> > > Track.objects.create(album=album, order=2, title='What More Can I Say', duration=264)
< Track: Track object>
> > > Track.objects.create(album=album, order=3, title='Encore', duration=159)
< Track: Track object>
> > > serializer = AlbumSerializer(instance=album)
> > > serializer.data
{
2013-11-17 22:26:41 +04:00
'album_name': 'The Grey Album',
'artist': 'Danger Mouse',
'tracks': [
2015-08-06 16:31:52 +03:00
{'order': 1, 'title': 'Public Service Announcement', 'duration': 245},
{'order': 2, 'title': 'What More Can I Say', 'duration': 264},
{'order': 3, 'title': 'Encore', 'duration': 159},
2013-11-17 22:26:41 +04:00
...
],
}
< / code > < / pre >
2016-09-29 23:29:51 +03:00
< h2 id = "writable-nested-serializers" > < a class = "toclink" href = "#writable-nested-serializers" > Writable nested serializers< / a > < / h2 >
2015-10-28 14:35:39 +03:00
< p > By default nested serializers are read-only. If you want to support write-operations to a nested serializer field you'll need to create < code > create()< / code > and/or < code > update()< / code > methods in order to explicitly specify how the child relationships should be saved.< / p >
2015-08-06 16:31:52 +03:00
< pre > < code > class TrackSerializer(serializers.ModelSerializer):
class Meta:
model = Track
2019-07-15 14:38:39 +03:00
fields = ['order', 'title', 'duration']
2015-08-06 16:31:52 +03:00
class AlbumSerializer(serializers.ModelSerializer):
tracks = TrackSerializer(many=True)
class Meta:
model = Album
2019-07-15 14:38:39 +03:00
fields = ['album_name', 'artist', 'tracks']
2015-08-06 16:31:52 +03:00
def create(self, validated_data):
tracks_data = validated_data.pop('tracks')
album = Album.objects.create(**validated_data)
for track_data in tracks_data:
Track.objects.create(album=album, **track_data)
return album
> > > data = {
'album_name': 'The Grey Album',
'artist': 'Danger Mouse',
'tracks': [
{'order': 1, 'title': 'Public Service Announcement', 'duration': 245},
{'order': 2, 'title': 'What More Can I Say', 'duration': 264},
{'order': 3, 'title': 'Encore', 'duration': 159},
],
}
> > > serializer = AlbumSerializer(data=data)
> > > serializer.is_valid()
True
> > > serializer.save()
< Album: Album object>
< / code > < / pre >
2016-09-29 23:29:51 +03:00
< hr / >
2015-11-04 17:59:23 +03:00
< h1 id = "custom-relational-fields" > < a class = "toclink" href = "#custom-relational-fields" > Custom relational fields< / a > < / h1 >
2016-09-29 23:29:51 +03:00
< p > In rare cases where none of the existing relational styles fit the representation you need,
you can implement a completely custom relational field, that describes exactly how the
output representation should be generated from the model instance.< / p >
2014-12-01 15:20:07 +03:00
< p > To implement a custom relational field, you should override < code > RelatedField< / code > , and implement the < code > .to_representation(self, value)< / code > method. This method takes the target of the field as the < code > value< / code > argument, and should return the representation that should be used to serialize the target. The < code > value< / code > argument will typically be a model instance.< / p >
< p > If you want to implement a read-write relational field, you must also implement the < code > .to_internal_value(self, data)< / code > method.< / p >
2016-02-05 18:25:03 +03:00
< p > To provide a dynamic queryset based on the < code > context< / code > , you can also override < code > .get_queryset(self)< / code > instead of specifying < code > .queryset< / code > on the class or when initializing the field.< / p >
2015-11-04 17:59:23 +03:00
< h2 id = "example_1" > < a class = "toclink" href = "#example_1" > Example< / a > < / h2 >
2015-05-14 12:03:42 +03:00
< p > For example, we could define a relational field to serialize a track to a custom string representation, using its ordering, title, and duration.< / p >
2014-11-25 19:04:38 +03:00
< pre > < code > import time
2013-11-17 22:26:41 +04:00
class TrackListingField(serializers.RelatedField):
2014-12-01 15:20:07 +03:00
def to_representation(self, value):
2013-11-17 22:26:41 +04:00
duration = time.strftime('%M:%S', time.gmtime(value.duration))
return 'Track %d: %s (%s)' % (value.order, value.name, duration)
class AlbumSerializer(serializers.ModelSerializer):
tracks = TrackListingField(many=True)
class Meta:
model = Album
2019-07-15 14:38:39 +03:00
fields = ['album_name', 'artist', 'tracks']
2013-11-17 22:26:41 +04:00
< / code > < / pre >
< p > This custom field would then serialize to the following representation.< / p >
2014-11-25 19:04:38 +03:00
< pre > < code > {
2013-11-17 22:26:41 +04:00
'album_name': 'Sometimes I Wish We Were an Eagle',
'artist': 'Bill Callahan',
'tracks': [
'Track 1: Jim Cain (04:39)',
'Track 2: Eid Ma Clack Shaw (04:19)',
'Track 3: The Wind and the Dove (04:34)',
...
]
}
< / code > < / pre >
< hr / >
2015-11-04 17:59:23 +03:00
< h1 id = "custom-hyperlinked-fields" > < a class = "toclink" href = "#custom-hyperlinked-fields" > Custom hyperlinked fields< / a > < / h1 >
2015-08-06 16:31:52 +03:00
< p > In some cases you may need to customize the behavior of a hyperlinked field, in order to represent URLs that require more than a single lookup field.< / p >
< p > You can achieve this by overriding < code > HyperlinkedRelatedField< / code > . There are two methods that may be overridden:< / p >
< p > < strong > get_url(self, obj, view_name, request, format)< / strong > < / p >
< p > The < code > get_url< / code > method is used to map the object instance to its URL representation.< / p >
< p > May raise a < code > NoReverseMatch< / code > if the < code > view_name< / code > and < code > lookup_field< / code >
attributes are not configured to correctly match the URL conf.< / p >
2018-10-11 16:48:33 +03:00
< p > < strong > get_object(self, view_name, view_args, view_kwargs)< / strong > < / p >
2015-08-06 16:31:52 +03:00
< p > If you want to support a writable hyperlinked field then you'll also want to override < code > get_object< / code > , in order to map incoming URLs back to the object they represent. For read-only hyperlinked fields there is no need to override this method.< / p >
< p > The return value of this method should the object that corresponds to the matched URL conf arguments.< / p >
< p > May raise an < code > ObjectDoesNotExist< / code > exception.< / p >
2015-11-04 17:59:23 +03:00
< h2 id = "example_2" > < a class = "toclink" href = "#example_2" > Example< / a > < / h2 >
2015-08-06 16:31:52 +03:00
< p > Say we have a URL for a customer object that takes two keyword arguments, like so:< / p >
< pre > < code > /api/< organization_slug> /customers/< customer_pk> /
< / code > < / pre >
< p > This cannot be represented with the default implementation, which accepts only a single lookup field.< / p >
< p > In this case we'd need to override < code > HyperlinkedRelatedField< / code > to get the behavior we want:< / p >
< pre > < code > from rest_framework import serializers
from rest_framework.reverse import reverse
class CustomerHyperlink(serializers.HyperlinkedRelatedField):
# We define these as class attributes, so we don't need to pass them as arguments.
view_name = 'customer-detail'
queryset = Customer.objects.all()
def get_url(self, obj, view_name, request, format):
url_kwargs = {
'organization_slug': obj.organization.slug,
'customer_pk': obj.pk
}
2015-11-04 17:59:23 +03:00
return reverse(view_name, kwargs=url_kwargs, request=request, format=format)
2015-08-06 16:31:52 +03:00
def get_object(self, view_name, view_args, view_kwargs):
lookup_kwargs = {
'organization__slug': view_kwargs['organization_slug'],
'pk': view_kwargs['customer_pk']
}
return self.get_queryset().get(**lookup_kwargs)
< / code > < / pre >
< p > Note that if you wanted to use this style together with the generic views then you'd also need to override < code > .get_object< / code > on the view in order to get the correct lookup behavior.< / p >
< p > Generally we recommend a flat style for API representations where possible, but the nested URL style can also be reasonable when used in moderation.< / p >
< hr / >
2015-11-04 17:59:23 +03:00
< h1 id = "further-notes" > < a class = "toclink" href = "#further-notes" > Further notes< / a > < / h1 >
< h2 id = "the-queryset-argument" > < a class = "toclink" href = "#the-queryset-argument" > The < code > queryset< / code > argument< / a > < / h2 >
2014-12-01 15:20:07 +03:00
< p > The < code > queryset< / code > argument is only ever required for < em > writable< / em > relationship field, in which case it is used for performing the model instance lookup, that maps from the primitive user input, into a model instance.< / p >
< p > In version 2.x a serializer class could < em > sometimes< / em > automatically determine the < code > queryset< / code > argument < em > if< / em > a < code > ModelSerializer< / code > class was being used.< / p >
< p > This behavior is now replaced with < em > always< / em > using an explicit < code > queryset< / code > argument for writable relational fields.< / p >
< p > Doing so reduces the amount of hidden 'magic' that < code > ModelSerializer< / code > provides, makes the behavior of the field more clear, and ensures that it is trivial to move between using the < code > ModelSerializer< / code > shortcut, or using fully explicit < code > Serializer< / code > classes.< / p >
2015-11-04 17:59:23 +03:00
< h2 id = "customizing-the-html-display" > < a class = "toclink" href = "#customizing-the-html-display" > Customizing the HTML display< / a > < / h2 >
2015-08-11 18:21:50 +03:00
< p > The built-in < code > __str__< / code > method of the model will be used to generate string representations of the objects used to populate the < code > choices< / code > property. These choices are used to populate select HTML inputs in the browsable API.< / p >
< p > To provide customized representations for such inputs, override < code > display_value()< / code > of a < code > RelatedField< / code > subclass. This method will receive a model object, and should return a string suitable for representing it. For example:< / p >
< pre > < code > class TrackPrimaryKeyRelatedField(serializers.PrimaryKeyRelatedField):
def display_value(self, instance):
return 'Track: %s' % (instance.title)
< / code > < / pre >
2015-11-04 17:59:23 +03:00
< h2 id = "select-field-cutoffs" > < a class = "toclink" href = "#select-field-cutoffs" > Select field cutoffs< / a > < / h2 >
2015-08-24 13:04:47 +03:00
< p > When rendered in the browsable API relational fields will default to only displaying a maximum of 1000 selectable items. If more items are present then a disabled option with "More than 1000 items…" will be displayed.< / p >
< p > This behavior is intended to prevent a template from being unable to render in an acceptable timespan due to a very large number of relationships being displayed.< / p >
< p > There are two keyword arguments you can use to control this behavior:< / p >
< ul >
< li > < code > html_cutoff< / code > - If set this will be the maximum number of choices that will be displayed by a HTML select drop down. Set to < code > None< / code > to disable any limiting. Defaults to < code > 1000< / code > .< / li >
< li > < code > html_cutoff_text< / code > - If set this will display a textual indicator if the maximum number of items have been cutoff in an HTML select drop down. Defaults to < code > "More than {count} items…"< / code > < / li >
< / ul >
2016-10-14 16:33:49 +03:00
< p > You can also control these globally using the settings < code > HTML_SELECT_CUTOFF< / code > and < code > HTML_SELECT_CUTOFF_TEXT< / code > .< / p >
2015-08-24 13:04:47 +03:00
< p > In cases where the cutoff is being enforced you may want to instead use a plain input field in the HTML form. You can do so using the < code > style< / code > keyword argument. For example:< / p >
< pre > < code > assigned_to = serializers.SlugRelatedField(
queryset=User.objects.all(),
2016-02-05 18:25:03 +03:00
slug_field='username',
2015-08-24 13:04:47 +03:00
style={'base_template': 'input.html'}
)
< / code > < / pre >
2015-11-04 17:59:23 +03:00
< h2 id = "reverse-relations" > < a class = "toclink" href = "#reverse-relations" > Reverse relations< / a > < / h2 >
2013-11-17 22:26:41 +04:00
< p > Note that reverse relationships are not automatically included by the < code > ModelSerializer< / code > and < code > HyperlinkedModelSerializer< / code > classes. To include a reverse relationship, you must explicitly add it to the fields list. For example:< / p >
2014-11-25 19:04:38 +03:00
< pre > < code > class AlbumSerializer(serializers.ModelSerializer):
2013-11-17 22:26:41 +04:00
class Meta:
2019-07-15 14:38:39 +03:00
fields = ['tracks', ...]
2013-11-17 22:26:41 +04:00
< / code > < / pre >
< p > You'll normally want to ensure that you've set an appropriate < code > related_name< / code > argument on the relationship, that you can use as the field name. For example:< / p >
2014-11-25 19:04:38 +03:00
< pre > < code > class Track(models.Model):
2016-11-01 14:32:46 +03:00
album = models.ForeignKey(Album, related_name='tracks', on_delete=models.CASCADE)
2013-11-17 22:26:41 +04:00
...
< / code > < / pre >
< p > If you have not set a related name for the reverse relationship, you'll need to use the automatically generated related name in the < code > fields< / code > argument. For example:< / p >
2014-11-25 19:04:38 +03:00
< pre > < code > class AlbumSerializer(serializers.ModelSerializer):
2013-11-17 22:26:41 +04:00
class Meta:
2019-07-15 14:38:39 +03:00
fields = ['track_set', ...]
2013-11-17 22:26:41 +04:00
< / code > < / pre >
2016-12-09 19:07:34 +03:00
< p > See the Django documentation on < a href = "https://docs.djangoproject.com/en/stable/topics/db/queries/#following-relationships-backward" > reverse relationships< / a > for more details.< / p >
2015-11-04 17:59:23 +03:00
< h2 id = "generic-relationships" > < a class = "toclink" href = "#generic-relationships" > Generic relationships< / a > < / h2 >
2016-05-26 13:48:39 +03:00
< p > If you want to serialize a generic foreign key, you need to define a custom field, to determine explicitly how you want to serialize the targets of the relationship.< / p >
2013-11-17 22:26:41 +04:00
< p > For example, given the following model for a tag, which has a generic relationship with other arbitrary models:< / p >
2014-11-25 19:04:38 +03:00
< pre > < code > class TaggedItem(models.Model):
2013-11-17 22:26:41 +04:00
"""
Tags arbitrary model instances using a generic relation.
2016-12-09 19:07:34 +03:00
See: https://docs.djangoproject.com/en/stable/ref/contrib/contenttypes/
2013-11-17 22:26:41 +04:00
"""
tag_name = models.SlugField()
2016-11-01 14:32:46 +03:00
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
2013-11-17 22:26:41 +04:00
object_id = models.PositiveIntegerField()
tagged_object = GenericForeignKey('content_type', 'object_id')
2019-03-03 22:21:22 +03:00
def __str__(self):
2015-09-11 15:06:48 +03:00
return self.tag_name
2013-11-17 22:26:41 +04:00
< / code > < / pre >
2016-03-14 10:52:29 +03:00
< p > And the following two models, which may have associated tags:< / p >
2014-11-25 19:04:38 +03:00
< pre > < code > class Bookmark(models.Model):
2013-11-17 22:26:41 +04:00
"""
A bookmark consists of a URL, and 0 or more descriptive tags.
"""
url = models.URLField()
tags = GenericRelation(TaggedItem)
class Note(models.Model):
"""
A note consists of some text, and 0 or more descriptive tags.
"""
text = models.CharField(max_length=1000)
tags = GenericRelation(TaggedItem)
< / code > < / pre >
< p > We could define a custom field that could be used to serialize tagged instances, using the type of each instance to determine how it should be serialized.< / p >
2014-11-25 19:04:38 +03:00
< pre > < code > class TaggedObjectRelatedField(serializers.RelatedField):
2013-11-17 22:26:41 +04:00
"""
A custom field to use for the `tagged_object` generic relationship.
"""
2014-12-01 15:20:07 +03:00
def to_representation(self, value):
2013-11-17 22:26:41 +04:00
"""
Serialize tagged objects to a simple textual representation.
2014-11-25 19:04:38 +03:00
"""
2013-11-17 22:26:41 +04:00
if isinstance(value, Bookmark):
return 'Bookmark: ' + value.url
elif isinstance(value, Note):
return 'Note: ' + value.text
raise Exception('Unexpected type of tagged object')
< / code > < / pre >
2014-12-17 19:23:42 +03:00
< p > If you need the target of the relationship to have a nested representation, you can use the required serializers inside the < code > .to_representation()< / code > method:< / p >
2014-12-01 15:20:07 +03:00
< pre > < code > def to_representation(self, value):
2013-11-17 22:26:41 +04:00
"""
Serialize bookmark instances using a bookmark serializer,
and note instances using a note serializer.
2014-11-25 19:04:38 +03:00
"""
2013-11-17 22:26:41 +04:00
if isinstance(value, Bookmark):
serializer = BookmarkSerializer(value)
elif isinstance(value, Note):
serializer = NoteSerializer(value)
else:
raise Exception('Unexpected type of tagged object')
return serializer.data
< / code > < / pre >
< p > Note that reverse generic keys, expressed using the < code > GenericRelation< / code > field, can be serialized using the regular relational field types, since the type of the target in the relationship is always known.< / p >
2016-12-09 19:07:34 +03:00
< p > For more information see < a href = "https://docs.djangoproject.com/en/stable/ref/contrib/contenttypes/#id1" > the Django documentation on generic relations< / a > .< / p >
2015-11-04 17:59:23 +03:00
< h2 id = "manytomanyfields-with-a-through-model" > < a class = "toclink" href = "#manytomanyfields-with-a-through-model" > ManyToManyFields with a Through Model< / a > < / h2 >
2013-11-17 22:26:41 +04:00
< p > By default, relational fields that target a < code > ManyToManyField< / code > with a
< code > through< / code > model specified are set to read-only.< / p >
< p > If you explicitly specify a relational field pointing to a
< code > ManyToManyField< / code > with a through model, be sure to set < code > read_only< / code >
to < code > True< / code > .< / p >
2019-06-04 14:04:28 +03:00
< p > If you wish to represent < a href = "https://docs.djangoproject.com/en/2.2/topics/db/models/#intermediary-manytomany" > extra fields on a through model< / a > then you may serialize the through model as < a href = "https://www.django-rest-framework.org/api-guide/serializers/#dealing-with-nested-objects" > a nested object< / a > .< / p >
2013-11-17 22:26:41 +04:00
< hr / >
2015-11-04 17:59:23 +03:00
< h1 id = "third-party-packages" > < a class = "toclink" href = "#third-party-packages" > Third Party Packages< / a > < / h1 >
2013-12-15 00:44:09 +04:00
< p > The following third party packages are also available.< / p >
2015-11-04 17:59:23 +03:00
< h2 id = "drf-nested-routers" > < a class = "toclink" href = "#drf-nested-routers" > DRF Nested Routers< / a > < / h2 >
2013-12-15 00:44:09 +04:00
< p > The < a href = "https://github.com/alanjds/drf-nested-routers" > drf-nested-routers package< / a > provides routers and relationship fields for working with nested resources.< / p >
2016-03-14 10:52:29 +03:00
< h2 id = "rest-framework-generic-relations" > < a class = "toclink" href = "#rest-framework-generic-relations" > Rest Framework Generic Relations< / a > < / h2 >
< p > The < a href = "https://github.com/Ian-Foote/rest-framework-generic-relations" > rest-framework-generic-relations< / a > library provides read/write serialization for generic foreign keys.< / p >
2015-06-04 17:37:22 +03:00
2015-06-23 14:05:53 +03:00
< / div > <!-- /span -->
< / div > <!-- /row -->
< / div > <!-- /.fluid - container -->
< / div > <!-- /.body content -->
2014-11-25 19:04:38 +03:00
< div id = "push" > < / div >
2015-06-23 14:05:53 +03:00
< / div > <!-- /.wrapper -->
2013-11-17 22:26:41 +04:00
< footer class = "span12" >
2015-10-28 14:35:39 +03:00
< p > Documentation built with < a href = "http://www.mkdocs.org/" > MkDocs< / a > .
2014-11-25 19:04:38 +03:00
< / p >
2013-11-17 22:26:41 +04:00
< / footer >
2014-11-25 19:04:38 +03:00
<!-- Le javascript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
< script src = "../../js/jquery-1.8.1-min.js" > < / script >
< script src = "../../js/prettify-1.0.js" > < / script >
< script src = "../../js/bootstrap-2.1.1-min.js" > < / script >
2019-06-04 14:04:28 +03:00
< script async src = "https://fund.django-rest-framework.org/sidebar_include.js" > < / script >
2015-06-04 17:37:22 +03:00
< script > var base _url = '../..' ; < / script >
< script src = "../../mkdocs/js/require.js" > < / script >
2014-12-11 12:55:10 +03:00
< script src = "../../js/theme.js" > < / script >
2014-11-25 19:04:38 +03:00
< script >
var shiftWindow = function() {
scrollBy(0, -50)
};
2015-06-23 14:05:53 +03:00
2014-11-25 19:04:38 +03:00
if (location.hash) shiftWindow();
window.addEventListener("hashchange", shiftWindow);
$('.dropdown-menu').on('click touchstart', function(event) {
event.stopPropagation();
});
2015-06-23 14:05:53 +03:00
// Dynamically force sidenav/dropdown to no higher than browser window
$('.side-nav, .dropdown-menu').css('max-height', window.innerHeight - 130);
2014-11-25 19:04:38 +03:00
$(function() {
$(window).resize(function() {
2015-06-23 14:05:53 +03:00
$('.side-nav, .dropdown-menu').css('max-height', window.innerHeight - 130);
2013-11-17 22:26:41 +04:00
});
2014-11-25 19:04:38 +03:00
});
< / script >
< / body >
2013-11-17 22:26:41 +04:00
2014-11-25 19:04:38 +03:00
< / html >