Excluding Fields in Django Class Based Views Not Working - python

Boy, it feels like I've tried EVERYTHING here, and I just can't get this form to render properly (e.g. with a subset of fields). Here's the relevant items (extra items removed):
models.py:
class Response(models.Model):
public = models.BooleanField(default=False)
question = models.CharField(max_length=255, default='', blank=True)
class ResponseForm(ModelForm):
class Meta:
model = Response
fields = ['question']
views.py:
class ResponseCreate(CreateView):
model = Response
fields = ['question']
response_form.html:
<form action="" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Create" />
</form>
I've read every bit of docs, and they suggest using exclude, excludes, field, fields in permutations of tuple, or list, and no matter what the "public" field seems to show up every time! Thoughts?
Thanks for your help!

It looks like you need to specify form_class on your view:
class ResponseCreate(CreateView):
model = Response
form_class = ResponseForm

Just I want to mention that you don't really need a ModelForm to be created separately.
Generic views really shine when working with models. These generic
views will automatically create aModelForm, so long as they can work
out which model class to use
You can just use this.
class Response(models.Model):
public = models.BooleanField(default=False)
question = models.CharField(max_length=255, default='', blank=True)
class ResponseCreate(CreateView):
model = Response
fields = ['question']

You can use exclude field in your class form:
class ResponseForm(ModelForm):
class Meta:
model = Response
exclude = ['field_to_exclude']
class ResponseCreate(CreateView):
model = Response
form_class = ResponseForm

Related

Django how to connect user profile model with comment model for showing data from user profile?

I want to show user profile picture publicly in my blog comment section. I tried to use foreignkey in my comment model for connect user profile model then use this in my html for showing profile picture but didn't work.
<img src="{{blogcomment.userprofile.profile_pic.url}}"> #didn't show any profile picture until I manually go to admin panel and set foreignkey of userprofile in my blogcomment model.
here is my full code:
userprofile model
class UserProfile(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE,related_name="userprofile")
slug = models.SlugField(max_length=2000,unique=True,blank=True,null=True)
profile_pic = models.ImageField(upload_to='profile/images/',validators=[validate_file_size,FileExtensionValidator( ['png','jpg'] )],blank=True,null=True)
blogcomment model:
class BlogComment(models.Model):
blog = models.ForeignKey(Blog,on_delete=models.CASCADE,null=True, blank=True,related_name="blogcomment_blog")
comment = models.TextField(max_length=50000)
name = models.CharField(max_length=250)
userprofile= models.ForeignKey(UserProfile,on_delete=models.CASCADE,null=True,blank=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='user_comment',blank=True,null=True)
views.py:
if comment_form.is_valid():
isinstance = comment_form.save(commit=False)
isinstance.user = request.user
isinstance.blog = blog
isinstance.save()
my html template:
{% for q in queryset %}
{{q.user.first_name}}
{{q.comment}}
<img src="{{q.userprofile.profile_pic.url}}">
{%endfor%}
my froms.py
class CommentFrom(forms.ModelForm):
captcha = CaptchaField()
class Meta:
model = BlogComment
fields = ['name','email','comment','parent','sno','blog','user']
my userprofile forms.py
class ProfileFroms(forms.ModelForm):
class Meta:
model = UserProfile
fields = ["profile_pic","mobile","country","website_link","skype","twitter"]
userprofile views.py
class UserProfileUpdate(UpdateView):
model = UserProfile
form_class = ProfileFroms
template_name = 'members/profileupdate.html'
success_url = reverse_lazy('members:user-profile-private')
html template for saving userprofile forms
<form method="POST" enctype="multipart/form-data" runat="server">
{% csrf_token %}
{{form}}
</form>
Finally I solved my problems. As Willem Van Onsem said I am missing somethings in my froms. I need to be save userprofile forignkey with my comment model when any new comment posted. I am using this queryset UserProfile.objects.filter(user=request.user) for find current id then pass this id in forms.
{%for i in user_profile%}
<input type="hidden" name='userprofile' value="{{i.id}}">
{%endfor%}

How to pass data from Django Template to View

I have a template where customer details are displayed, along with a 'Create Lead' button at the bottom. This should take the user to the Lead creation form page where the customer field should be pre-selected.
I'm new to django. Based on responses of previous similar questions, I came up with the below code. But when I click the 'Create Lead' button, the url changes from "http://127.0.0.1:8000/sales/customer/21" to "http://127.0.0.1:8000/sales/customer/21/?customer_id=21" but nothing happens on the page. I tried with POST method and csrf token also, but it gives HTTP ERROR 405. Could some please help here.
Also, I've separate view for creating a Lead, which is sort of duplication of CreateView for Lead. And I believe that's not how it's supposed to be. What is the way to club them both in single view.
Below are the code snippets.
Models.py
class Customer(models.Model):
name = models.CharField(max_length=256)
email = models.EmailField(unique=True)
phone = models.PositiveIntegerField()
class Lead(models.Model):
customer = models.ForeignKey(Customer,related_name='Leads',on_delete=models.PROTECT)
destinations = models.CharField(max_length=256)
lead_source = models.CharField(max_length=256,choices=lead_source_choices,default='FNF')
lead_source_id = models.CharField(max_length=25,blank=True)
lead_status = models.CharField(max_length=25,choices=lead_status_choices,default='NEW')
remarks = models.TextField(blank=True)
trip_id = models.CharField(max_length=10,editable=False,unique=True,default="IN"+uuid.uuid1().hex[:5].upper())
creation_date = models.DateField(auto_now=True)
Forms.py
class LeadForm(forms.ModelForm):
class Meta:
model = Lead
fields = ('customer','destinations','lead_source','lead_source_id','lead_status','remarks')
class LeadFromCustomerForm(forms.ModelForm):
class Meta:
model = Lead
fields = ('destinations','lead_source','lead_source_id','lead_status','remarks')
Template
<form method="GET">
<input type="hidden" name="customer_id" value="{{customer.id}}">
<a href="{% url 'SalesApp:lead_create_from_customer' %}">
<button class="btn btn-warning btn-lg float-right" type="submit">Create Lead</button></a>
</form>
Urls.py
path('lead/create/',views.LeadCreateView.as_view(),name='lead_create'),
path('lead/create/customer/',views.LeadCreateFromCustomerView.as_view(),name='lead_create_from_customer')
Views.py
class LeadCreateView(LoginRequiredMixin,UserPassesTestMixin,CreateView):
form_class = LeadForm
model = Lead
def test_func(self):
return self.request.user.groups.filter(name='Sales').exists()
class LeadCreateFromCustomerView(LoginRequiredMixin,UserPassesTestMixin,CreateView):
form_class = LeadFromCustomerForm
model = Lead
def test_func(self):
return self.request.user.groups.filter(name='Sales').exists()
def form_valid(self,form):
customer_id = self.request.GET.get("value")
form.instance.customer = Customer.objects.get(id=customer_id)
return super(LeadCreateFromCustomerView,self).form_valid(form)

Django access foreignkey fields in a form

I'm working on a Virtual Library app (using Django v2.1, python v3.5) where anyone should be able to access the book catalog and request a loan by simply leaving some personal info like name, surname, email, etc.
These are some of the models in models.py:
class Profile(models.Model):
name = models.CharField(max_length=50)
# more fields like surname, email, phone...
class TrackBook(models.Model):
# Somefields to keep track of date and status...
borrower = models.ForeignKey(Profile, on_delete=models.SET_NULL, null=True, blank=True)
class Book(TrackBook):
#info about title, author, etc.
What I'm trying to do is to update a Book instance's borrower with a Profile instance that I created in the Form.
1)I've tried directly accessing borrower fields in a BookForm, but it didn't work.
# views.py
class BookRequestView(UpdateView):
template_name = 'core/book_request.html'
model = Book
form_class = BookProfileForm
#forms.py
class BookProfileForm(forms.ModelForm):
class Meta:
model = Book
fields = ['borrower']
# book_request.html
<form class="" action="" method="post">
{% csrf_token %}
<div class="row">
{{ form.borrower.name }}
<! -- and all other fields -->
</div>
{% for field in form.hidden_fields %}
{{ field }}
{% endfor %}
<button type="submit" class="btn btn-block btn-success btn-flat">Save</button>
</form>
2) I've tried creating an inlineformset_factory() of Profile model but it doesn't work since what I want to achieve is create a profile form inside the book form, not viceversa. So the example here is not what I'm looking for.
Maybe I'm going out of my mind for a very simple thing, but I can't seem to find any compatible solution for this problem... Any help/suggestion is welcome. Thanks in advance.
You need a form based on Profile, not Book. Your view then needs to create the profile and then set the book's borrower to that.
class BookProfileForm(forms.ModelForm):
book = forms.ModelChoiceField(queryset=Book.objects.all())
class Meta:
model = Profile
fields = ['name', 'address',...]
class BookRequestView(CreateView):
template_name = 'core/book_request.html'
model = Book
form_class = BookProfileForm
def form_valid(self, form):
borrower = form.save()
book = Book.objects.get(self.kwargs['book_id'] # or whatever is in your URL
book.borrower = borrower
book.save()
return redirect(self.get_success_url())

Error Generic detail view must be called with either an object pk or a slug, even with the pk

I'm trying to update records of a view which has a foreign key field, due to this I'm getting an error, since I tried to update another model without a foreign key field and it worked very well.
There are other quetions like this, but in my case I'm passing the pk.
urls.py
urlpatterns = [
url(r'^info/(?P<studentpk>\d+)/update/$', views.updatestudent.as_view(), name="updatestudent"),
]
views.py
class updatestudent(UpdateView):
model = Student
form_class = forms.studentform
template_name = "temp/updatestudent.html"
def get_success_url(self):
return reverse("courses")
updatestudent.html
<form action="" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Update" />
</form>
models.py
class Student(models.Model):
classfk = models.ForeignKey(Class)
name = models.CharField(max_length=100)
birth_date = models.DateField('Birthdate')
def __str__(self):
return self.name
error
AttributeError: Generic detail view updatestudent must be called with either an object pk or a slug.
Django doesn't expect you to use studentpk in the URL pattern. The easiest fix is to use pk instead.
url(r'^info/(?P<pk>\d+)/update/$', views.updatestudent.as_view(), name="updatestudent"),
If you really want to use studentpk, then set pk_url_kwarg in the view.
class updatestudent(UpdateView):
model = Student
form_class = forms.studentform
template_name = "temp/updatestudent.html"
pk_url_kwarg = 'studentpk'
Note that in Python, the recommended style is to name your class based view UpdateStudent, and your form class StudentForm.

How to make django crispy form to hide a particular field?

I'm trying to make my date_modified field as hidden since I have passed datetime.now parameter on defining date_modified field in model.
model.py
class Guide(models.Model):
name = models.CharField(max_length=50)
sno = models.CharField(max_length=50)
date_created = models.DateTimeField(default=datetime.now, blank=True)
date_modified = models.DateTimeField(default=datetime.now, blank=True)
def __unicode__(self):
return unicode(self.name)
views.py
class GuideFormUpdateView(UpdateView):
model = Guide
fields = ['name', 'sno', 'date_modified']
template_name_suffix = '_update_form'
success_url = reverse_lazy('Guides')
corresponding form forms.py looks like
<form role="form" method="POST" action="{% url 'Guideform-edit' object.pk %}"
class="post-form form-horizontal" enctype="multipart/form-data">{% csrf_token %}
{{ form|crispy }}
<button type="submit" value="Upload" class="save btn btn-default btn-primary center-block">Update</button>
</form>
This form displays date_modified field. But I don't want this field on frontend instead I want the value of this field in model or db_table should get updated. I know how to hide this particular field in jquery but I don't want to touch those js tools. Is there any way to make crispy to exclude that particular field like {{ form|crispy|exclude:date_modified }} ..
Instead of using Generic Form that your UpdateView will use implicitly, create your custom Form. And in your custom Form change the widget of the date_modified field.
In your forms.py
from django.forms import ModelForm, HiddenInput
class GuideForm(ModelForm):
def __init__(self, *args, **kwargs):
super(GuideForm, self).__init__(*args, **kwargs)
self.fields['date_modified'].widget = HiddenInput()
class Meta:
fields = ('name', 'sno', 'date_modified', )
model = models.Guide
In your views.py
class GuideFormUpdateView(UpdateView):
model = Guide
form_class = forms.GuideForm
template_name_suffix = '_update_form'
success_url = reverse_lazy('Guides')
To automatically update date_modified whenever you update the record, you need to use attributes auto_now and auto_now_add instead of default. See Docs. So your model will be
class Guide(models.Model):
name = models.CharField(max_length=50)
sno = models.CharField(max_length=50)
date_created = models.DateTimeField(auto_now_add=True, blank=True)
date_modified = models.DateTimeField(auto_now=True, blank=True)
def __unicode__(self):
return unicode(self.name)
You can hide a field in a form class like so:
Field('field_name', type="hidden")
Where Field is from crispy_forms.layout
Don't forget that if he field cannot be left empty, you'll still need to pass an appropriate value before saving it.
Abstract example:
class GuideFormHiddenField(GuideFormUpdateView):
def __init__(self, *args, *kwargs):
Field('date_modified', type="hidden")
This is the easiest way. You can of course make an entirely new form, or implement your fields individual, and use a condition to determine the visibility of a certain field; which would be something like if User.is_authenticated(): ... .
I think this should work:
from django.forms.models import modelform_factory
class GuideFormUpdateView(UpdateView):
model = Guide
form_class = modelform_factory(Guide, widgets={"date_modified": HiddenInput })
fields = ['name', 'sno', 'date_modified']
template_name_suffix = '_update_form'
success_url = reverse_lazy('Guides')
See here modelform_factory.

Categories