I want to send data from Form but can't send a specific data
for example:
in my model has a student that I want send separate from view
in view:
student = Student.objects.filter(id=id)
if request.method == "POST":
form = StudentProject(request.POST, files=request.FILES)
form.student_id=id
form.save()
return redirect('main')
in form:
class Meta:
model=Project
fields=['name','link','image','body','term']
in model:
name=models.CharField(max_length=100,null=False)
link=models.CharField(max_length=1000,null=False)
image=models.ImageField(upload_to='static/project/images/')
body=models.TextField()
term=models.DecimalField(max_digits=1,decimal_places=0,null=False)
student=models.ForeignKey(Student,on_delete=models.CASCADE)
created_at=models.DateTimeField(default=timezone.now)
I found that I can modify ModelForm in django like this:
class MyForm(forms.ModelForm):
name=forms.CharField(label="Name",widget=forms.TextInput(
attrs={
'class':'form-control',
}
))
If you want to send specific data, then exclude all the fields that you don't want to be on the form. Suppose I only want the name of the project:
class Meta:
model = Project
fields = ['name']
in my model has a student that I want send separate from view
I think the cleanest way to do this is to separate your initial form into two, create two views, and have the user input it separately.
Related
I decided to organize my page using two separated forms to build a single model:
class MandateForm1(forms.ModelForm):
class Meta:
model = Mandate
fields = ("field_a", "field_b"),
class MandateForm2(forms.ModelForm):
class Meta:
model = Mandate
fields = ("field_c", "field_d"),
In my view, I would get something like:
form_1 = MandateForm1(request.POST)
form_2 = MandateForm2(request.POST)
This way, how can I create my model using Form save() method?
As a current workaround, I'm using Mandate.objects.create(**form_1.cleaned_data, **form_2.cleaned_data). The drawback is I need to handle M2M manually with this method.
Thanks.
The way you have phrased the question, this is all being submitted in the same POST from a single page. If that's true, you might be able to do something like:
if request.method == "POST" and form1.is_valid() and form2.is_valid():
form1.instance.field_c = form2.instance.field_c
form1.instance.field_d = form2.instance.field_d
form1.save()
I'm currently writing a system in Django where I'd like to save a user at the same time i'm creating another model.
Model Code:
class MyModel(models.Model):
user = models.OneToOneField(User,related_name="profile",primary_key=True)
custom_field = models.CharField(...)
The model is more elaborate of course, but it shows the setup of the whole thing.
Example form:
First name: [input]
Last name: [input]
Email: [input]
Password: [pass_input]
Custom Text: [text_input]
Is this at all possible using a ModelForm?
Yes; you could create a ModelForm that corresponds to MyModel:
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
fields = ['custom_field']
Then in your view, you could interrupt the save of this form using commit=False (https://docs.djangoproject.com/en/1.11/topics/forms/modelforms/#the-save-method) and set the user value of your new object manually. For example, you could set user = request.user like so:
if form.is_valid():
instance = form.save(commit = False)
instance.user = request.user
instance.save()
form.save_m2m() #if your form has any m2m data to save
Yes. In your forms.py file, add this code:
class UserForm(ModelForm):
class Meta:
model = User
fields = ('first_name', 'last_name', 'email')
class ProfileForm(ModelForm):
class Meta:
model = MyModel
fields = ('customfield1', 'customfield2')
EDIT
Here is a great tutorial on to do this: https://simpleisbetterthancomplex.com/tutorial/2016/07/22/how-to-extend-django-user-model.html
This maybe a simple question, but I do not have any idea how to do this.
I have two models in Django.
class ModelA(models.Model):
some_member = models.Charfield(...)
class ModelB(models.Model):
model = OneToOneField(ModelA)
other_member = models.Charfield(...)
ModelA is filled in by a ModelForm and then redirect to the form for ModelB.
How can I Autofill the OneToOneField based on the previous form.
Thank you for helping.
I am doing it like this now
class ModelBView(CreateView):
.......
def form_valid(self, form):
model_b = form.save(commit=False)
model_a_form = ModelAForm(self.request.POST)
model_b.model = model_a_form.save(commit=False)
model_b.save()
return super(ModelBView, self).form_valid(form)
but get the error: "...could not be created because the data didn't validate."
So here the problem is, I simply can get the data from the previous form by request.POST.
How can I get this data.
Maybe you can save the data from ModelForm for ModelA in request.session or request.get and redirect to the next page for ModelB, where you can get the data for model field in ModelB then fill it.
It depends on what you want exactly.
If you want to auto-fill the field in the second form, then you can use the initial keyword argument when instantiating the form for ModelB (e.g. in your view); like this:
def my_view(request):
"""
Save data to ModelA and show the user the form for ModelB
"""
if request.method == 'POST':
# Save ModelA instance
model_a_form = ModelFormA(request.POST)
if model_a_form.is_valid():
model_a_instance = model_a_form.save()
# Once saved, show the user the form for ModelB, prefilled
# with the result from the previous form
model_b_form = ModelFormB(initial={'model': model_a_instance})
# etc. Render the page as usual
else:
# ...
elif request.method == 'GET':
# ...
If, on the other hand, you don't want ModelA to appear in the second form as a field, but still link it to the resulting instance, you can do something like this when handling the response of the second form.
# ... instance of first model is saved in `model_a_instance`
# Initiate an empty instance of ModelB, with the value of `model` field set to model_a_instance
model_b_instance = ModelB(model=model_a_instance)
# Provide it as an instance to your model form
model_b_form = ModelFormB(request.POST, instance=model_b_instance)
if model_b_form.is_valid():
# Everything else should work fine.
Hope this helps.
Let's say I have the following model:
class Folder(models.Model):
name = models.CharField(default='untitled', max_length=255)
parent = models.ForeignKey('self', null=True, blank=True)
root = models.ForeignKey('self', null=True, blank=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL)
In my app, this class is used to represents two types of folders: a normal folder-object and a so called root_folder-object, which does not have a parent nor a root-FK set.
I created a custom ModelForm with custom clean(), which is working like a charm (according to unittests and manual testing):
class FolderForm(ModelForm):
def __init__(self, *args, **kwargs):
try:
data = kwargs.get('data', None).copy()
except AttributeError:
data = None
self.prefix = kwargs.get('prefix')
user = kwargs.pop('user', None)
if data is not None:
if user is not None:
data[self.add_prefix('user')] = user.id
kwargs['data'] = data
super(FolderForm, self).__init__(*args, **kwargs)
def clean(self):
# just working fine, so I won't include it here
pass
class Meta:
model = Folder
fields = '__all__'
So, because my root-folder is just a normal Folder-object with blank FKs, I don't want to even show these fields to the user while creation. I created another form for this:
class AddRootFolderForm(FolderForm):
class Meta:
model = Folder
exclude = ['parent', 'root', 'user']
As you can see, I exclude user aswell, this value will be set in the view. Currently, this is my view code:
#login_required
def create_rootfolder(request):
if request.method == 'POST':
form = FolderForm(data = request.POST,
user = request.user)
else:
form = AddRootFolderForm()
if form.is_valid():
new = form.save()
return redirect('show_rootfolder', root_id = new.id)
return render(request, 'create_rootfolder.html',
{ 'form': form })
This whole setup is working, but seems awful hackerish. Is there any better approach to hide certain fields from the user (meaning: Don't even show them as hidden fields), but include them in validation? My main problem is, that I can't use the same form for displaying and validating, because the excluded fields will not be validated, if I use AddRootFolderForm as single form instance.
I am aware that I can exclude the fields dynamically in the constructor, I even tried this, but it got my constructor bloated to 50 LOC, which seemed unclean.
So what would be the best approach to validate the model with all fields, even if they were not included in the form shown to the user?
Why validate fields, not used in Form?
The cleaning process is the way to check the data posted by a user. The rest of the data, required for Model operations must be added after the form validation
if form.is_valid():
new = form.save(commit=False)
new.user = request.user
...
new.save()
Suppose I have two models:
class Topic(models.Model):
title = models.CharField()
# other stuff
class Post(models.Model):
topic = models.ForeignKey(Topic)
body = models.TextField()
# other stuff
And I want to create a form contains two fields: Topic.title and Post.body. Of course, I can create the following form:
class TopicForm(Form):
title = forms.CharField()
body = forms.TextField()
# and so on
But I don't want to duplicate code, since I already have title and body in models. I'm looking for something like this:
class TopicForm(MagicForm):
class Meta:
models = (Topic, Post)
fields = {
Topic: ('title', ),
Post: ('body', )
}
# and so on
Also, I want to use it in class based views. I mean, I would like to write view as:
class TopicCreate(CreateView):
form_class = TopicForm
# ...
def form_valid(self, form):
# some things before creating objects
As suggested in comments, I could use two forms. But I don't see any simple way to use two forms in my TopicCreate view - I should reimplement all methods belongs to getting form(at least).
So, my question is:
Is there something already implemented in Django for my requirements? Or is there a better(simpler) way?
or
Do you know a simple way with using two forms in class based view? If so, tell me, it could solve my issue too.
You can create two separate forms having the required fields, for each model. Then show both forms in the template inside one html element. Both forms will get rendered and then submitted individually. You can then process the forms separately in the view.
class TopicForm(ModelForm):
class Meta:
model = Topic
fields = ("title", ..)
class PostForm(ModelForm):
class Meta:
model = Post
fields = ("body", ..)
In view:
form1 = TopicForm()
form2 = PostForm()
In template:
<form ...>
{{ form1 }}
{{ form2 }}
</form>
You can easily use form.save() and all other functions, without doing it all yourself.