i'm new to django. The version i'm using is 1.11.2
I have a a schema like this.
There are many "designs" and each design can have any number of "patterns".
my design model is like below
from django.db import models
from products.models import Product
class Design(models.Model):
name = models.CharField(max_length=200)
product_id = models.ForeignKey(Product, on_delete=models.CASCADE)
price = models.CharField(max_length=200)
def __str__(self):
return self.name
My design serializer is like below
from rest_framework import serializers
from .models import Design
from rest_framework import serializers
from patterns.models import Pattern
class DesignsSerializer(serializers.ModelSerializer):
patterns = DesignPatternSerializer(read_only=True, many=True)
class Meta:
depth = 1
model = Design
fields = ('id','name','patterns')
read_only_fields = ('id','name','patterns')
The view for designs is as below
from django.shortcuts import render
from .models import Design
from .serializers import DesignsSerializer
from rest_framework import generics, filters
# Create your views here.
class ListDesignsByProducId(generics.ListCreateAPIView):
serializer_class = DesignsSerializer
def get_queryset(self):
return Design.objects.filter(product_id__exact = self.kwargs.get('product_id'))
My pattern model is like below.
from django.db import models
from datetime import date
from designs.models import Design
class Pattern(models.Model):
design_id = models.ManyToManyField(Design)
name = models.CharField(max_length=200)
def __str__(self):
return self.name
My pattern serializer is as below
from rest_framework import serializers
from .models import Pattern
class PatternSerializer(serializers.ModelSerializer):
class Meta:
depth = 1
model = Pattern
fields = ('id','design_id','name')
read_only_fields =('id','design_id','name')
Right now the api would return the details of the designs and it's associated products.
I would also like to get an array of patterns associated with the design.
In your DesignsSerializer you referred to the patterns by the name patterns without defining it in your models.
From the Django REST Framework documentation:
You'll normally want to ensure that you've set an appropriate
related_name argument on the relationship, that you can use as the
field name.
In your Pattern model:
class Pattern(models.Model):
design_id = models.ManyToManyField(Design, related_name='patterns')
...
Related
I have two models: the first is named Card and has a foreign key (named owner) to the second model (User). I'm trying to write a view that lists all the Cards owned by a User, the client selects the User by changing the URL (not query parameters).
For example, if I make a GET request to /cards/by-user-id/42/, I should get all the Cards owned by the User whose id is 42.
From what I understood, it is possible to achieve this by using an URL pattern like this : path('cards/by-user-id/<int:user_id>', my_view.as_view()) and then in the viewset I can use self.kwargs['user_id'] to get the id and then filter the data. However, I can't find how to do it using routers (more appropriated for djangorestframework). I tried with <int:user_id> in the prefix but it does not pick it up, it just considers it as a normal string, so not only the URL is incorrect (I have to type literally /cards/by-user-id/<int:user_id>/) but also kwargs doesn't contain 'user_id'.
Here is what I tried:
models.py:
from django.contrib.auth.models import User
from django.db import models
class Card(models.Model):
owner = models.ForeignKey(User, null=True, on_delete=models.SET_NULL)
serializers.py:
from rest_framework import serializers
from . import models
class CardSerializer(serializers.ModelSerializer):
owner = serializers.StringRelatedField()
class Meta:
model = models.Card
fields = ['owner', 'id']
views.py:
from rest_framework import viewsets
from . import models, serializers
class ListCardsPerUser(viewsets.ModelViewSet):
serializer_class = serializers.CardListSerializer
def get_queryset(self):
models.CardList.objects.filter(owner__id=self.kwargs['user_id'])
urls.py:
from django.urls import path, include
from rest_framework import routers
from . import views
router = routers.SimpleRouter()
router.register(r'cards/by-user-id/<int:user_id>/', views.ListCardsPerUser, basename='cards_list')
urlpatterns = [
path('', include(router.urls)),
]
I'm starting to wonder if it is even possible with routers...
Django version: 4.1 and DRF: 3.14
you should just edit your user serializer
class CardASerializer(serializers.ModelSerializer):
class Meta:
model = Card
fields = "__all__"
class UserSerializer(serializers.ModelSerializer):
cards = CardASerializer(many=True)
class Meta:
model = User
fields = "__all__"
Note that the cards is related_name
class Card(models.Model):
owner = models.ForeignKey(User, null=True,related_name="cards", on_delete=models.SET_NULL)
I have 2 models named Recipe and Step..
I have serialized both to make an API for GET request.. I want to know is there a way to create for POST request so that I can send both the data (steps and recipe) in the same request?
models.py:
from django.db import models
class Recipe(models.Model):
title = models.CharField( max_length=50)
uuid = models.CharField( max_length=100)
def __str__(self):
return f'{self.uuid}'
class Step(models.Model):
step = models.CharField(max_length=300)
uuid = models.ForeignKey(Recipe, on_delete=models.CASCADE)
def __str__(self):
return f'{self.step} - {self.uuid}'
serializers.py:
from rest_framework import serializers
from .models import *
class RecipeSerializer(serializers.ModelSerializer):
class Meta:
model = Recipe
fields = ['title', 'uuid']
class StepSerializer(serializers.ModelSerializer):
class Meta:
model = Step
fields = ['step', 'uuid']
views.py:
from django.shortcuts import render
from rest_framework.decorators import api_view
from rest_framework.response import Response
from .serializers import *
from .models import *
#api_view(['GET'])
def apiOverview(request):
api_urls = {
'List':'/recipe-list/',
'Detail View':'/recipe-detail/<str:pk>/',
'Create':'/recipe-create/',
'Update':'/recipe-update/<str:pk>/',
'Delete':'/recipe-delete/<str:pk>/',
'Steps' : '/steps/<str:pk>'
}
return Response(api_urls)
#api_view(['GET'])
def recipeList(request):
recipes = Recipe.objects.all()
serializer = RecipeSerializer(recipes, many=True)
return Response(serializer.data)
#api_view(['GET'])
def recipeDetail(request, pk):
recipe = Recipe.objects.get(uuid=pk)
recipe_serializer = RecipeSerializer(recipe, many=False)
steps = Step.objects.filter(uuid=pk)
steps_serializer = StepSerializer(steps, many=True)
return Response({
'recipe' : recipe_serializer.data,
'steps' : steps_serializer.data
})
How can I create a view for POST and handle both the models?
Try:
from rest_framework import generics
from .models import *
class StepAndRecipe(generics.CreateAPIView):
queryset = Step.objects.all()
queryset = Recipe.objects.all()
serializer_class = StepSerializer
serializer_class = RecipeSerializer
Add in urls.py:
from django.urls import path
from .views import StepAndRecipe
urlpatterns = [
path('steprecipepost', StepAndRecipe.as_view(), name='steps_recipes')
This will only work with POST! And one more thing: take care with the raw data and the HTML form, maybe theses get a little confused since you are using two models in the same view.
Using Djangorestframework I had created rest api. I have two models in my app countries and states. I had related countries model to states model using Foreign key method, But while fetching list of states in States api i am getting states names, but in the place of country i am getting countries primary key id instead of it's name how can i get all the fields of Countries instead of PK id
----------
Models.py code
class countries(models.Model):
country = models.CharField(max_length=10)
def __str__(self):
return self.country
class states(models.Model):
state = models.CharField(max_length=15)
country = models.ForeignKey(countries, on_delete=models.PROTECT)
def __str__(self):
return self.state
----------
Serializers.py code
from rest_framework import serializers
from .models import countries, states
class countiresSerializers(serializers.ModelSerializer):
class Meta:
model = countries
fields = '__all__'
class statesSerializers(serializers.ModelSerializer):
class Meta:
model = states
fields = '__all__'
----------
Viewset.py code--
from django.shortcuts import render
from django.http import HttpResponse
from django.shortcuts import get_object_or_404
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from.models import countries, states
from .serializers import countiresSerializers, statesSerializers
class countryList(APIView):
def get(self, request):
country1 = countries.objects.all()
serializer = countiresSerializers(country1, many=True)
return Response (serializer.data)
def __pos__(self):
pass
class statesList(APIView):
def get(self, request):
state = states.objects.all()
serializer = statesSerializers(state, many=True)
return Response (serializer.data)
def __pos__(self):
pass
I had attached image u can see the country displaying primary id instead of it's name, how can i get name and all other related fields of countries..
You can use depth serializer's option:
class statesSerializers(serializers.ModelSerializer):
class Meta:
model = states
fields = '__all__'
depth = 1
is there any way to show only a list of fields or excluding some of them when using django-rest-framework?
Here's my app/views.py:
from rest_framework.generics import ListAPIView
from .models import PhpbbUsers
class UsersReadView(ListAPIView):
model = PhpbbUsers
Obiously there are some user information that I don't want to show to everyone. How could I do?
Solution code
from rest_framework import generics, serializers
from .models import PhpbbUsers
class UsersSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = PhpbbUsers
fields = ('user_id', 'username', 'user_avatar')
class UsersReadView(generics.ListAPIView):
model = PhpbbUsers
serializer_class = UsersSerializer
Set the serializer_class attribute on the view.
See the quickstart for a good example: http://django-rest-framework.org/tutorial/quickstart.html
I want to create a view that is able to show a ModelForm for various different models. It does this by obtaining the content type of the model and then dynamically instantiating the model form associated with that particular model. Here is my model:
from django.db import models
class SomeModel(models.Model):
name = models.CharField(max_length=150)
def __unicode__(self):
return self.name
And inside the same app there is a forms.py with the following form:
from django.forms import ModelForm
from someapp.models import SomeModel
class SomeModelForm(ModelForm):
class Meta:
model = SomeModel
fields = ('name',)
So what I want to do inside of my view file is return the correct form for each model dynamically. I tried the following:
from django.db import models
from someapp.forms import SomeModelForm
class SomeModel(models.Model):
name = models.CharField(max_length=150)
form = SomeModelForm
def __unicode__(self):
return self.name
But it doesn't work because of the obvious circular import. Does anyone have any idea how I might go about achieving this? I tried toying with modelform_factory, but it seems to ignore any of my custom model forms in forms.py.
EDIT: I should of mentioned that I won't have an instance of the model, just the model class itself, so having a method that inside of the model doesn't work (it does, however, work if you are calling it on an instance of the model)
You could get around the circular import by importing your model form inside a method.
class SomeModel(models.Model):
name = models.CharField(max_length=150)
#staticmethod
def get_form_class():
from someapp.forms import SomeModelForm
return SomeModelForm
# in your view:
SomeModel.get_form_class()
Putting the import within a method on the model should be enough to get you around the circular import, so instead of what you have, you'd use:
class SomeModel(models.Model):
...
def get_form(self):
from someapp.forms import SomeModelForm
return SomeModelForm
You can even make it a property if you want with:
form = property(get_form)
There is a built-in func get_model for lazy importing models.
from django.db.models import get_model
SomeModel = get_model('your_app_name', 'SomeModel')
Using __import__ and getattr.
# models.py
class SomeModel(models.Model):
...
#classmethod
def get_form(cls):
try:
app = __import__(cls._meta.app_label)
forms = getattr(app, "forms")
return getattr(forms, "%sForm" % cls.__name__)
except:
return None
# forms.py
class SomeModelForm(forms.Form):
...
in a view you can get the form associate to a models like this:
# views.p
from models import SomeModel
...
def myview(request):
form = SomeModel.getform()