So I am trying to have "two forms" in single class based view.
My view is:
class ListAndCreate(CreateView):
model = xmpp_buddy_groups
form_class = xmpp_buddy_groups_form
second_form_class = sip_extension_form
template_name = "xmpp/index.html"
success_url = reverse_lazy('xmpp:index')
def get_context_data(self, **kwargs):
context = super(ListAndCreate, self).get_context_data(**kwargs)
context['object_list'] = self.model.objects.all()
extension = SipExtension.objects.values_list('sip_extension', flat=True)
obj = SipExtension.objects.filter(sip_extension=1331).first()
for buddy_groups in group_names:
for sip in buddy_groups.sipextension_set.all():
sip_extension = sip.sip_extension
print(sip_extension)
context['extension'] = extension
SipExtension.objects.exclude(sip_extension__in=extension)
print(extension)
context['form'] = self.form_class
context['form2'] = self.second_form_class(instance=obj)
context['extensions'] = SipExtension.objects.exclude(sip_extension__in=extension)
return context
My form classes:
from django import forms
from .models import xmpp_buddy_groups
from extensions.models import SipExtension
class xmpp_buddy_groups_form(forms.ModelForm):
class Meta:
model = xmpp_buddy_groups
fields = ['group_name']
def __init__(self, *args, **kwargs):
super(xmpp_buddy_groups_form, self).__init__(*args, **kwargs)
self.fields['group_name'].required = False
class sip_extension_form(forms.ModelForm):
class Meta:
model = SipExtension
fields = ['real_name','sip_extension']
widgets = {
"sip_extension": forms.Select
}
def __init__(self, *args, **kwargs):
super(sip_extension_form, self).__init__(*args, **kwargs)
self.fields['sip_extension'].queryset = \
SipExtension.objects.filter(sip_extension=1331)
My models:
from django.db import models
from django.urls import reverse
class xmpp_buddy_groups(models.Model):
group_name = models.CharField(max_length=30,unique=True)
def __str__(self):
return '%s' % (self.group_name)
from django.db import models
class SipExtension(models.Model):
real_name = models.CharField(max_length=32)
sip_extension = models.PositiveIntegerField(unique=True)
sip_secret = models.CharField(max_length=32)
commlink_push = models.BooleanField(default=False)
default_did = models.ForeignKey('dids.DidNumber',null=True,blank=True)
xmpp = models.BooleanField(default=False)
xmpp_username = models.CharField(max_length=50,default='username')
xmpp_password = models.CharField(max_length=32,default='password')
xmpp_buddy_groups_names = models.ManyToManyField('xmpp.xmpp_buddy_groups')
def __str__(self):
return '%s : %s' % (self.sip_extension, self.real_name)
I am accessing form in template as {{form2.as_p}}. The dropdown appears empty. I want it to populate with 1331. How can I do that?
EDIT: Added models make the question clearer. Pardon my inexperience with Django
Related
I am trying to make a form in Django that gives the user a limited selection based on a foreign key. To be more exact, the form has 2 fields, a ModelChoiceField and a simple text field. This form's purpose is to allow a user to add a Riddle to a previously created Room. So the goal is to limit the ModelChoiceField to only allow the currently logged-in user to add riddles to just their own rooms.
forms.py:
from django import forms
from .models import Project, Riddle
class ProjectForm(forms.ModelForm):
class Meta:
model = Project
fields = ['title', 'max_players', 'has_actor', 'scenario']
class RiddleForm(forms.ModelForm):
project = forms.ModelChoiceField(queryset=Project.objects.all(),
empty_label=None,
widget=forms.Select(attrs={'class': 'form-control'}),
label='Project')
class Meta:
model = Riddle
fields = ['project','description']
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['project'].queryset = Project.objects.all()
self.fields['project'].label_from_instance = lambda obj: obj.title
models.py:
from django.db import models
from django.contrib.auth import get_user_model
from django.urls import reverse
User = get_user_model()
class Project(models.Model):
title = models.CharField(max_length=255, unique=True)
max_players = models.PositiveIntegerField(default=0)
has_actor = models.BooleanField(default=False)
scenario = models.TextField(blank=True, null=True)
#number_of_riddles = models.PositiveIntegerField(default=0)
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='rooms')
def get_absolute_url(self):
return reverse(
"rooms:project_list",
kwargs={
"username": self.user.username,
#"pk": self.pk
}
)
class Riddle(models.Model):
project = models.ForeignKey(Project, on_delete=models.CASCADE)
description = models.TextField()
urls.py:
from django.urls import path
from .views import ProjectListView, ProjectDetailView, ProjectCreateView, ProjectUpdateView, ProjectDeleteView, RiddleAddView
app_name = 'rooms'
urlpatterns = [
path('projects/madeby/<slug:username>', ProjectListView.as_view(), name='project_list'),
path('projects/<slug:username>/<int:pk>/', ProjectDetailView.as_view(), name='project_detail'),
path('projects/create/', ProjectCreateView.as_view(), name='project_create'),
path('projects/update/<int:pk>', ProjectUpdateView.as_view(), name='project_update'),
path('projects/delete/<int:pk>/', ProjectDeleteView.as_view(), name='project_delete'),
path('projects/addriddle/', RiddleAddView.as_view(), name='riddle_add'),
]
views.py:
from django.urls import reverse_lazy, reverse
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views import View, generic
from django.views.generic import CreateView, DetailView, UpdateView
from .models import Project, Riddle
from .forms import ProjectForm, RiddleForm
from django.contrib.auth import get_user_model
from django.http import Http404
from braces.views import SelectRelatedMixin
from django.contrib import messages
User = get_user_model()
class ProjectCreateView(CreateView):
model = Project
form_class = ProjectForm
template_name = 'rooms/project_form.html'
#success_url = reverse_lazy('rooms:project_list username=')
def get_success_url(self):
return reverse('rooms:project_list', kwargs= {'username': self.request.user})
def form_valid(self, form):
form.instance.user = self.request.user
return super().form_valid(form)
#def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# context['riddle_form'] = RiddleForm()
# return context
#def form_valid(self, form):
#project = form.save()
# project_id = self.kwargs.get('pk')
# project = Project.objects.get(id=project_id)
# riddle_form = RiddleForm(self.request.POST)
#if riddle_form.is_valid():
# riddle = riddle_form.save(commit=False)
# riddle.project = project
# riddle.save()
#return super().form_valid(form)
class ProjectDetailView(DetailView):
model = Project
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
project_id = self.kwargs.get('pk')
project = Project.objects.get(id=project_id)
context['project'] = project
return context
class ProjectUpdateView(UpdateView):
model = Project
form_class = ProjectForm
template_name = 'rooms/project_form.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['riddle_form'] = RiddleForm()
return context
#def form_valid(self, form):
#project = form.save()
# project_id = self.kwargs.get('pk')
# project = Project.objects.get(id=project_id)
# riddle_form = RiddleForm(self.request.POST)
#if riddle_form.is_valid():
# riddle = riddle_form.save(commit=False)
# riddle.project = project
# riddle.save()
#return super().form_valid(form)
#def form_valid(self, form):
# form.save()
# return redirect('rooms:project_list')
class ProjectListView(generic.ListView):
model = Project
template_name = "rooms/room_list.html"
def get_queryset(self):
try:
self.room_user = User.objects.prefetch_related('rooms').get(
username__iexact=self.kwargs.get('username')
)
except User.DoesNotExist:
raise Http404
else:
return self.room_user.rooms.all()
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["room_user"] = self.room_user
return context
class ProjectDeleteView(LoginRequiredMixin, SelectRelatedMixin, generic.DeleteView):
model = Project
select_related = ('user',)
#success_url = reverse_lazy('home')
def get_success_url(self):
return reverse('rooms:project_list', kwargs= {'username': self.request.user})
def get_queryset(self):
queryset = super().get_queryset()
return queryset.filter(user_id=self.request.user.id)
def delete(self, *args, **kwargs):
messages.success(self.request, "Post Deleted")
return super().delete(*args, **kwargs)
class RiddleAddView(CreateView):
model = Riddle
form_class = RiddleForm
template_name = 'rooms/riddle_form.html'
def form_valid(self, form):
project = form.cleaned_data.get('project')
project_title = project.title
try:
project = Project.objects.get(title=project_title)
except Project.DoesNotExist:
messages.error(self.request, "No project with the title '{}' was found.".format(project_title))
return super().form_invalid(form)
form.instance.project = project
return super().form_valid(form)
def get_success_url(self):
return reverse_lazy('rooms:project_detail', kwargs={'username': self.object.project.user.username, 'pk': self.object.project.id})
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['riddle_form'] = RiddleForm()
#context['project_id'] = self.kwargs['project_id']
return context
For now, I just have the Project.objects.all() but that does not achieve the functionality I want.
I have tried using the select_related(), filter() methods and the attribute__foreignattribute syntax to no success. Any ideas of how I should go about this are welcome! Taking into account how common this operation is, the solution is probably something pretty obvious, but I haven't been able to come up with something to fit my case.
Thanks in advance!
I think you can pass the user as an argument for the RiddleForm:
In RiddleAddView you can define user as a parameter for the RiddleForm:
class RiddleAddView(CreateView):
...
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs['user'] = self.request.user
return kwargs
...
Then you can use it to restrict the queryset in the RiddleForm:
class RiddleForm(forms.ModelForm):
...
def __init__(self, *args, **kwargs):
user = kwargs.pop('user')
super().__init__(*args, **kwargs)
self.fields['project'].queryset = Project.objects.filter(user=user)
...
Also, you can use the reverse relationship:
class RiddleForm(forms.ModelForm):
...
def __init__(self, *args, **kwargs):
user = kwargs.pop('user')
super().__init__(*args, **kwargs)
self.fields['project'].queryset = user.rooms.all()
...
I have a form that I am using to create new models, but every time I submit the form, it overrides the only existing model in the database.
My form view:
class createItinerary(CreateView):
template = "create.html"
form_class = CreateItineraryForm
def get(self, request, *args, **kwargs):
form = self.form_class()
return render(request, self.template, {"form": form})
def post(self, request, *args, **kwargs):
super().__init__(*args, **kwargs)
form = self.form_class(request.POST)
if form.is_valid():
destination = form.cleaned_data.get("destination")
trip_length = form.cleaned_data.get("trip_length")
start = form.cleaned_data.get("start")
end = form.cleaned_data.get("end")
sights = form.cleaned_data.get("sights")
new = Itinerary(destination=destination,
trip_length=trip_length, start=start, end=end)
new.sights.set(sights)
new.save()
return redirect("/")
else:
form = CreateItineraryForm
return render(request, self.template, {"form" : form})
My forms.py:
from django import forms
from django.forms.widgets import *
from itineraries.models import Itinerary
from sights.models import Sight
sight_choices = ()
for sight in Sight.objects.all():
new_sight = (("%s" % sight.name, "%s" % sight.name))
sight_choices += new_sight
class CreateItineraryForm(forms.ModelForm):
class Meta:
model = Itinerary
exclude = []
destination = forms.CharField(label="Destination", max_length=100)
start = forms.DateField(widget=NumberInput(attrs={"type" : "date"}))
end = forms.DateField(widget=NumberInput(attrs={"type" : "date"}))
sights = forms.ModelMultipleChoiceField(
queryset=Sight.objects.all())
My models.py:
from django.db import models
from sights.models import Sight
import datetime
class Itinerary(models.Model):
id = models.AutoField(primary_key=True, default=0)
destination = models.CharField(max_length=100, null=False)
trip_length = models.IntegerField(null=False)
start = models.DateField()
end = models.DateField()
sights = models.ManyToManyField(Sight)
def __str__(self):
trip_name = "%s in %s days" % (self.destination, self.trip_length)
return trip_name
This is the only existing model in the database:
When I use the form to save a new one:
It replaces the old model with the newly created one every time.
Remove default=0 from id in your model.
I want to change Photo 'labeled' field False when I delete LabeledPhoto object.
#models.py
class Photo(models.Model):
image = models.ImageField(upload_to='shoes_data/%Y/%m/%d', name='image')
created = models.DateTimeField(auto_now_add=True)
labeled = models.BooleanField(default=False)
class LabeledPhoto(models.Model):
labeled_image = models.OneToOneField(Photo, on_delete=models.PROTECT, related_name='labeled_image')
topcategory = models.CharField(max_length=64)
subcategory = models.CharField(max_length=64)
labeler = models.CharField(max_length=32)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
I tried like this but, It didn't work
# views.py
class LabeledPhotoDelete(DeleteView):
model = LabeledPhoto
template_name = 'label/labeled_photo_delete.html'
success_url = reverse_lazy('photo:labeled_list')
def delete(self, request, *args, **kwargs):
self.object = self.get_object()
success_url = self.get_success_url()
labeled = LabeledPhoto.objects.get(id=self.object.pk)
labeled.labeled_image.labeled = False
labeled.save()
self.object.delete()
return reverse(success_url)
You need to .save() the Photo:
from django.http import HttpResponseRedirect
class LabeledPhotoDelete(DeleteView):
model = LabeledPhoto
template_name = 'label/labeled_photo_delete.html'
success_url = reverse_lazy('photo:labeled_list')
def delete(self, request, *args, **kwargs):
self.object = self.get_object()
success_url = self.get_success_url()
image = self.object.labeled_image
image.labeled = False
image.save()
self.object.delete()
return HttpResponseRedirect(success_url)
But there is no reason to store whether the image is labeled in a field: you can simply look that up if you want to know this. Indeed, you can add a property:
class Photo(models.Model):
image = models.ImageField(upload_to='shoes_data/%Y/%m/%d', name='image')
created = models.DateTimeField(auto_now_add=True)
#property
def labeled(self):
try:
return self.labeled_image is not None
except LabeledPhoto.DoesNotExist:
return False
or annotate the queryset with the fact if a LabeledPhoto exists:
from django.db.models import BooleanField, ExpressionWrapper, Q
Photo.objects.annotate(
is_labeled=ExpressionWrapper(
Q(labeled_image__isnull=False),
output_field=BooleanField()
)
)
My models.py
from django.db import models
from django.contrib.auth.models import User
import datetime
from django.utils import timezone
# Create your models here.
class LiveClass(models.Model):
standard = models.IntegerField()
no_of_students_registered = models.IntegerField(default=0)
class Meta:
verbose_name_plural = 'Class'
def __str__(self):
return str(self.standard) + ' class'
class User_details(models.Model):
name = models.OneToOneField(User, on_delete = models.CASCADE, max_length=30)
standard = models.ForeignKey(LiveClass, on_delete=models.CASCADE)
email = models.EmailField(max_length=30)
mobile_number = models.IntegerField()
class Meta:
verbose_name_plural = 'User_details'
def __str__(self):
return self.name
class Mentor(models.Model):
name = models.CharField(max_length=30)
details = models.TextField()
ratings = models.FloatField(default=2.5)
class Meta:
verbose_name_plural = 'Mentors'
def __str__(self):
return self.name
class LiveClass_details(models.Model):
standard = models.ForeignKey(LiveClass, on_delete=models.CASCADE)
chapter_name = models.CharField(max_length=30)
chapter_details = models.TextField()
mentor_name = models.ForeignKey(Mentor, max_length=30, on_delete=models.CASCADE)
class_time = models.DateTimeField()
end_time = models.DateTimeField()
isDoubtClass = models.BooleanField(default=False)
doubtsAddressed = models.IntegerField(default=0)
class Meta:
verbose_name_plural = 'LiveClass_details'
def __str__(self):
return self.chapter_name
class SavedClass(models.Model):
class_details = models.ForeignKey(LiveClass_details, on_delete=models.CASCADE)
name = models.ForeignKey(User_details, on_delete=models.CASCADE)
is_registered = models.BooleanField(default=False)
is_attended = models.BooleanField(default=False)
class Meta:
verbose_name_plural = 'SavedClasses'
def __str__(self):
return 'SavedClass : ' + str(self.class_details)
my serializers.py
from rest_framework import serializers
from . import models
class LiveClass_serializer(serializers.ModelSerializer):
class Meta:
model = models.LiveClass
fields = '__all__'
class User_details_serializer(serializers.ModelSerializer):
class Meta:
model = models.User_details
fields = '__all__'
class LiveClass_details_serializer(serializers.ModelSerializer):
class Meta:
model = models.LiveClass_details
fields = '__all__'
class Mentor_serializer(serializers.ModelSerializer):
class Meta:
model = models.Mentor
fields = '__all__'
class SavedClass_serializer(serializers.ModelSerializer):
class Meta:
model = models.SavedClass
fields = '__all__'
my views.py
from django.shortcuts import render
from rest_framework import mixins
from rest_framework import generics
from django.contrib.auth.mixins import LoginRequiredMixin
from rest_framework import status
from django.contrib.auth.models import User
from rest_framework.response import Response
from . import serializers
from . import models
# Create your views here.
class ListLiveClass(mixins.ListModelMixin, LoginRequiredMixin, generics.GenericAPIView):
queryset = models.LiveClass_details.objects.all()
serializer_class = serializers.LiveClass_details_serializer
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
class LiveClassView(mixins.ListModelMixin,
mixins.CreateModelMixin,
LoginRequiredMixin,
generics.GenericAPIView):
queryset = models.LiveClass_details.objects.all()
serializer_class = serializers.LiveClass_details_serializer
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
if request.user.is_superuser:
return self.create(request, *args, **kwargs)
else:
return Response(status=status.HTTP_403_FORBIDDEN)
class LiveClassViewId(mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
LoginRequiredMixin,
generics.GenericAPIView):
queryset = models.LiveClass_details.objects.all()
serializer_class = serializers.LiveClass_details_serializer
lookup_field = 'id'
def get(self, request, id=None, format=None):
if id:
return self.retrieve(request)
else:
return Response(status=status.HTTP_400_BAD_REQUEST)
def put(self, request, id, format=None):
if request.user.is_superuser:
return self.update(request, id)
else:
return Response(status=status.HTTP_403_FORBIDDEN)
def delete(self, request, id, format=None):
if request.user.is_superuser:
return self.destroy(request, id)
else:
return Response(status=status.HTTP_403_FORBIDDEN)
class ListMentors(mixins.ListModelMixin, LoginRequiredMixin, generics.GenericAPIView):
queryset = models.Mentor.objects.all()
serializer_class = serializers.Mentor_serializer
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
class ListUserDetails(mixins.ListModelMixin, LoginRequiredMixin, generics.GenericAPIView):
queryset = models.User_details.objects.all()
serializer_class = serializers.User_details_serializer
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
#api endpoints to save and register live classes
class SavedClassView(LoginRequiredMixin, mixins.ListModelMixin, mixins.DestroyModelMixin, generics.GenericAPIView):
model = models.SavedClass
serializer = serializers.SavedClass_serializer
def get_object(self):
return self.request.user.id
def get(self, request):
CurrentUserID = self.get_object()
In SavedClassView i want to get saved classes from the current logged user only and i want to preserve this user from getting other user saved classes , i have done something like above but i am getting no perfect logic that fits the working of django rest framework , please help me in achieving the above result
Add filter to queryset
queryset = models.User_details.objects.filter(user=request.user)
Just make sure to implement tokens so you can access request.user
I am trying to make a calendar app and currently trying to stop people from being about to save an event when they are already busy during that time period. I believe my issue is that the modelForm doesn't have the user_id as part of the form object. how can I pass the user_id so I can use it to filter with the clean().
I tried using get_form_kwargs() but this doesn't seem to be the correct route to take.
Please can you point me in the right direction of how to do this.
view.py
class CalendarEventAdd(LoginRequiredMixin, CreateView):
model = Event
form_class = EventForm
template_name = 'calendar_create_event_form.html'
success_url = reverse_lazy('calendar_list')
def form_valid(self, form):
form.instance.manage = self.request.user
return super(CalendarEventAdd, self).form_valid(form)
def get_form_kwargs(self, *args, **kwargs):
kwargs = super(CalendarEventAdd, self).get_form_kwargs()
kwargs['user_id'] = self.request.user
return kwargs
form.py
class EventForm(forms.ModelForm):
class Meta:
model = Event
widgets = {
'start_time': DateInput(attrs={'type': 'datetime-local'}, format='%Y-%m-%dT%H:%M'),
'end_time': DateInput(attrs={'type': 'datetime-local'}, format='%Y-%m-%dT%H:%M'),
}
fields = ['avilibility','start_time','end_time']
def __init__(self, *args, **kwargs):
super(EventForm, self).__init__(*args, **kwargs)
# input_formats parses HTML5 datetime-local input to datetime field
self.fields['start_time'].input_formats = ('%Y-%m-%dT%H:%M',)
self.fields['end_time'].input_formats = ('%Y-%m-%dT%H:%M',)
def clean(self, *args, **kwargs):
form_start_time = self.cleaned_data.get('start_time')
form_end_time = self.cleaned_data.get('end_time')
form_manage_id = self.cleaned_data.get('manage_id')
between = Event.objects.filter(manage_id=1, end_time__gte=form_start_time, start_time__lte=form_end_time)
if between:
raise forms.ValidationError('Already Calendar entry for this time')
super().clean()
model.py
class Event(models.Model):
avilibility_choices = [
('Avilible', 'Avilible'),
('Busy', 'Busy'),
]
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
manage = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
avilibility = models.CharField(max_length=10, choices=avilibility_choices, editable=True)
start_time = models.DateTimeField()
end_time = models.DateTimeField()
def __str__(self):
return self.avilibility + " - " + str(self.start_time) + " - " + str(self.end_time) + " - " +str(self.id)
def get_absolute_url(self):
return reverse('calendar_event_detail', args=[str(self.id)])
def get_absolute_url_edit(self):
return reverse('calendar_event_detail_update', args=[str(self.id)])
def get_html_url(self):
url = reverse('event_edit', args=(self.id,))
return f' {self.avilibility} '
In your view, you should pass the primary key of the user, so:
def get_form_kwargs(self, *args, **kwargs):
kwargs = super(CalendarEventAdd, self).get_form_kwargs()
kwargs['user_id'] = self.request.user.pk
return kwargs
You can save it in the EventForm object:
class EventForm(forms.ModelForm):
def __init__(self, *args, user_id=None, **kwargs):
super(EventForm, self).__init__(*args, **kwargs)
self.user_id = user_id
# input_formats parses HTML5 datetime-local input to datetime field
self.fields['start_time'].input_formats = ('%Y-%m-%dT%H:%M',)
self.fields['end_time'].input_formats = ('%Y-%m-%dT%H:%M',)
def clean(self, *args, **kwargs):
form_start_time = self.cleaned_data.get('start_time')
form_end_time = self.cleaned_data.get('end_time')
form_manage_id = self.cleaned_data.get('manage_id')
between = Event.objects.exclude(pk=self.instance.pk).filter(
manage_id=self.user_id,
end_time__gte=form_start_time,
start_time__lte=form_end_time
)
if between.exists():
raise forms.ValidationError('Already Calendar entry for this time')
return super().clean()
The .exclude(pk=self.instance.pk) will exclude the object you are editing, if you later decide to use the EventForm not only to create but also update an Event object.
Note: The documentation advises to
use the AUTH_USER_MODEL setting [Django-doc] over
get_user_model() [Django-doc].
This is safer, since if the authentication app is not yet loaded, the settings
can still specify the name of the model. Therefore it is better to write:
from django.conf import settings
class Event(models.Model):
# …
manage = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE
)