I'm new in Django and I'm trying to pre fill one of the fields of my form with a slug.
I'm getting the slug from another model. I'm not using ForeignKey because that shows me a list with my objects and I want to save in the form the same slug that I'm using in the url.
Maybe I'm not thinking this right. What should I do?
Thank you!
This are my models:
from django.db import models
class Thing(models.Model):
name = models.CharField(max_length=255,)
rut = models.CharField(max_length=12, blank= True)
cel = models.CharField(max_length=12, blank= True)
slug = models.SlugField(unique=True)
class Control(models.Model):
id_p = models.SlugField()
pa = models.CharField(max_length=3,)
My forms
from django.forms import ModelForm
from collection.models import Thing, Control, Medicamento
class ThingForm(ModelForm):
class Meta:
model = Thing
fields = ('name', 'rut','cel','pet',)
class ControlForm(ModelForm):
class Meta:
model = Control
exclude = ['id_p']
This is what I'm doing in the views
def add_control(request, slug):
thing = Thing.objects.get(slug=slug)
form_class = ControlForm
form_class(initial={'id_p':thing})
if request.method == 'POST':
form = form_class(request.POST)
if form.is_valid():
form.save()
return redirect('thing_detail', slug=thing.slug)
else: form = form_class()
return render(request, 'things/control.html', {
'thing': thing,
'form': form,
})
So, I figure it out!
In views.py, after " if form.is_valid():"
I put this:
prev = form.save(commit=False)
prev.id_p = thing.slug
prev.save()
In that way I put the data in the excluded field before I commit the form.
Related
i am saving a form with a filefield, and saying upload_to to a user_path from the userprofile. I do not know how to write the view for the form
models.py
def nice_user_folder_upload(instance, filename):
extension = filename.split(".")[-1]
return (
f"{instance.UserProfile.Assigned_Group}/{filename}"
)
class Metadataform(models.Model):
id = models.AutoField(primary_key=True)
Authors_Name = models.CharField(max_length=500, blank=True, null=True)
Document = models.FileField(upload_to=nice_user_folder_upload)
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
Assigned_Group= models.CharField(max_length=500, choices=Group_choices, default='Please Select')
def __str__(self):
return self.user.username
views.py
def Metadata_submission(request):
Authors_Name = request.POST["Authors_Name"]
if request.method == 'POST':
form = Fileuploadform(request.POST, request.FILES)
if form.is_valid():
form.save()
return render(request, "home.html")
else:
form = Fileuploadform()
# forms.py
class Fileuploadform(forms.ModelForm):
class Meta:
model = Metadataform
fields = ['Authors_Name','Affliations','Dataset_Creation_Date','Publication_Ref','Embargo_Time','DataGeneration_Type','Methods','Instruments','Software','Models','Device','Configuration','Precursor','Data_Type','Variables','Error_Estimation','Document']
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('Assigned_Group',)
i am getting an AttributeError at /Metadata_submission/
'Metadataform' object has no attribute 'UserProfile'
The problem here I think is you have so many fields here that might not be associated with your Metadataform model (Maybe you haven't posted it in full). I think you should consider reading doc. By the look of it, you are trying to add UserProfile somewhere on your form, which is causing the error.
I am new to Django and I need to know how to have DetailView and UpdateView on the same Page.
I have two Models:
class Company(models.Model):
CustomerNo = models.AutoField(primary_key=True)
Company = models.CharField(max_length=200)
Str = models.CharField(max_length=200)
Zip = models.IntegerField()
City = models.CharField(max_length=200)
Name = models.CharField(max_length=200)
Phone = models.IntegerField()
Mobile = models.IntegerField()
Email = models.EmailField(max_length=200)
Web = models.CharField(max_length=200)
Info = models.CharField(max_length=200)
def __str__(self):
return self.Company
class Contact(models.Model):
Contact_Company = models.ForeignKey(Company, on_delete=models.CASCADE)
Contact_Name = models.CharField(max_length=200)
Contact_Phone = models.IntegerField()
Contact_Mobile = models.IntegerField()
Contact_Fax = models.IntegerField()
Contact_E_Mail = models.EmailField()
Contact_Web = models.CharField(max_length=200)
def __str__(self):
return self.Contact_Name
I want to build a page where I can see the company data from the first model and an update form for contacts realeted to the first model.
I enter the page with pk, from the previous page, its a DetailView for the first Model and with additionally context to list the Contact data with a for loop in Template.
I can use UpdateView to get data in the form and save it. but I don't know
how do display the realeted Company on the same page. Is there a way to use DetailView and UpdateView together?
I can use this UpdateView to change the Contact data, but I don't know how to include extra context from the first model to display the address on same page.
The success URL is wrong too.
I need to pass the pk from the first model so I can go back to the right list on previous page.
class ContactUpdate(UpdateView):
model = Contact
form_class = ContactCreateForm
template_name = 'customer/contact_update.html'
def get_success_url(self):
return reverse('customer_list', kwargs={'pk': self.object.pk})
def get_context_data(self, **kwargs):
context = super(ContactUpdate, self).get_context_data(**kwargs)
return context
Maybe FormMixin is a solution, I used it to Display the Data from
first Model and form for second Model on same Page. But I am really stuck
to realize this with UpdateForm.
I hope you understand my problem, sorry for my english.
Thank you for your help.
Forms.py
from django.forms import ModelForm
from .models import Company
from .models import Contact
from django.forms import HiddenInput
from django import forms
class CompanyCreateForm(ModelForm):
class Meta:
model = Company
fields = '__all__'
class ContactCreateForm(ModelForm):
class Meta:
model = Contact
widgets = {'Contact_Company': forms.HiddenInput()}
fields = [
'Contact_Company',
'Contact_Name',
'Contact_Phone',
'Contact_Mobile',
'Contact_Fax',
'Contact_E_Mail',
'Contact_Web',
You need to add form in the detail view,
class PostDetailView(DetailView):
model = Post #your model name
template_name = 'detail.html' #your template
# here you will add your form
def get_context_data(self, **kwargs):
context = super(PostDetailView, self).get_context_data(**kwargs)
context['contactupdateform'] = ContactCreateForm()
return context
# Add POST method
def post(self, request, slug):
post = get_object_or_404(Post, slug=slug)
form = contactupdateform(request.POST)
if form.is_valid():
# from here you need to change your post request according to your requirement, this is just a demo
obj = form.save(commit=False)
obj.post = post
obj.author = self.request.user #to add the user
obj.save()
return redirect('detail', post.slug) #add your url
Make sure you are adding the POST request correctly, according to your model and url. This is an outline you can refer.
To add the form in the HTML, you need to do this,
{% for form in contactupdateform %}
<-- Add Your CSRF token and form here --!>
{% endfor %}
You can import this (LoginRequiredMixin) and insert in the updateview as an argument as the contact is a user
then try putting this in the models.py file :
def get_absolute_url(self):
return reverse('customer_list', kwargs={'pk': self.pk})
and remove (get_success_url) from views.py
You might need these too in the updateview Class "ContactUpdate"
login_url = '/login/'
redirect_field_name = <-- template path(html) of the page you want to reverse to...
HOPE THIS HELPS...
I am writing an application which stores "Jobs". They are defined as having a ForeignKey linked to a "User". I don't understand how to pass the ForeignKey into the model when creating it. My Model for Job worked fine without a ForeignKey, but now that I am trying to add users to the system I can't get the form to validate.
models.py:
from django.db import models
from django import forms
from django.contrib.auth.models import User
class Job(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=50, blank=True)
pub_date = models.DateTimeField('date published', auto_now_add=True)
orig_image = models.ImageField('uploaded image', upload_to='origImageDB/', blank=True)
clean_image = models.ImageField('clean image', upload_to='cleanImageDB/', blank=True)
fullsize_image = models.ImageField('fullsize image', upload_to='fullsizeImageDB/')
fullsize_clean_image = models.ImageField('fullsize clean image', upload_to='fullsizeCleanImageDB/')
regions = models.TextField(blank=True)
orig_regions = models.TextField(blank=True)
class JobForm(forms.ModelForm):
class Meta:
model = Job
In views.py I was creating the objects as follows:
if request.method == 'POST':
form = JobForm(request.POST, request.FILES)
if form.is_valid():
#Do something here
I understand that this passes the form data and the uploaded files to the form. However, I don't understand how to pass in a User to be set as the ForeignKey.
Thanks in advance to anyone who can help.
A typical pattern in Django is:
exclude the user field from the model form
save the form with commit=False
set job.user
save to database
In your case:
class JobForm(forms.ModelForm):
class Meta:
model = Job
exclude = ('user',)
if request.method == 'POST':
form = JobForm(request.POST, request.FILES)
job = form.save(commit=False)
job.user = request.user
job.save()
# the next line isn't necessary here, because we don't have any m2m fields
form.save_m2m()
See the Django docs on the model form save() method for more information.
Try:
if request.method == 'POST':
data = request.POST
data['user'] = request.user
form = JobForm(data, request.FILES)
if form.is_valid():
#Do something here
For example I have got the Student model
class Student(models.Model):
first_name = models.CharField(max_lenght=100)
last_name = models.CharField(max_lenght=100)
learning_group = models.CharField(max_lenght=100)
So I want to create the following form for each student in some group:
| Student | Mark | Absent |
| John Smyth | input for mark | input for absent hours|
Thank you for your help.
EDIT:
I am storing my absent and mark fields in JSonField() and it look like this
{ student_pk: 1, mark: 5, absent: 3 }
So what did I tried:
At first I tried to implement this through overriding forms.Form init method but it was formatted wrong
def MarkBookForm(forms.Form):
def __init__(self, *args, **kwargs):
self.students = kwargs.pop('students', None)
super(MarkBookForm, self).__init__(*args, **kwargs)
for student in self.students:
self.fields["student_{}".format(student.pk)] = forms.CharField(initial="{} {}".format(student.first_name, student.last_name)
self.fields["mark_{}".format(student.pk)] = forms.FloatField()
self.fields["absent_{}".format(student.pk)] = forms.FloatField()
This is what I want
And this what i did
First of all you should define your model for mark and absent
You can use sth like this( not tested :) ):
models.py:
class MyModel(models.Model):
field1 = models.CharField(max_length=40, blank=False, null=False)
field2 = models.CharField(max_length=60, blank=True, null=True)
forms.py:
class FormForMyModel(forms.Form):
form_field1 = forms.CharField(max_length=40, required=True)
form_field2 = forms.CharField(max_length=60, required=False)
views.py:
def create_a_my_model(request):
if request.method == 'POST':
form = FormForMyModel(request.POST)
if form.is_valid():
my_model = MyModel()
my_model.field1 = form.cleaned_data.get('form_field1', 'default1')
my_model.field2 = form.cleaned_data.get('form_field2', 'default2')
my_model.save()
else:
form = FormForMyModel()
context_data = {'form': form}
return HttpResponse('templtate.html', context_data)
The above example outlines generic form workflow.
You can notice two annoying issues in the above example:
I have to define Fields on MyModel and Fields on FormForMyModel separately. However, there is a lot of similarity between those two groups (types) of Fields, so that's kind of duplicate work. The similarity grows when adding labels, validators, etc.
creating of MyModel instance is a bit silly, having to assign all those values manually.
This is where a ModelForm comes in.
So back to the two issues:
Instead of defining a form Field for each model Field, I simply define model = MyModel in the the Meta class. This instructs the Form to automatically generate form Fields from model Fields.
Model forms have save method available. This can be used to create instance of model in one line in the view, instead of manually assigning field-by-field.
So, lets make the example above with a ModelForm:
models.py:
class MyModel(models.Model):
field1 = models.CharField(max_length=40, blank=False, null=False)
field2 = models.CharField(max_length=60, blank=True, null=True)
forms.py:
class MyModelForm(forms.ModelForm): # extending ModelForm, not Form as before
class Meta:
model = MyModel
views.py:
def create_a_my_model(request):
if request.method == 'POST':
form = MyModelForm(request.POST)
if form.is_valid():
# save the model to database, directly from the form:
my_model = form.save() # reference to my_model is often not needed at all, a simple form.save() is ok
# alternatively:
# my_model = form.save(commit=False) # create model, but don't save to database
# my.model.something = whatever # if I need to do something before saving it
# my.model.save()
else:
form = MyModelForm()
context_data = {'form': form}
return HttpResponse('templtate.html', context_data)
This is probably a fairly simple question, but I can't seem to figure it out from the Django Docs. I'm trying to save a two ModelForms at once with one being a ForeignKey of another. I'm not sure how to write the logic in the views to ensure these go together properly.
models.py
class Address(models.Model):
address = models.CharField(max_length=100)
city = models.CharField(max_length=50)
zipcode = models.PositiveIntegerField()
class Store(models.Model):
name = models.CharField(max_length=100)
description = models.CharField(max_length=140, blank=True)
address = models.ForeignKey(Address, null=True)
forms.py
class CreateStore1Form(forms.ModelForm):
class Meta:
model = Store
exclude = ('address',)
class CreateStore2Form(forms.ModelForm):
class Meta:
model = Address
views.py
#login_required
def create(request):
if request.method == "POST":
form1 = CreateStore1Form(request.POST)
form2 = CreateStore2Form(request.POST)
if form1.is_valid() and form2.is_valid():
store = form1.save(address)
new_address = form2.save(commit=False)
new_address.store = store
mew_address.save()
else:
form1 = CreateStore1Form()
form2 = CreateStore2Form()
return render(request, 'create.html', locals())
Any help would be appreciated. Thanks!
Django provides inline formsets for this use case:
Inline formsets is a small abstraction layer on top of model formsets.
These simplify the case of working with related objects via a foreign
key.
forms.py
class AddressForm(forms.ModelForm):
class Meta:
model = Address
class StoreForm(forms.ModelForm):
class Meta:
model = Store
exclude = ('address',)
views.py
from django.forms.models import inlineformset_factory
#login_required
def create(request):
AddressInlineFormSet = inlineformset_factory(Address, Store, form=AddressForm)
if request.method == 'POST':
storeForm = StoreForm(request.POST)
if storeForm.is_valid():
new_store = storeForm.save()
addressInlineFormSet = AddressInlineFormSet(request.POST, request.FILES, instance=new_store)
if addressInlineFormSet.is_valid():
addressInlineFormSet.save()
return HttpResponseRedirect(reverse('some_happy_customer_url'))
else:
classificationformset = ClassificationInlineFormSet(request.POST, request.FILES, instance=new_store)
else:
addressInlineFormSet = AddressInlineFormSet()
storeForm = StoreForm()
return render(request, 'create.html', locals())
Please see also this question for more details.