The issue is next: I'm using existing templates for my site. I have an order page. I want to use my own template for form
I know that I can implement it just using {% for field in form %}. But I need to show not all fields. For example, here is my Order model:
class Order(models.Model):
state_choices = ('ACTIVE', 'COMPLETED', 'FROZEN')
order_date = models.DateTimeField(auto_now_add=True)
delivery_time = models.CharField(max_length=100)
address_city = models.CharField(max_length=40)
address_street = models.CharField(max_length=40)
address_building = models.CharField(max_length=40)
state = models.CharField(max_length=200, default='ACTIVE')
client = models.ForeignKey(CustomUser)
I need to show just: address_city, address_street, address_building and delivery_time. Because in view I just return current user and set it to client. Here is my view that saves Order:
def submit(request):
args = {}
args['form'] = OrderForm
if request.POST:
order_form = OrderForm(request.POST)
if order_form.is_valid():
order_form.save()
user = request.user
address_country = order_form.cleaned_data['address_country']
address_city = order_form.cleaned_data['address_city']
address_building = order_form.cleaned_data['address_building']
delivery_time = order_form.cleaned_data['delivery_time']
new_order = Order(address_country=address_country,
address_city=address_city,
address_building=address_building,
delivery_date=delivery_time, client=user)
new_order.save()
Basket.objects.filter(client=user).delete()
return redirect('/order/')
else:
return render(request, 'order_page.html', args)
I guess that new_order is odd, because order_form.save() saves it. But how to set user of current session to Order through form?
To understand it all, here is my OrderForm code:
class OrderForm(forms.ModelForm):
class Meta():
model = Order
fields = ['address_city', 'address_street', 'address_building', 'delivery_time']
I handle this kind of logic in the form's init method, and when creating the form in the view I pass in the request object as a kwarg for the form to get its data from, then hide the appropriate fields:
In forms.py...
class YourForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
request = kwargs.pop('request', None)
super(YourForm, self).__init__(*args, **kwargs)
if request:
self.fields['field'].initial = process_request_to_get_value(request)
self.fields['field'].widget = forms.HiddenInput()
# More logic here if needed
class Meta:
model = Order
In views.py...
def your_view(request):
if request.method == 'POST':
form = YourForm(request.POST, request = request)
if form.is_valid():
form.save()
return HttpResponseRedirect('somewhere')
else:
form = YourForm(request = request)
return render_to_response('template',
{'form': form,},
context_instance = RequestContext(request))
Related
I have a model with a unique together and I want to validate this condition in my modelform. The unique together includes a field that is passed to the form in an init method, the user, and a field that is in the form. I'm having problems with validating a unique together condition.
EDIT
I have modified the code to what you see below
model:
class Objective(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
user = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
course = models.ForeignKey(Course, on_delete=models.CASCADE)
objective_name = models.CharField(max_length=10)
description = models.CharField(max_length=300)
mode = models.CharField(max_length=2, default='LA')
class Meta:
unique_together = ['user', 'objective_name', 'course']
ordering = ['objective_name']
def __str__(self):
return self.objective_name
The view:
def addobjective(request, course_id):
this_course = get_object_or_404(Course, pk=course_id)
user = request.user
all_courses = Course.objects.filter(user=user)
objective_list = Objective.objects.filter(
course=this_course).order_by('objective_name')
context = {'objective_list': objective_list}
if request.method == 'POST':
form = ObjectiveForm(user, request.POST, my_course=this_course)
if form.is_valid():
obj = form.save(commit=False)
obj.course = this_course
obj.user = user
obj.save()
form = ObjectiveForm(user, my_course=this_course)
context['form'] = form
return redirect('gradebook:addobjective', course_id=this_course.id)
else:
form = ObjectiveForm(user, my_course=this_course)
context['form'] = form
context['this_course'] = this_course
context['all_courses'] = all_courses
return render(request, 'gradebook/objective-form.html', context)
forms.py:
class ObjectiveForm(ModelForm):
def __init__(self, user, *args, **kwargs):
self.request = kwargs.pop('request', None)
my_course = kwargs.pop('my_course')
self.objs = Objective.objects.filter(user=user, course=my_course)
super(ObjectiveForm, self).__init__(*args, **kwargs)
class Meta:
model = Objective
fields = ('objective_name', 'description', 'mode',)
def clean(self):
super(ObjectiveForm, self).clean()
objective_name = self.cleaned_data.get("objective_name")
description = self.cleaned_data.get("description")
mode = self.cleaned_data.get("mode")
if self.objs.filter(objective_name=objective_name).count() > 0:
print("error")
del self.cleaned_data["objective_name"]
del self.cleaned_data["description"]
del self.cleaned_data["mode"]
raise ValidationError(
"This course already has a learning objective with this name.")
return self.cleaned_data
EDIT
The error I know get is |as_crispy_field got passed an invalid or inexistent field. This occurs when I enter in a value for objective_name that is a duplicate. error is printed to the console and then I get the above error. I do not get the ValidationError.
The full traceback can be seen here.
Maybe with the form I do not need the unique together constraint in the model?
Yes, my_course field is not defined in Objective model , so maybe you need to change this line:
form = ObjectiveForm(request.POST, my_course=this_course)
To
form = ObjectiveForm(request.POST, course=this_course)
It turns out that the problem was caused by improper indentation of return redirect('gradebook:addobjective', course_id=this_course.id) after the if form.is_valid():. The return redirect has to be a part of the POST request.
I have a list of jobs that are created by the admin. When one of the agents starts the job by updating the notes. I would like to save that agent to the job model.
Models.py
class Job(models.Model):
name = models.CharField(max_length=20, blank=True, null=True)
agent = models.ForeignKey("Agent", on_delete=models.SET_NULL, null=True)
start_date = models.DateField(null=True, blank=True)
notes = models.TextField(default=0, null=True, blank=True)
Views.py
class JobUpdateView(LoginRequiredMixin, generic.UpdateView):
template_name = "jobs/job_update.html"
queryset = Job.objects.all()
form_class = JobModelForm
def get_success_url(self):
return reverse("jobs:job-list")
def job_update(request, pk):
job = Job.objects.get(id=pk)
form = JobModelForm(instance=job)
if request.method == "POST":
form = JobModelForm(request.POST, instance=job)
if form.is_valid():
form.save()
return redirect("/jobs)
context = {
"form": form,
"job': job
}
return render(request, "jobs/job_update.html", context)
**Forms.py **
class JobModelForm(forms.ModelForm):
class Meta:
model = Job
fields = ('agent', 'start_date', 'notes')
Why don't you save appropriate Agent instance after form.save() is called ?
class JobUpdateView(LoginRequiredMixin, generic.UpdateView):
template_name = "jobs/job_update.html"
queryset = Job.objects.all()
form_class = JobModelForm
def get_success_url(self):
return reverse("leads:lead-list")
def job_update(request, pk):
job = Job.objects.get(id=pk)
form = JobModelForm(instance=job)
if request.method == "POST":
form = JobModelForm(request.POST, instance=job)
if form.is_valid():
form.save()
# Here
job.agent = Agent.objects.get(user=request.user)
job.save()
return redirect("/jobs)
context = {
"form": form,
"job': job
}
return render(request, "jobs/job_update.html", context)
If you don't want to make another update query, then make custom form class is an option. You can override form class, allow it to be passed with agent instance, and set agent to job instance right after save method is called.
I'm trying to save and retrive the data owned by the user.
I mean, in one Sqlite3 DB I store the tables for all users but each one has their one data store in it, how can I give each one their own data.
this are my models, view and form
MODEL.PY
class Cuentas (models.Model):
rubro_cta = models.ForeignKey(TipoC, on_delete=models.CASCADE, verbose_name = u'Tipo')
sub_rubro_cta = models.ForeignKey(Sub_rubro, on_delete=models.CASCADE, verbose_name = u'Sub Rubro')
titulo_cuenta = models.CharField(max_length=50)
detalle_cuenta = models.CharField(max_length=60)
importe_cuenta = models.FloatField()
def save(self, *args, **kwargs):
self.importe_cuenta = round(self.importe_cuenta, 2)
super(Cuentas, self).save(*args, **kwargs)
def __str__(self):
return self.detalle_cuenta
FORMS.PY
class CuentasForm (forms.ModelForm):
class Meta:
model = Cuentas
fields = ['rubro_cta', 'sub_rubro_cta', 'detalle_cuenta', 'importe_cuenta']
labels = {
'rubro_cta': _('Cuenta'),
'sub_rubro_cta': _('Tipo'),
'detalle_cuenta': _('Detalle'),
'importe_cuenta': _('Importe'),
}
VIEWS.PY
#login_required
def carga (request):
if request.method == 'POST':
form = CuentasForm(request.POST)
if form.is_valid:
form.save()
return redirect('balance')
else:
form = CuentasForm()
return render (request, "ProyetoWebApp/carga.html",{"form": form})
you have to add a foreign key field to user in your Cuentas class:
class Cuentas (models.Model):
user = models.ForeignKey(User, models.CASCADE)
...
in your view add this code for GET method:
info = None
if request.method == 'GET':
info = Cuentas.objects.get(user=request.user)
return render (request, "ProyetoWebApp/carga.html",{"form": form, "info":info})
I have a custom form that is not saving to the database. I do not get any errors but the values do not save to the database. Any ideas?
views.py
def diseasestateoption(request, disease_id, state_id):
state = get_object_or_404(State, pk=state_id)
disease = get_object_or_404(Disease, pk=disease_id)
if request.method == "POST":
form = UpdateStateWithOptionsForm(request.POST, instance=state)
if form.is_valid():
for option_id in request.POST.getlist('options'):
state_option = StateOption.objects.create(partstate=state, partoption_id=int(option_id))
state_option.save()
return HttpResponseRedirect(reverse('success'))
else:
form = UpdateStateWithOptionsForm(instance=state)
models.py
class Option(models.Model):
relevantdisease = models.ForeignKey(Disease)
option = models.CharField(max_length=300)
class State(models.Model):
state = models.CharField(max_length=300, verbose_name='state')
relevantdisease = models.ForeignKey(Disease, verbose_name="disease")
relevantoption = models.ManyToManyField(Option, through='StateOption')
class StateOption(models.Model):
parttstate = models.ForeignKey(State)
partoption = models.ForeignKey(Option)
forms.py
class UpdateStateWithOptionsForm(forms.ModelForm):
class Meta:
model = State
exclude = ['state', 'relevantdisease']
def __init__(self, *args, **kwargs):
super(UpdateStateWithOptionsForm, self).__init__(*args, **kwargs)
self.fields['relevantoption']=forms.ModelMultipleChoiceField(queryset=Option.objects.all(),required=True, widget=forms.CheckboxSelectMultiple)
I think Problem is with getting option from POST, use-
request.POST.getlist('relevantoption')
in stead of
request.POST.getlist('options')
apart, why to use form here for single multiple choice field, even where you are modifying choices also and not using form.save too.
I don't know if I'm approaching the problem in the right way. The intended outcome is to have a form that displays only name and description. Once the user submits the form I want to add the current user as owner and check if there's already an entry that has the same name and user. If there is, I want to return the form with errors. If not, I want to save Status.
My model:
class Status(models.Model):
name = models.CharField(max_length=100)
description = models.TextField(blank=True)
owner = models.ForeignKey(User)
active = models.BooleanField(default=True)
class Meta:
unique_together = ('name','owner')
My View:
def settings_status(request):
status_form = StatusForm()
if request.method == 'POST':
status_form = StatusForm(request.POST)
if status_form.is_valid():
new_status = Status()
new_status.name = status_form.cleaned_data['name']
new_status.description = status_form.cleaned_data['description']
new_status.owner = request.user
new_status.save()
return render_to_response('base/settings_status.html',{
'status_form' : status_form,
}, context_instance=RequestContext(request))
I have tried numerous things, but I keep running into the problem that if I add owner to the object separately then it isn't available to the model's clean function and therefore can't be used to check if name and owner are unique.
Several ways to do this:
for example, passing in the user (owner) to the form:
forms.py:
class StatusForm(forms.Form):
def __init__(self, *args, **kwargs):
self.user = kwargs.pop('user','')
super(StatusForm, self).__init__(*args, **kwargs)
self.fields['name'] = forms.CharField(label='Name')
self.fields['description'] = CharField(label='Description', widget=forms.Textarea)
def clean(self):
cleaned_data = self.cleaned_data
name = cleaned_data.get('name')
if Status.objects.filter(name=name, owner=self.user).exists():
self._errors['name'] self.error_class(['Status with this name exists'])
return cleaned_data
views.py:
def settings_status(request):
if request.method == 'POST':
status_form = StatusForm(request.POST, user=request.user)
if status_form.is_valid():
new_status = Status()
new_status.name = status_form.cleaned_data['name']
new_status.description = status_form.cleaned_data['description']
new_status.owner = request.user
new_status.save()
else:
status_form = StatusForm(user=request.user)
context = {'status_form':status_form,}
return render_to_response('base/settings_status.html', context,
context_instance=RequestContext(request))
Also look at setting initial data depending on your form setup and consider using a ModelForm.