Default the value of an external key in a form - django

In the form for adding a calendar (of the Model "Calendar"), in the "group" field shows a drop-down menu where all the "CalendarGroups" are. I would like this menu not to be there and "group" to be set by default with the "group" id which I pass through the url parameter ("group_id"). How could I solve this?
In models.py:
class CalendarGroups(models.Model):
name = models.CharField(max_length = 155, blank=True, null=True, unique=True)
def __str__(self):
return str(self.name)
#property
def get_html_url(self):
url = reverse('', args=(self.id,))
return f' {self.name} '
class Calendar(models.Model):
name = models.CharField(max_length=200, unique=True)
#created_by
group = models.ForeignKey(CalendarGroups, on_delete = models.CASCADE, default='')
#property
def get_html_url(self):
url = reverse('cal:calendar_view', args=(self.id, self.group))
return f' {self.name} '
In forms.py:
class CalendarGroupsForm(ModelForm):
class Meta:
model = CalendarGroups
fields = ('name',)
def __init__(self, *args, **kwargs):
super(CalendarGroupsForm, self).__init__(*args, **kwargs)
class CalendarForm(ModelForm):
class Meta:
model = Calendar
fields = ('name', 'group')
def __init__(self, *args, **kwargs):
super(CalendarForm, self).__init__(*args, **kwargs)
In views.py:
def group(request, group_id=None):
instance = CalendarGroups()
if group_id:
instance = get_object_or_404(CalendarGroups, pk=group_id)
else:
instance = CalendarGroups()
form = CalendarGroupsForm(request.POST or None, instance=instance)
if request.POST and form.is_valid():
form.save()
return HttpResponseRedirect(reverse('cal:home'))
return render(request, 'cal/form.html', {'form': form})
def calendar(request, group_id=None):
instance = Calendar()
form = CalendarForm(request.POST or None, instance=instance)
if request.POST and form.is_valid():
form.save()
return HttpResponseRedirect(reverse('cal:home'))
return render(request, 'cal/form.html', {'form': form})
In urls.py:
url(r'^home/(?P<group_id>\d+)/calendar/new/$', views.calendar, name='calendar_new')

After consulting the documentation, I solved it by modifying the code as follows:
In views.py:
def calendar(request, group_id=None):
instance = Calendar()
instance = Calendar(group_id=group_id)
form = CalendarForm(request.POST or None, instance=instance)
if request.POST and form.is_valid():
form.save()
return HttpResponseRedirect(reverse('cal:home'))
return render(request, 'cal/form.html', {'form': form})
In forms.py:
class CalendarForm(ModelForm):
class Meta:
model = Calendar
fields = ('name',)
def __init__(self, *args, **kwargs):
super(CalendarForm, self).__init__(*args, **kwargs)

You already have send to the views.calendar the group_id key you need.
Now try to add it to the form before the form.save
Try to modify like this in view.py
def calendar(request, group_id):
instance = Calendar()
form = CalendarForm(request.POST or None, instance=instance)
if request.POST and form.is_valid():
form.group=group_id
form.save()
return HttpResponseRedirect(reverse('cal:home'))
return render(request, 'cal/form.html', {'form': form})
Take note that might override what user can post on CalendarForm and you should consider to hide or make not editable that filed group_id,
Also this is slightly different to what i usually do but it should work
I Post also an example of what works for me:
def calendar(request, group_id):
instance = Calendar()
form = CalendarForm(request.POST or None)
if request.POST and form.is_valid():
instance = form.save(commit=False)
instance.group = group_id
instance.save()
return HttpResponseRedirect(reverse('cal:home'))
return render(request, 'cal/form.html', {'form': form})

Related

Handling form fields in django for logged in user

Im trying to handle the existing name of a Category, so that users wont be allowed to create 2 categories with the same name, but at the moment its taking all categories from the database, not only for the logged-in user. I dont know how and where to implement request.user.
I`m building an inventory app where everyone creates their own categories and adds items.
Thank you.
This is my model:
class Category(models.Model):
user = models.ForeignKey(User, default=1, on_delete=models.CASCADE,
related_name='category', null=True)
name = models.CharField(max_length=100, null=False, blank=False)
slug = models.SlugField(max_length=100)
created_on = models.DateTimeField(auto_now_add=True)
timestamp = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['-timestamp']
verbose_name = 'category'
verbose_name_plural = 'categories'
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('category_detail', kwargs={'slug': self.slug})
This is my form:
class CategoryForm(forms.ModelForm):
add_category = forms.BooleanField(widget=forms.HiddenInput, initial=True)
class Meta:
model = Category
fields = ['name']
def clean_name(self):
name = self.cleaned_data.get('name')
if (name == ""):
raise forms.ValidationError('This field cannot be left blank')
for instance in Category.objects.all():
if instance.name == name:
raise forms.ValidationError('There is a category with the name ' + name)
return name
This is my view:
#login_required
def index(request):
categories = Category.objects.filter(user=request.user)
items = Item.objects.all()
add_item = ItemForm()
add_category = CategoryForm()
query = None
if request.method == 'POST':
if 'add_item' in request.POST:
add_item = ItemForm(request.POST)
if add_item.is_valid():
form = add_item.save(commit=False)
form.category = get_object_or_404(
Category, name=request.POST.get('category'),
user=request.user)
add_item.save()
return redirect('home')
else:
add_category = CategoryForm(request.POST)
if add_category.is_valid():
category_form = add_category.save(commit=False)
category_form.save()
messages.success(request, f'{name} has been added')
return redirect('home')
Edit Category View
#login_required
def category_edit(request, pk):
category = Category.objects.get(id=pk)
if request.method == 'POST':
form = CategoryForm(request.POST, instance=category)
if form.is_valid():
form.save()
messages.info(request, f'{category.name} has been updated!')
return redirect('home')
else:
form = CategoryForm(instance=category, user=request.user)
context = {
'form': form,
}
return render(request, 'category_edit.html', context)
Ive tried adding user = request.user in the form class, but that resulted in an error Ive tried adding category_form.user = request.user before saving the form but that was still taking names from every other user
Pass the request's user to the form:
class CategoryForm(forms.ModelForm):
add_category = forms.BooleanField(widget=forms.HiddenInput, initial=True)
def __init__(self, user, *args, **kwargs):
self.user = user
super().__init__(*args, **kwargs)
class Meta:
model = Category
fields = ['name']
def clean_name(self):
name = self.cleaned_data.get('name')
if (name == ""):
raise forms.ValidationError('This field cannot be left blank')
qs = Category.objects.filter(user=self.user, name=name)
if self.instance.pk:
# EXCLUDE CURRENT INSTANCE TO ENABLE EDIT
qs = qs.exclude(pk=self.instance.pk)
if qs.exists():
raise forms.ValidationError('There is a category with the name ' + name)
return name
then in the view you need to pass the user:
#login_required
def index(request):
categories = Category.objects.filter(user=request.user)
items = Item.objects.all()
add_item = ItemForm()
add_category = CategoryForm(user=request.user)
query = None
if request.method == 'POST':
if 'add_item' in request.POST:
add_item = ItemForm(request.POST)
if add_item.is_valid():
form = add_item.save(commit=False)
form.category = get_object_or_404(
Category, name=request.POST.get('category'),
user=request.user)
add_item.save()
return redirect('home')
else:
add_category = CategoryForm(user=request.user, data=request.POST)
if add_category.is_valid():
category_form = add_category.save(commit=False)
category_form.save()
messages.success(request, f'{name} has been added')
return redirect('home')

Get username or user as initial value on forms in django

I would like to get initial value on the following form but i get error : name 'user' is not defined. I don't know how to get user.username.
class InvoiceForm(ModelForm):
date = forms.DateField(widget=DateInput)
company = forms.CharField(initial={"company": user.username})
class Meta:
model = Invoice
fields = "__all__"
and the view to create the invoice is :
class InvoiceCreate(CreateView):
form_class = InvoiceForm
model = Invoice
template_name = "sales/invoice_form.html"
def get_success_url(self, request):
return reverse_lazy('invoice_details', kwargs={'pk' : self.object.pk})
def get(self, request, *args, **kwargs):
self.object = None
form_class = self.get_form_class()
form = self.get_form(form_class)
formset = InvoiceItemFormSet()
products = list(Product.objects.values())
return self.render_to_response(
self.get_context_data(form=form,formset=formset, products=products))
def post(self, request, *args, **kwargs):
self.object = None
form_class = self.get_form_class()
form = self.get_form(form_class)
formset = InvoiceItemFormSet(self.request.POST)
if (form.is_valid() and formset.is_valid()):
return self.form_valid(form, formset)
else:
return self.form_invalid(form, formset)
def form_valid(self, form, formset):
self.object = form.save()
formset.instance = self.object
formset.save()
try:
addmore = self.request.GET["addmore"]
if addmore == "True":
return redirect("update_invoice", pk=self.object.id)
except Exception as e:
pass
return HttpResponseRedirect(self.get_success_url())
def form_invalid(self, form, formset):
return self.render_to_response(self.get_context_data(form=form, formset=formset))
I would like to get initial value on the following form but i get error : name 'user' is not defined. I don't know how to get user.username.
You had that error because there is no user at that point in the class level definition:
company = forms.CharField(initial={"company": user.username})
change to:
company = forms.CharField()
then is views.py add this method to InvoiceCreate class:
def get_initial(self):
return {"company": self.request.user}

Associating the logged in user with the Photo Model

I basically want to associate the logged in user name with the PhotoModel by using models.ForeignKey. I override the safe_model in admin.py but when i execute the views.py class PhotoCreateNew(View) then it stops at print(form) and the form is not validated (if form.is_valid()) skips the entire part which was supposed to set the request.user as photo.user_name and return the empty template.
My models.py
class Photo(models.Model):
user_name = models.ForeignKey(User, on_delete=models.CASCADE)
PLACES = (('RD','研发-R&D'),('Warehouse','仓库-Warehouse'),('Gate','门卫处-Gate Guard'),('SecondFloor','2F生产部'))
photo = models.FileField()
photo_name = models.CharField(max_length=20)
date = models.DateField(auto_now="True")
quantity = models.CharField(max_length=4)
CONDITIONS = (('N','NG'), ('G', 'GOOD'))
condition =models.CharField(max_length=1,choices=CONDITIONS)
place = models.CharField(max_length=30,choices=PLACES,default='Warehouse')
def __str__(self):
return self.photo_name
def get_absolute_url(self):
return reverse('photo:photo_detail', kwargs={'pk':self.pk})
class PhotoForm(ModelForm):
class Meta:
model = Photo
fields =['user_name','photo','photo_name','quantity','condition','place']
exclude= ('user_name',)
My admin.py:
from django.contrib import admin
from photo.models import Photo
from photo.models import Supplier
class PhotoAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change):
if not obj.pk:
obj.user_name = request.user
obj.save()
admin.site.register(Supplier,)
admin.site.register(Photo, PhotoAdmin)
My views.py:
class PhotoCreateNew(View):
form_class = PhotoForm
template_name = 'photo/photo_form.html'
def get(self, request):
form =self.form_class(None)
return render(request, self.template_name, {'form':form})
def post(self,request):
form = self.form_class(request.POST)
print(request.user)
print(form)
if form.is_valid(): # uploader has been excluded. No more error.
print("Przeszlo")
photo = form.save(commit=False) # returns unsaved instance
photo.user_name = request.user
print(request.user)
photo.save() # real save to DB.
return redirect('photo:photo_detail')
return render(request,self.template_name,{})
After initializing the form class with request.POST and request.FILES it is working.
I had to replace :
form = self.form_class(request.POST)
with :
form = self.form_class(request.POST, request.FILES)

Initialize form with request.user in a ModelForm django

I have this ModelForm
class ScheduleForm(forms.ModelForm):
class Meta:
model = Schedule
fields = ['name', 'involved_people',]
def __init__(self, user, *args, **kwargs):
super(ScheduleForm, self).__init__(*args, **kwargs)
self.fields['involved_people'].queryset = Profile.objects.exclude(user=user)
This is my view
def create_schedule(request):
form = ScheduleForm(request.POST or None)
schedules = Schedule.objects.all().order_by('deadline_date')
if form.is_valid():
schedule = form.save(commit=False)
schedule.save()
messages.success(request, "Schedule added successfully!")
return render(request, 'schedule/index.html', {'schedules': schedules})
context = {'form': form}
return render(request, 'schedule/create_schedule.html', context)
How do you pass request.user in the view?
How do you initialize the form with request.user in it?
You have added user to the __init__ method,
def __init__(self, user, *args, **kwargs):
so now you just pass the user as the first argument when you instantiate your form.
form = ScheduleForm(request.user, request.POST or None)

How to define initial values for ModelForm rightly?

I have no idea and I need to ask your advice.
I have simple form:
class CommentForm(ModelForm):
class Meta:
model = Comment
fields = ['text','author','news']
I want to add form in DetailView and hadle this form there:
class NewsDetailView(DetailView):
model = News
template_name = 'news/detail.html'
def get_initial(self):
return {'news': self.get_object(), 'author': self.request.user}
def get_context_data(self, **kwargs):
context = super(NewsDetailView, self).get_context_data(**kwargs)
context['form'] = CommentForm(initial=self.get_initial())
return context
def post(self, request, *args, **kwargs):
'''
comment_form = CommentForm(request.POST)
if comment_form.is_valid():
comment_form.save()
I don't want to show 'author' and news fieds. But if I hide them I can't to get initial values..
UPDATED:
After form validation I need return current form instance in the template through updating page. I attempted the next:
comment_form = CommentForm(request.POST, request=request)
if comment_form.is_valid() and comment_form.validate_user():
comment_form.save()
return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
else:
context = super(NewsDetailView,self).get_context_data(**kwargs)
context['form'] = comment_form
return self.render_to_response(context)
But did not work.
If you don't render your fields using {{ form.author }} and {{ form.news }} the form won't validate. Try using a HiddenInput for each field, You can do that by overriding the __init__ method of your form:
class CommentForm(ModelForm):
def __init__(self, *args, **kwargs):
super(CommentForm, self).__init__(*args, **kwargs)
self.fields['author'].widget = forms.HiddenInput()
self.fields['news'].widget = forms.HiddenInput()
class Meta:
model = Comment
fields = ['text','author','news']