I have a django model
models.py
class Item(models.Model):
author = models.ForeignKey(User)
name = models.CharField('Brief summary of job', max_length=200)
created = models.DateTimeField('Created', auto_now=True,auto_now_add=True)
description = models.TextField('Description of job')
I would like to update the description field in a modelform using UpdateView. I would like to see the other fields (author,name etc) but want editing and POST disabled
forms.py
from django.forms import ModelForm
from todo.models import Item
class EditForm(ModelForm):
class Meta:
model = Item
fields = ['author', 'job_for', 'name', 'description']
urls.py
urlpatterns = patterns('',
# eg /todo/
url(r'^$', views.IndexView.as_view(), name='index'),
#eg /todo/5
url(r'^(?P<pk>\d+)/$', views.UpdateItem.as_view(), name='update_item'),
)
views.py
class UpdateItem(UpdateView):
model = Item
form_class = EditForm
template_name = 'todo/detail.html'
# Revert to a named url
success_url = reverse_lazy('index')
I have looked at the solution suggesting form.fields['field'].widget.attrs['readonly'] = True but I am unsure where to put this or how to implement
Field.disabled
New in Django 1.9.
The disabled boolean argument, when set to True, disables a form field using the disabled HTML attribute so that it won’t be editable by users. Even if a user tampers with the field’s value submitted to the server, it will be ignored in favor of the value from the form’s initial data.
def MyForm(forms.ModelForm):
class Meta:
model = MyModel
def __init__(self):
self.fields['field'].disabled = True
Related
A newbie here in the world of Django. I am struggling with creating a hyperlink for a nested route.
The error I am getting is:
Could not resolve URL for hyperlinked relationship using view name "rest:campaign-detail". You may have failed to include the related model in your API, or incorrectly configured the `lookup_field` attribute on this field.
Some project setup notes
Using django rest framework
using DRF-extensions to create the routes
Using ModelViewSet
Expected end points:
/accounts/
/accounts/< pk >/
/accounts/< pk >/campaigns/
/accounts/< pk >/campaigns/< pk >/
/accounts/< pk >/campaigns/adgroup/
/accounts/< pk >/campaigns/adgroup/< pk >/
Set a namespace of rest in urls.py
Using HyperlinkedIdentityField to create the hyperlink. It only works with the parent object i.e.
url = serializers.HyperlinkedIdentityField(view_name='rest:account-detail')
However fails with any nested object i.e.
url = serializers.HyperlinkedIdentityField(view_name='rest:campaign-detail')
The model is quiet simple, an Account can have many Campaigns, and a campaign can have many AdGroups. See code below:
models.py
from django.db import models
from django.db.models import Q
from model_utils import Choices
ORDER_COLUMN_CHOICES = Choices(
('0', 'id'),
('1', 'keyword'),
('2', 'status'),
('3', 'match_type'),
)
# Account
class Account(models.Model):
account_name = models.CharField(max_length=128)
def __str__(self):
return self.account_name
# Campaign
class Campaign(models.Model):
class Status(models.TextChoices):
Enabled = "Enabled"
Paused = "Paused"
account = models.ForeignKey(
to=Account, on_delete=models.CASCADE, related_name='campaigns'
)
campaign_name = models.CharField(max_length=128)
status = models.CharField(max_length=21, choices=Status.choices, default=Status.Paused)
def __str__(self):
return self.campaign_name
# AdGroup
class AdGroup(models.Model):
class Status(models.TextChoices):
Enabled = "Enabled"
Paused = "Paused"
campaign = models.ForeignKey(
to=Campaign, on_delete=models.CASCADE, related_name='adgroups'
)
adgroup_name = models.CharField(max_length=128)
status = models.CharField(max_length=21, choices=Status.choices, default=Status.Enabled)
def __str__(self):
return self.adgroup_name
views.py
from rest_framework import viewsets
from .serializers import *
from . import models
from rest_framework_extensions.mixins import NestedViewSetMixin
class AccountViewSet(NestedViewSetMixin, viewsets.ModelViewSet):
serializer_class = AccountSerializer
queryset = models.Account.objects.all()
class CampaignViewSet(NestedViewSetMixin, viewsets.ModelViewSet):
serializer_class = CampaignSerializer
queryset = models.Campaign.objects.all()
class AdGroupViewSet(NestedViewSetMixin, viewsets.ModelViewSet):
serializer_class = AdGroupSerializer
queryset = models.AdGroup.objects.all()
serializers.py
from rest_framework import serializers
from . import models
class CampaignSerializer(serializers.ModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name="rest:campaign-detail")
class Meta:
model = models.Campaign
fields = '__all__'
class AccountSerializer(serializers.HyperlinkedModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='rest:account-detail')
class Meta:
model = models.Account
fields = '__all__'
class AdGroupSerializer(serializers.ModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='rest:adgroup-detail')
class Meta:
model = models.AdGroup
fields = '__all__'
I have 2 URL files. The project is named Vanilla and an app named rest where the DRF logic sits.
Vanilla urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('', include('rest.urls', namespace='rest')),
path('api-auth/', include('rest_framework.urls', namespace='rest_framework')),
path('admin/', admin.site.urls)
]
Rest urls.py
from django.urls import include, path
from . import views
from rest_framework_extensions.routers import ExtendedSimpleRouter
app_name = 'rest'
router = ExtendedSimpleRouter()
(
router.register(r'accounts',
views.AccountViewSet,
basename='account')
.register(r'campaigns',
views.CampaignViewSet,
basename='campaign',
parents_query_lookups=['account__id'])
.register(r'adgroups',
views.AdGroupViewSet,
basename='adgroup',
parents_query_lookups=['campaign__account', 'campaign'])
Thank You!
use hyperlinkedModelSerializer in all of your related serializer. that should work
I am trying to develop a profile edit page in Django 3.1. I am new to this so if something is funky just say so. I copied some of this from Django edit user profile
Views.py
from myapp.forms import UserForm, UserProfileInfoForm
from django.views.generic import (View, TemplateView, UpdateView)
from myapp.models import UserProfileInfo
class UpdateProfile(UpdateView):
model = UserProfileInfoForm
fields = ['first_name', 'last_name', 'email', 'phone', 'title', 'password']
template_name = 'profile.html'
slug_field = 'username'
slug_url_kwarg = 'slug'
models.py
class UserProfileInfo(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
phone = PhoneField(blank=True, help_text='Contact phone number')
title = models.CharField(max_length=255)
system_no = models.CharField(max_length=9)
def __str__(self):
return self.user.username
forms.py
#...
from myapp.models import UserProfileInfo
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
class Meta():
model = User
fields = ('username', 'email', 'password', 'first_name', 'last_name')
class UserProfileInfoForm(forms.ModelForm):
class Meta():
model = UserProfileInfo
fields = ('phone', 'title', 'system_no')
myapp/urls.py
from django.urls import path
from . import views
app_name = 'myapp'
urlpatterns = [
path('', views.index,name='index'),
path('about/',views.AboutView.as_view(),name='about'),
path('register/', views.register,name='register'),
path('profile/', views.UpdateProfile.as_view(), name='profile'),
]
I have a link that only show after login in:
base.html (href only)
<a class="nav-link active" href="{% url 'myapp:profile' %}">Profile</a>
Can you tell me what to fix? After clicking on the above link I get an error message in the browser
AttributeError at /profile/
type object 'UserProfileInfoForm' has no attribute '_default_manager'
well you have done very good till here. Note these :
1.if you are using UpdateView class based view the model field must be the name of the model not the form.(UserProfileInfo)
2.if you are using class based view it is better for you to have a success url in class to redirect after successful attempt
3.if you are using UpdateView no need to have form in forms.py for that model. all you need is a form tag in your template update view will handle it for you and save the changes automatically.
if you want to use form (if you want to save sth in instances that class with not automatically do it ) , better to use FormView and remember here you have to save the form by yourself
link to FormView
If you want to use django for long time I strongly recommend to check this link and start reading the documents https://docs.djangoproject.com/en/3.1/ref/class-based-views/generic-editing/#django.views.generic.edit.FormView
I am having a hard time to understand how to display function based views URLS with Django REST FRAMEWORK.
I have the setup below of my project but for some reason I am unable to display the endpoint while MovieListViewSet works.
PROJECT.URLS
from users import views
router = routers.DefaultRouter()
router.register(r'movies', MovieListViewSet)
urlpatterns = [
path('', include(router.urls)),
path('admin/', admin.site.urls),
path('profile/', views.ProfileList, name='ProfileList')
]
users.model
User = settings.AUTH_USER_MODEL
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.TextField(max_length=500)
location = models.CharField(max_length=50)
image = models.ImageField(default='default.jpg', upload_to='profile_pics')
def __str__(self):
return self.user.username
serializers
from rest_framework import serializers
from users.models import Profile
class ProfileSerializer(serializers.ModelSerializer):
user = serializers.StringRelatedField(read_only=True)
class Meta:
model = Profile
fields = (
'id',
'user',
#'bio',
#'location',
'image',
)
I have comment bio and location because when they are uncommented, I receive this message.
Got AttributeError when attempting to get a value for field `bio` on serializer `ProfileSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `QuerySet` instance.
Original exception text was: 'QuerySet' object has no attribute 'bio'.
users.views (app)
#api_view(["GET"])
def ProfileList(APIView):
profile = Profile.objects.all()
serializer = ProfileSerializer(profile)
return Response(serializer.data)
I am unable to see ProfileList view as endpoint
Can someone point me to what I am doing wrong to display this endpoint to django rest framework.
You should specify many=True while serialization.
serializer = ProfileSerializer(profile, many=True)
You are mixing up functions and class based view definition here:
#api_view(["GET"])
def ProfileList(APIView):
profile = Profile.objects.all()
serializer = ProfileSerializer(profile)
return Response(serializer.data)
Either you define a class based view like this:
class ProfileView(APIView):
profile = Profile.objects.all()
serializer = ProfileSerializer
def list(request):
return Response(self.serializer_class(self.get_queryset(), many=True).data)
Or a function base view like:
#api_view(["GET])
def profile_list(request):
return Response(ProfileSerializer(Profile.objects.all(), many=True).data)
I am building a backend for a web app using django rest framework. I have a profile model that has a user forieingkey referencing a django user. Everything is loading correctly except for one issue which is that the User field is not showing up in the django rest framework backend urls so that I can assign a user to the profile object i want to create... does anyone know why this is happening...
models.py:
class Profile(models.Model):
user = models.ForeignKey(
User, on_delete=models.CASCADE
)
synapse = models.CharField(max_length=25, null=True)
bio = models.TextField(null=True)
profile_pic = models.ImageField(
upload_to='./profile_pics/',
max_length=150
)
facebook = models.URLField(max_length=150)
twitter = models.URLField(max_length=150)
updated = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.user.username + ' profile'
viewset:
from users.models import Profile
from users.api.serializers.ProfileSerializer import ProfileSerializer
from rest_framework import viewsets
class ProfileViewSet(viewsets.ModelViewSet):
queryset = Profile.objects.all()
serializer_class = ProfileSerializer
lookup_field = 'user__username'
url:
from users.api.views.ProfileView import ProfileViewSet
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register(r'', ProfileViewSet, base_name='profile')
urlpatterns = router.urls
serializer:
from rest_framework import serializers
from users.models import Profile
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = (
'id',
'user',
'synapse',
'bio',
'profile_pic',
'facebook',
'twitter'
)
depth=2
That happens when you set a depth bigger that 0, foreign key fields become not editable (if you send a POST with that field containing some value, DRF viewset would ignore it, and if the field is required, it will raise an exception).
One solution for that is to override to_representation() method of the serializer and set the depth and restore it to zero:
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = (
'id',
'user',
'synapse',
'bio',
'profile_pic',
'facebook',
'twitter'
)
def to_representation(self, instance):
self.Meta.depth = 2
representation = super().to_representation(instance)
self.Meta.depth = 0
return representation
I have the following model class:
# Song Model
class Song(models.Model):
title = models.CharField(max_length=200)
artist = models.CharField(max_length=200)
content = models.TextField()
user = models.ForeignKey('auth.User', related_name='songs')
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self): # __unicode__ on Python 2
return self.title + ' ' + self.artist
class Meta:
ordering = ('title',)
My serializers
class SongSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
fields = ('id', 'title', 'artist', 'content')
model = Song
class UserSerializer(serializers.ModelSerializer):
songs = serializers.HyperlinkedRelatedField(
many=True, read_only=True,
view_name='songs'
)
class Meta:
model = User
fields = '__all__'
and my views
class SongViewSet(viewsets.ModelViewSet):
queryset = Song.objects.all()
serializer_class = SongSerializer
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
I am trying to get the list of songs but I keep getting this error
ImproperlyConfigured: Could not resolve URL for hyperlinked relationship using view name "songs"
This has been working with PrimaryKeyRelatedField
but not as it is now.
routes file for reference:
router = DefaultRouter()
router.register(r'songs', views.SongViewSet)
router.register(r'users', views.UserViewSet)
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^api/', include(router.urls)),
]
Well, I was able to make it work with
view_name='song-detail'
If anyone wants to explain the why of how it works, please feel free
I'm total newbie in Django but I've faced with the same issue. I suppose that because of router prefix param is not the view name.
Documentation for the router says:
The example above would generate the following URL patterns:
URL pattern: ^users/$ Name: 'user-list'
URL pattern: ^users/{pk}/$ Name: 'user-detail'
URL pattern: ^accounts/$ Name: 'account-list'
URL pattern: ^accounts/{pk}/$ Name: 'account-detail'
Documentation for the serializer says:
view_name - The view name that should be used as the target of the relationship. If you're using the standard router classes this will be a string with the format
<modelname>-detail. required.
If you are using DefaultRouter
you can try change basename='song'
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register('song', views.SongViewset, basename='song')