I have this url is http://127.0.0.1:8000/upload/picturelist/1, which makes user_id = 1,
In my urls.py
url(r'^picturelist/(?P<user_id>\d+)$', views.pictureList),
In my view.py
def pictureList(request, user_id):
if int(user_id) != request.user.id:
raise PermissionDenied
How can I make this function based view to use createview?
class pictureList(CreateView):
You could do something like this:
In urls.py: url(r'^picturelist/(?P<user_id>\d+)$', views.MakeItView.as_view()),
In views.py:
class MakeItView(CreateView):
model = myModel
template_name = 'whatever.html'
def get_context_data(self, **kwargs):
context = super(MakeItView, self).get_context_data(**kwargs)
if int(self.kwargs['user_id']) != self.request.user.id:
raise PermissionDenied
return context
I've never used CreateView, but here's what I gather from reading the docs:
You could do it by defining form_valid:
view:
class pictureList(CreateView):
model = YourModelHere
fields = ['whatever','fields','you','want','edited']
def form_valid(self, form):
record = form.save(commit = False)
# assuming the user id is associated
# to the model with fieldname user_id
if (self.request.user == record.user_id):
record.save()
return HttpResponseRedirect(self.get_success_url())
# not sure if this works:
return self.form_invalid()
Then the template would be at 'yourappname/yourmodelhere_form.html'.
See CreateView for an example.
Related
I have a CreateView and UpdateView, and upon success in the CreateView I'm trying to return the UpdateView with the object instance already filled in the form. The code below successfully creates the object instance (and redirects to the url with the uuid pattern in it as per the code), but the UpdateView form is empty. Why? How do I fix this?
views.py
class ProductCreate(CreateView):
"""Simple CreateView to create a Product."""
model = Product
form_class = ProductCreateForm
template_name = 'productcreate.html'
def get_success_url(self):
kwargs = {'uuid': self.object.uuid}
return reverse_lazy('productupdate', kwargs=kwargs)
def form_valid(self, form):
#some fields depend on request.user, so we can't set them in the Form.save() method
product = form.save()
product.fk_user = self.request.user
product.save()
return super(ProductCreate, self).form_valid(form)
class ProductUpdate(UpdateView):
"""Simple UpdateView to update a Product"""
model = Product
form_class = ProductCreateForm #same form
template_name = 'productcreate.html' #same template
def get_object(self, **kwargs):
#get the uuid out of the url group and find the Product
return Product.objects.filter(uuid=kwargs.get('uuid')).first()
def get_success_url(self):
kwargs = {'uuid': self.object.uuid}
return reverse_lazy('productupdate', kwargs=kwargs)
urls.py
url(r'^create-product/$', ProductCreate.as_view(), name="productcreate"),
url(r'^update-product/(?P<uuid>#giant_uuid_regex#)/$', ProductUpdate.as_view(), name="productupdate"),
productcreate.html extract:
{{ form.as_p }}
forms.py (I've left out the field cleaning code and a couple of additional fields not in the model):
class ProductCreateForm(forms.ModelForm):
"""Form to support adding a new Product"""
class Meta:
model = Product
fields = (
'field1',
'etc...',
)
I have an UpdateView for a model. I want to get the 'car_owner' attribute (of the Newcars model) in the UpdateView. Here's the code.
models.py
class Newcars(models.Model):
shop_no = models.ForeignKey(Shop, on_delete=models.CASCADE, default=0, related_name='newcars')
car_name = models.CharField(max_length=250)
car_owner = models.CharField(max_length=250)
def get_absolute_url(self):
return reverse('carapp:index')
def __str__(self):
return self.car_name + ' - ' + self.car_owner
views.py
(Here's the UpdateView.)
class NewcarUpdate(UpdateView):
model = Newcars
fields = ['car_name', 'car_owner']
urls.py (only the necessary part of the urlpatterns)
url(r'^newcars/(?P<pk>[0-9]+)/$', views.NewcarUpdate.as_view(), name='newcar-update'),
This is what I intend to do with the UpdateView, but cannot understand how.
class NewcarUpdate(UpdateView):
model = Newcars
fields = ['car_name', 'car_owner']
#Get the selected newcar object's 'car_owner' attribute.
#Check if the object's 'car_owner' attribute == "sometext" or not.
#If matches, only then go the normal update form.
#If doesn't, redirect to a 404 page.
add this method to your view:
def dispatch(self, request, *args, **kwargs):
if self.get_object().car_owner != "sometext":
raise Http404('Car owner does not match.')
return super(NewcarUpdate, self).dispatch(
request, *args, **kwargs)
You will need to import Http404 from django.http
You could that in the get_object method:
from django.http import Http404
# ...
class NewcarUpdate(UpdateView):
# ...
def get_object(self, queryset=None):
obj = super(NewcarUpdate, self).get_object(queryset)
if obj.car_owner == "sometext":
raise Http404
return obj
I do not want the logged in user to show up on this ModelMultipleChoiceField in order to restrict themselves from creating a following relationship with themselves? So how do I exclude the logged in user from the queryset, probably an easy fix but I'm new to Django and it has eluded me for a few hours now.
forms.py
class Add_Profile(forms.ModelForm):
def __init__(self,*args, **kwargs): # initializing your form in other words loading it
super(Add_Profile, self).__init__(*args, **kwargs)
user_id = kwargs.pop('user_id') # taking user_id out of the querylist
self.fields['follows'] = forms.ModelMultipleChoiceField(widget=forms.CheckboxSelectMultiple(), queryset=UserProfile.objects.filter(~Q(id=user_id)))
class Meta:
model = UserProfile
fields = (
'bio',
'follows',
'theme',
'profile_picture',
)
Views.py
#login_required
def edit_profile(request, user_id):
userprofile = UserProfile.objects.get(pk=user_id)
if request.method == 'POST':
edit_profile = Add_Profile(request.POST, request.FILES, instance=userprofile, user_id=request.user.id)
if edit_profile.is_valid():
edit_profile.save()
return redirect('/home/user/{0}/'.format(request.user.username))
else:
print edit_profile.errors
else:
edit_profile = Add_Profile(instance=userprofile, user_id=request.user.id)
return render (request, 'edit.html', {'form': edit_profile,})
Error: init() got an unexpected keyword argument 'user_id'
You can definitely do it using forms.Form instead of forms.ModelForm with something along the lines of this example in the docs:
from django import forms
from django.contrib.auth import get_user_model
class Add_Profile(forms.Form):
follows = forms.ModelMultipleChoiceField(queryset=None)
def __init__(self, user=None, *args, **kwargs):
super(Add_Profile, self).__init__(*args, **kwargs)
if user is not None:
self.fields['follows'].queryset = get_user_model().objects.exclude(pk=user.pk)
else:
self.fields['follows'].queryset = get_user_model.objects.all()
Just pass in the user you wish to exclude when you instantiate the form:
form = Add_Profile() # all users will be present in the dropdown
some_guy = User.objects.get(pk=4)
form = Add_Profile(user=some_guy) # all users except some_guy will be present
Define an __init__ method for the form class. Pass the logged in userid to the form while initializing it, this will work with a model form.
def __init__(self, *args, **kwargs):
user_id = kwargs.pop('user_id')
super(Add_Profile, self).__init__(*args, **kwargs)
self.fields['follows'] = forms.ModelMultipleChoiceField(queryset=UserProfile.objects.filter(~Q(user_id=user_id)))
While initializing your form, you can pass user_id
address_form = Add_Profile(request.POST, user_id=request.user.id)
The following code successfully adds a new ToolCalibration to my database, however it does not save the SerialFormset or PartFormset. I've been staring at this code trying to figure it out for quite some time now, so any and all help would be greatly appreciated. Thanks!
Forms.py
from django.forms import ModelForm
from django.forms.models import inlineformset_factory
from tool_cal.models import ToolCalibration, SerialNumber, PartNumber
class ToolForm(ModelForm):
class Meta:
model = ToolCalibration
SerialFormSet = inlineformset_factory(ToolCalibration, SerialNumber, can_delete=True)
PartFormSet = inlineformset_factory(ToolCalibration, PartNumber, can_delete=True)
Views.py
class ToolCreate(CreateView):
model = ToolCalibration
template_name = "create.html"
form_class = ToolForm
success_url = '/toolcal/success'
def get(self, request, *args, **kwargs):
"""
Handles GET requests and instantiates blank versions of the form
and its inline formsets.
"""
self.object = None
form_class = self.get_form_class()
form = self.get_form(form_class)
serial_form = SerialFormSet(prefix='serial')
part_form = PartFormSet(prefix='part')
return self.render_to_response(
self.get_context_data(form=form,
serial_form=serial_form,
part_form=part_form))
def post(self, request, *args, **kwargs):
"""
Handles POST requests, instantiating a form instance and its inline
formsets with the passed POST variables and then checking them for
validity.
"""
self.object = None
form_class = self.get_form_class()
form = self.get_form(form_class)
serial_form = SerialFormSet(self.request.POST, prefix='serial')
part_form = PartFormSet(self.request.POST, prefix='part')
if (form.is_valid() and serial_form.is_valid() and
part_form.is_valid()):
return self.form_valid(form, serial_form, part_form)
else:
return self.form_invalid(form, serial_form, part_form)
def form_valid(self, form, serial_form, part_form):
"""
Called if all forms are valid. Creates a ToolCalibration instance along with
associated Serial and Parts and then redirects to a
success page.
"""
self.object = form.save()
serial_form.instance = self.object
serial_form.save()
part_form.instance = self.object
part_form.save()
return HttpResponseRedirect(self.get_success_url())
def form_invalid(self, form, serial_form, part_form):
"""
Called if a form is invalid. Re-renders the context data with the
data-filled forms and errors.
"""
return self.render_to_response(
self.get_context_data(form=form,
serial_form=serial_form,
part_form=part_form))
Have you considered using django-extra-views? It contains a quick and easy CBV for dealing with InlineFormSets.
In addition to an InlineFormSetView and GenericInlineFormSetView, they've also got a CreateWithInlinesView that seems to be just what you want. Relevant docs here.
Example:
from extra_views import InlineFormSet, CreateWithInlinesView, UpdateWithInlinesView,
from extra_views.generic import GenericInlineFormSet
from tool_cal.models import ToolCalibration, SerialNumber, PartNumber
class SerialNumberInline(InlineFormSet):
model = SerialNumber
class PartNumberInline(GenericInlineFormSet):
model = PartNumber
class ToolCreateView(CreateWithInlinesView):
model = ToolCalibration
inlines = [SerialNumberInline, PartNumberInline]
def get_success_url(self):
return self.object.get_absolute_url()
Even if you don't want to use them, you could dig through the code and see how they handle it.
My form isn't saving the models that I need it to. My form:
class RewardForm(forms.Form):
quantity = forms.IntegerField(max_value=10, min_value=1, label=_('quantity'), initial=1)
reward = forms.CharField(max_length=50, label=_('reward'))
reward_denomination = forms.ModelChoiceField(queryset=Reward_Denomination.objects.all(), widget=forms.RadioSelect)
def clean_reward(self):
data = self.cleaned_data.get('reward')
try:
reward = Reward.objects.get(reward_name=data)
except ObjectDoesNotExist:
raise forms.ValidationError(_('Reward does not exist'), code='invalid')
return data
def clean_reward_denomination(self):
data = self.cleaned_data.get('reward_denomination')
try:
denomination = Reward_Denomination.objects.get(denomination=data)
except ObjectDoesNotExist:
raise forms.ValidationError(_('Denomination does not exist'), code='invalid')
return data
def save(self, request, commit=True):
user = request.user
data = self.cleaned_data
'try:
post_reward = data['reward']
post_denomination = data['reward_denomination']
quantity = data['quantity']
except LookupError:
raise Http404
reward = Reward.objects.get(reward_name=post_reward)
denomination = Reward_Denomination.objects.get(denomination=post_denomination)
user_points = Points.objects.filter(affiliate__id=user.id).aggregate(total_points=Sum('points'))
user_points = user_points['total_points']
try:
total_cost = (quantity * denomination.cost)
except ArithmeticError:
raise Http404
quote_price = -total_cost
if user_points >= total_cost:
reward_order = Points.objects.create(affiliate=user, points=quote_price, from_reward=True, from_offer=False)
status_coded = Status_Code.objects.create(short_name="Pending", name="The order is currently being reviewed", description="The order is in queue")
redeem_order = Redeem.objects.create(affiliate=user, status_code=status_coded, quantity=quantity, reward=reward, price=total_cost)
return reward_order
My Views:
class Reward_Detail(DetailView):
model = Reward
slug_field = 'reward_slug'
context_object_name = 'reward'
template_name = 'omninectar/reward.html'
#Detail Stuff
class RedeemReward(SingleObjectMixin, FormView):
template_name = 'omninectar/reward.html'
slug_field = 'reward_slug'
form_class = RewardForm
model = Reward
def post(self, request, *args, **kwargs):
self.object = self.get_object()
return super(RedeemReward, self).post(request, *args, **kwargs)
def get_success_url(self):
return reverse('omni:reward_confirmation')
class RewardBeautify(View):
def get(self, request, *args, **kwargs):
view = Reward_Detail.as_view()
return view(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
view = RedeemReward.as_view()
return view(request, *args, **kwargs)
So I initially thought that the FormView would handle the form processing (validate, and, if valid, run form.save(), etc). I'm following the FormView, SingleObjectMixin example on the Django website. I don't receive any errors when I try and submit the form, but no objects are created either. I've tried defining a form_valid method that runs the save method, I've tried putting it inside the post method in the formview, etc. Can anyone spot the error/errors? Thanks!
I'm new to view classes too and I had almost the same problem with Django 1.6.
You should add
def form_valid(self, form):
form.save()
return super(RedeemReward, self).form_valid(form)
method overriding to your RedeemReward class. This worked for me.
If you look to Django source code, you will see that there is no form saving in FormView class inheritance chain.
I am not sure if this will help or not, but I had issues finding code showing how to save the data from a FormView model. This is what I came up with. I hope it helps and you can apply it to your code.
forms.py
class JobCreateForm(forms.Form):
title = forms.CharField(label='Job Title', max_length=500)
number = forms.IntegerField(label='Job Number: ')
comps = forms.ModelMultipleChoiceField(label='Comparable Sales',
required=False, queryset=m.ComparableSale.objects.all())
details = forms.CharField(label='Job Details:', max_length=200,
required=False, widget=forms.Textarea(attrs={'rows':6, 'cols':20}))
Views.py
class JobCreateView(generic.FormView):
template_name = 'form_templates/createjob_form.html'
form_class = f.JobCreateForm
model = models.Job
success_url = '/'
def form_valid(self, form):
comps = form.cleaned_data['comps']
title = form.cleaned_data['title']
number = form.cleaned_data['number']
details = form.cleaned_data['details']
job = models.Job(title=title, number=number, details=details)
job.save()
print(comps)
if comps != []:
job.comps.add(*comps)
return super(JobCreateView, self).form_valid(form)
You can write your own ModelFormView using the mixins provided by Django (specifically, the ModelFormMixin). Then your form will be saved on a successful post.
from django.views.generic.base import TemplateResponseMixin
from django.views.generic.edit import ModelFormMixin, ProcessFormView
class BaseModelFormView(ModelFormMixin, ProcessFormView):
pass
class ModelFormView(TemplateResponseMixin, BaseModelFormView):
pass