I have the following model
#models.py
class MyModel(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete = models.CASCADE,null=True)
link = models.URLField(max_length=2048)
date_added = models.DateTimeField(default = timezone.now)
used = models.BooleanField(default = True)
and my form
class MyModelForm(forms.ModelForm):
class Meta:
model = Wishlist
exclude = [
"user","date_added"
]
when I in my view try to "manually" create an instance (in the for-loop) and save it, the "user_id" in my database is NULL
#views.py
def AddLink(request):
user = request.user
instance = MyModel(user=user)
if request.method == "POST":
form = MyModelForm(request.POST,instance = instance)
if form.is_valid():
link = form.instance.wishlist
used = form.instance.discount_pct
#some util function to do some stuff
res = my_util_func(link,api_key)
for used, link in zip(res[0],res[1]):
data = {"link":link,"used":used}
form = MyModelForm(data=data)
form.save()
context = {
"results":res}
return render(request, "discounttracker/myhtml.html",context=context)
I have tried changing data to data = {"link":link,"used":used,"user":user} and data = {"link":link,"used":used,"user_id":user} but it is still empty.
How can I add the user here?
There is a secret option in ModelForm.save() called commit that allows you to not save the form right now, but instead return a model and insert some data into it. This should work perfectly here
form = MyModelForm(data=data))
instance = form.save(commit=False)
instance.user = request.user
instance.save()
This sample inserts the currently logged in user into the user field on your model.
Related
I have a model "TnaTemplateModel"
class TnaTemplateModel(models.Model):
id = models.UUIDField(primary_key = True,default=uuid.uuid4, editable=False)
template_name = models.ForeignKey(TemplateNameModel, verbose_name="template name", null=False,
blank=False, on_delete=models.CASCADE, help_text="Select the template")
process_name = models.ForeignKey(ProcessModel, verbose_name="process name", null=False,
blank=False, on_delete=models.CASCADE, help_text="Select the process")
sequence = models.IntegerField(verbose_name="Process Sequence",null = False,blank = False)
is_base = models.BooleanField()
dependent_process = models.CharField(verbose_name="Dependent Process",null=True, blank= True,max_length= 150)
formula = models.IntegerField(verbose_name="Formula", null= True,blank = True)
remarks = models.CharField(verbose_name="Process remarks", null= True, blank = True,max_length= 300)
class Meta:
unique_together = ["template_name", "process_name"]
def __str__(self):
return str(self.template_name)
I need to save entries from a form where dependent_process field will be a list of all processes in TNATemplateModel with the desired template_name and where is_base = True.
For this I have created 2 views and 2 forms 1 each for first saving all the entries with is_base = True and second for saving entries which will have a dependent_process as a dropdown from the previously added is_base = true processes. Note that the dropdown list should show processes with the same template_name where is_base = True.
Views.py
#for saving processes with is_base = true
def baseprocesscreatenew(request,pk):
template_name = TemplateNameModel.objects.get(id=pk)
data = {'template_name': template_name.id,'is_base': True}
dependent_list = TnaTemplateModel.objects.filter(template_name = template_name.id)
if request.method == 'POST':
form = BaseProcessModelformNew(request.POST,initial= data)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('templatepointslist_new',kwargs={'pk':pk}))
else:
form = BaseProcessModelformNew(initial= data)
print(form.errors)
return render (request,"tna/template_tna/baseprocessmodel_create.html",{'form':form,'dependent_list':dependent_list})
#for saving dependent processes
def dependentprocesscreatenew(request,pk):
template_name = TemplateNameModel.objects.get(id=pk)
data = {'template_name': template_name.id,'is_base': False}
dependent_list = TnaTemplateModel.objects.filter(template_name = template_name.id)
if request.method == 'POST':
form = DependentProcessModelformNew(request.POST,initial= data)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('templatepointslist_new',kwargs={'pk':pk}))
else:
form = DependentProcessModelformNew(initial= data)
print(form.errors)
return render (request,"tna/template_tna/dependentprocessmodelnew_create.html",{'form':form,'dependent_list':dependent_list})
** forms.py **
#form for saving base process
class BaseProcessModelformNew(forms.ModelForm):
class Meta:
model = TnaTemplateModel
fields =('__all__')
widgets = {'template_name': forms.HiddenInput(),'dependent_process:':forms.HiddenInput(),
'formula':forms.HiddenInput(),'is_base':forms.HiddenInput()}
#for Saving Dependent process
class DependentProcessModelformNew(forms.ModelForm):
class Meta():
model = TnaTemplateModel
fields =('__all__')
widgets = {'template_name': forms.HiddenInput(),
'is_base':forms.HiddenInput()}
def __init__(self,*args,**kwargs):
template_id= kwargs['initial']['template_name']
tna_template_name = TemplateNameModel.objects.get(id= template_id)
super (DependentProcessModelformNew,self ).__init__(*args,**kwargs)
dependent_obj_list = TnaTemplateModel.objects.filter(template_name = tna_template_name,is_base=True)
print("*************",dependent_obj_list)
def convert_queryset_tuple(obj):
dependent_list=[]
for a in obj:
dependent_list.append[a.process_name]
return tuple(dependent_list)
dependent_list = convert_queryset_tuple(dependent_obj_list)
self.fields['dependent_process'] = forms.ChoiceField(choices=dependent_list)
I have tried multiple approaches to this problem. I tried making a separate model for base and dependent process but since I have to calculate dates for dependent process which will depend on the dates entered in the base process , I wasn't able to figure out how can i do that with 2 different model.
After making one model for the base process I am unable to figure out :
How can I pass dependent list to html template and create the dropdown as I am using django form
If I am using ChoiceField I am not able to get the dynamic tuple out of the queryset and i believe ChoiceField cannot be create without a tuple
I have spent a lot of time trying to find the best way to achieve and I seeking to find the best approach to do this.
Say I have the following
#models.py
class MyModel(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete = models.CASCADE,null=True)
link = models.URLField(max_length=2048)
date_added = models.DateTimeField(default = timezone.now)
used = models.BooleanField(default = True)
and my form
class MyModelForm(forms.ModelForm):
class Meta:
model = Wishlist
exclude = [
"user","date_added"
]
If I try to create an instance like (note, I have omitted the if request.method="POST" etc. for clarity)
def myView(request):
user = request.user
instance = MyModel(user=user)
data = {"link":link,"date_added":domain,"user":user}
form = MyModelForm(data=data)
form.save()
the link and date_added is written to the database, but the user field is empty.
If I set the user to the instance after the form is created like
def myView(request):
user = request.user
instance = MyModel(user=user)
data = {"link":link,"date_added":domain}
form = MyModelForm(data=data)
form.save(commit=False)
form.instance.user = user #Setting the user here
form.save()
It works like a charm.
How come, I cannot set the user in the data-dict, and is there a way to do so?
How come, I cannot set the user in the data-dict.
A form will ignore all fields that it does not have to process. This makes the webserver more secure: here we ensure that the user can not create a MyModel for another user.
If thus a field belongs to the excluded attribute, or not in the fields attribute from the Meta class, then the form will not set the corresponding model object attribute.
You did not specify the instance to the form:
def myView(request):
user = request.user
instance = MyModel(user=user)
data = {"link":link,"date_added":domain}
form = MyModelForm(data=data, instance=instance)
form.save()
I am trying to perform crud operations but when i try to update then django add's a new row in the db with the new pk 'id'. I am using autofield set to primary_key = True(default).
#login_required
def edit(request,id):
note = UserCreatedNote.objects.filter(pk=id,user=request.user)
if request.method == 'POST':
form = AddNoteForm(request.POST,note[0])
if form.is_valid():
form_data = form.save(commit=False)
form_data.user = request.user //cause i have excluded this field in form.
form_data.save()
form = AddNoteForm(instance=note[0])
context={'note':note[0],'u_form':form}
return render(request,'edit_note.html',context)
Models.py
class UserCreatedNote(models.Model):
user = models.ForeignKey(get_user_model(),on_delete=models.CASCADE)
note_title = models.CharField(default='',max_length=100,blank=True,null=True)
note_tags = models.CharField(default='',max_length=20,blank=True,null=True)
note_contents = RichTextField(default='',max_length=1000,blank=True,null=True)
creation_time = models.DateTimeField(auto_now_add=True)
last_modified_time = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['creation_time',]
def __str__(self):
return str(self.user)
You have to pass the note object as an instance to update.
form = AddNoteForm(request.POST,instance=note[0])
I'm pretty new to django and working on a blog based project where user can add ratings to specific type of review post.For example giving stars are enabled for restaurant but not for tech stores.
I have created two different form for "review" and "star" model. I want to rate the restaurant using the model named "star" and do it in same template.But I'm having difficulties to do that.
Im getting this error.
"The above exception (NOT NULL constraint failed: reviews_star.post_id_id) was the direct cause of the following exception:"
How do I get the review id that I just save with "review_form.save()".
my review model kinda looks like this (Removed other attributes which aren't related to this problem):
class Review(models.Model):
review_title = models.CharField(verbose_name='Title', max_length=100)
review_body = models.TextField()
author = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE)
restaurant_or_techstore = models.CharField(verbose_name='Foods or Travel',max_length=20)
slug = models.SlugField(null=False,unique=True,max_length = 300)
My rating model looks like this:
class Star(models.Model):
post_id = models.ForeignKey(Review, on_delete = models.CASCADE )
food = models.FloatField(verbose_name='Food',null=False)
service = models.FloatField(verbose_name='Food',null=False)
cleanliness = models.FloatField(verbose_name='Food',null=False)
and my view :
def CreateReview(request):
ImageFormSet = modelformset_factory(Image,form=ImageForm,extra=5)
if request.method == 'POST':
reviewForm = ReviewForm(request.POST)
formset = ImageFormSet(request.POST,request.FILES,queryset=Image.objects.none())
starsForm = StarsrForm(request.POST)
if reviewForm.is_valid() and formset.is_valid() and starsForm.is_valid():
review_form = reviewForm.save(commit=False)
review_form.author = request.user
review_form.post_or_discussion = 1
review_form.food_or_travel = 'Foods'
review_form.save()
reviewForm.save_m2m()
starsForm.save()
for form in formset.cleaned_data:
if form:
image = form['image']
photo = Image(review=review_form,image=image)
photo.save()
messages.success(request,'Image Uploaded Successfully')
return HttpResponseRedirect("/")
else:
print(reviewForm.errors, formset.errors)
else:
reviewForm = ReviewForm()
starsForm = StarsrForm()
formset = ImageFormSet(queryset=Image.objects.none())
return render(request,'reviews/review_form.html',{'reviewForm':reviewForm,'formset':formset,'starsForm':starsForm})
best try when you use ForeighKey is to use related_name attr for this field
class Star(models.Model):
post = models.ForeignKey(Review, related_name='post_review', on_delete = models.CASCADE )
after it you can refer to star from review by some_object_review.post_review.some_field_star
For you error above try reviews_star.post_id.id
Solve The problem.All I had to do is pass the review_form instance to the star form.
new view is:
if request.method == 'POST':
reviewForm = ReviewForm(request.POST)
formset = ImageFormSet(request.POST,request.FILES,queryset=Image.objects.none())
starsForm = StarsrForm(request.POST)
if reviewForm.is_valid() and formset.is_valid() and starsForm.is_valid():
review_form = reviewForm.save(commit=False)
review_form.author = request.user
review_form.post_or_discussion = 1
review_form.food_or_travel = 'Foods'
review_form.save()
reviewForm.save_m2m()
instance = review_form
print(instance.id)
star_form = starsForm.save(commit=False)
star_form.post_id = instance
star_form.save()
for form in formset.cleaned_data:
if form:
image = form['image']
photo = Image(review=review_form,image=image)
photo.save()
messages.success(request,'Image Uploaded Successfully')
return HttpResponseRedirect("/")
else:
print(reviewForm.errors, formset.errors)
else:
reviewForm = ReviewForm()
starsForm = StarsrForm()
formset = ImageFormSet(queryset=Image.objects.none())
return render(request,'reviews/review_form.html',{'reviewForm':reviewForm,'formset':formset,'starsForm':starsForm})
I haven't got much experience with building custom forms (only default model forms) and I'm looking for some help here. I'm trying to build a form that will get "feed_url" from user and if it already exist, just add reference into UserFeed model. In case it doesn't exist, it should add it to the Feed model and also reference it in UserFeed model as well.
models
class Category(models.Model):
name = models.CharField(unique=False, max_length=64)
user = models.ForeignKey(User)
slug = AutoSlugField(populate_from='name', always_update='True', unique_with='user')
def __unicode__(self):
return self.name
class Meta:
ordering = ('name',)
class Feed(models.Model):
feed_url = models.URLField(unique=True)
def __unicode__(self):
return self.feed_url
class UserFeed(models.Model):
feed = models.ForeignKey(Feed)
title = models.CharField(max_length=64)
category = models.ForeignKey(Category)
user = models.ForeignKey(User)
slug = AutoSlugField(populate_from='title', always_update='True', unique_with='user')
def __unicode__(self):
return self.title
class Meta:
ordering = ('title',)
forms
class UserFeedForm(forms.Form):
feed_url = forms.URLField()
title = forms.CharField(max_length=64)
category = forms.ModelChoiceField(Category)
user = forms.HiddenInput()
views
def addfeed(request):
categories = Category.objects.filter(user=request.user)
feeds = Feed.objects.all()
if request.method == 'POST':
form = UserFeedForm(request.POST)
form.fields['category'].queryset = categories
if form.is_valid():
feed = form.save(commit=False)
if form.fields['feed_url'] in feeds:
##### add to Feed object and add reference to UserFeed object
feed.user = request.user
feed.save()
else:
##### get id from Feed object and add reference to UserFeed object
feed.user = request.user
feed.save()
return HttpResponseRedirect("/reader/manage")
else:
form = UserFeedForm()
form.fields['category'].queryset = categories
context = {'form': form,}
return expand_context_and_render(request, context, 'reader/form.html')
Could anybody please point me in the right direction?
thanks
UPDATE
Now I have updated my view and form as follows:
forms
class UserFeedForm(forms.ModelForm):
feed = forms.URLField()
title = forms.CharField(max_length=64)
category = forms.ModelChoiceField(Category)
user = forms.HiddenInput()
class Meta:
model = UserFeed
fields = ['feed', 'title', 'category']
views
def addfeed(request):
categories = Category.objects.filter(user=request.user)
feeds = Feed.objects.all()
if request.method == 'POST':
form = UserFeedForm(request.POST)
form.fields['category'].queryset = categories
if form.is_valid():
feed = form.cleaned_data.get('feed')
if feed in feeds:
##### get id from Feed and add reference to UserFeed
existing_feed = Feed.objects.get(feed_url=feed)
form.feed = existing_feed.id
form.user = request.user
form.save(commit=True)
else:
##### add to Feed object and then add reference to UserFeed object
Feed.object.create(feed_url=feed)
existing_feed = Feed.objects.get(feed_url=feed)
form.feed = existing_feed.id
form.user = request.user
form.save(commit=True)
return HttpResponseRedirect("/reader/manage")
else:
form = UserFeedForm()
form.fields['category'].queryset = categories
context = {'page_title': page_title,
'form': form,
}
return expand_context_and_render(request, context, 'reader/form.html')
I think I'm getting closer but it still won't work, giving me this error:
"Cannot assign "u'http://feeds.bbci.co.uk/news/rss.xml'": "UserFeed.feed" must be a "Feed" instance."
Any idea how can I fix this?
thanks
Try taking a look at this question, and also inline formsets in the docs.
Additionally in your UserFieldForm, feed is defined as a URLField. So in your view, in this line:
feed = form.get_cleaned_data.get('feed')
your feed variable is simply a string, and not actually a Feed object. This is where your error might be occurring? That's where inline formsets could help you. Also, this line also makes your your if feed in feeds: statement moot, because feed is just a string, whereas feeds is a Queryset of all your Feed instances. I think this will cause your view to always end up in the else block?
I'm new to Django myself but I hope this helps you.
The logic you are looking for is:
Check if the feed exists.
If it exists, fetch it.
If it doesn't create a new feed.
Associate the feed with a UserFeed object.
The get_or_create method does parts 1-3, so you need the following:
if form.is_valid():
obj = form.save(commit=False)
feed = form.cleaned_data.get('feed')
feed_obj, created = Feed.objects.get_or_create(feed_url=feed)
obj.feed = feed_obj
obj.save()
return HttpResponseRedirect("/reader/manage")
I finally got it working like this:
forms
class UserFeedForm(forms.Form):
feed = forms.URLField()
title = forms.CharField(max_length=64)
category = forms.ModelChoiceField(Category)
user = forms.HiddenInput()
class Meta:
model = UserFeed
fields = ['feed', 'title', 'category']
views
def addfeed(request):
user = request.user
categories = Category.objects.filter(user=request.user)
if request.method == 'POST':
form = UserFeedForm(request.POST)
form.fields['category'].queryset = categories
if form.is_valid():
feed = form.cleaned_data['feed']
category = form.cleaned_data['category']
title = form.cleaned_data['title']
feed_obj, created = Feed.objects.get_or_create(feed_url=feed)
obj = UserFeed(feed=feed_obj, title=title, category=category, user=user)
obj.save()
return HttpResponseRedirect("/reader/manage")
else:
form = UserFeedForm()
form.fields['category'].queryset = categories
context = {'page_title': page_title,
'form': form,
}
return expand_context_and_render(request, context, 'reader/form.html')
Both tips from the answers below pointed me in the right direction. Thanks !