i have a method where i am saving the data from users, but each user has to have a single profile, so each time he saves, the data should be overwritten.
first i verify if he already has a profile data, and in this case i add an instance to the form. if not, (this is his first registration), i simply add data into DB
my code is:
but i get an error:'QuerySet' object has no attribute '_meta'
is my method right? thanks!
def save_userprofile(request):
if request.method == 'POST':
u = UserProfile.objects.filter(created_by = request.user)
if u:
form = UserProfileForm(request.POST, request.FILES,instance=u )
else:
form = UserProfileForm(request.POST, request.FILES)
If you're expecting just one object back from a query, you should use the get() method.
from django.core.exceptions import ObjectDoesNotExist
try:
u = UserProfile.objects.get(created_by = request.user)
# can update here
except ObjectDoesNotExist:
# create object
The queryset reference should explain all. You may also find get_or_create() is useful.
The instance argument of UserProfileForm doesn't expect to receive a QuerySet, which is what you're giving it. To retrive the profile, you should use this, which returns a single UserProfile object:
u = UserProfile.objects.get(created_by = request.user)
Related
I am saving a from and updating another model in the form, but the update is not saved to database.
if request.method == 'POST':
form = InventoryTransactionForm(request.POST, instance=InventoryTransaction())
if form.is_valid():
quantity = request.POST['quantity']
part_id = request.POST['part_id']
item_template_id = request.POST['supply']
try:
item_object = Item.objects.get(pk=part_id)
masterQty = item_object.masterQty - int(quantity)
item_object.save(force_update=True)
except Exception, e:
messages.error(request, e.message)
can anybody please help what is wrong in above code, thanks.
EDIT: updated code as below
#transaction.commit_manually
def post(self, request, *args, **kwargs):
if request.method == 'POST':
form = InventoryTransactionForm(request.POST, instance=InventoryTransaction())
if form.is_valid():
quantity = request.POST['quantity']
part_id = request.POST['part_id']
item_template_id = request.POST['supply']
try:
item_object = Item.objects.get(pk=part_id)
masterQty = item_object.masterQty - int(quantity)
item_object.save(force_update=True)
transaction.commit()
except Exception, e:
transaction.rollback()
messages.error(request, e.message)
form.save(True)
You are using force_update=True in the save method. From the docs:
In some rare circumstances, it’s necessary to be able to force the save() method to perform an SQL INSERT and not fall back to doing an UPDATE. Or vice-versa: update, if possible, but not insert a new row. In these cases you can pass the force_insert=True or force_update=True parameters to the save() method. Obviously, passing both parameters is an error: you cannot both insert and update at the same time!
You are saving the object to the database for the first time so it doesn't make sense to call force_update=True as it will prevent the object from being created in the first place. So change
item_object.save(force_update=True)
to
item_object.save()
I think your problem is about working with django ORM here.
You get your object from the database here : item_object = Item.objects.get(pk=part_id) but you lose the instance of this object when doing item_object = Item(masterQty=masterQty, item_template_id=item_template_id, id=part_id).
That's why you think you need a force update but you actually just need to keep the right instance of your object.
Why don't you just update the fields on the object you got from the db and then save it ?
Like so :
item_object = Item.objects.get(pk=part_id)
item_object.masterQty -= int(quantity)
item_object.item_template_id = item_template_id
item_object.save()
You don't even need a force update as you'll be working on an instance you got from the db.
Say I have a form that looks like this:
forms.py
class CreateASomethingForm(ModelForm):
class Meta:
model = Something
fields = ['field2', 'field3', 'field4']
I want the form to have these three fields. However my Somethingclass also has field1. My question is - how do I add data to field1, if I am not using the ModelForm to collect the data. I tried doing something like this, but it isn't working and I am unsure on the proper way to solve this:
views.py
def create_something_view(request):
if (request.method == 'POST'):
# Create an object of the form based on POST data
obj = CreateASomething(request.POST)
# ** Add data into the blank field1 ** (Throwing an error)
obj['field1'] = request.user
# ... validate, save, then redirect
The error I receive is:
TypeError: 'CreateAClassForm' object does not support item assignment
In Django, what is the proper way to assign data to a ModelForm object before saving?
form = CreateASomething(request.POST)
if form.is_valid():
obj = form.save(commit=False)
obj.field1 = request.user
obj.save()
Sometimes, the field might be required which means you can't make it past form.is_valid(). In that case, you can pass a dict object containing all fields to the form.
if request.method == 'POST':
data = {
'fields1': request.user,
'fields2': additional_data,
}
form = CreateASomethingForm(data)
if form.is_valid():
form.commit(save)
There are two ways given by Django official
LINK : https://docs.djangoproject.com/en/3.0/topics/forms/modelforms/
Method 1]
author = Author(title='Mr')
form = PartialAuthorForm(request.POST, instance=author)
form.save()
Method 2]
form = PartialAuthorForm(request.POST)
author = form.save(commit=False)
author.title = 'Mr'
author.save()
Here is a more suitable way to add data especially used during testing:
First convert an existing entry into a dictionary with the model_to_dict function
from django.forms.models import model_to_dict
...
valid_data = model_to_dict(entry)
Then add the new data into this dictionary
valid_data['finish_time'] = '18:44'
This works better than setting the value in the form
update_form.finish_time = '18:44'
Create the form with the valid data and the instance
update_form = UserEntryForm(valid_data, instance=entry)
Do any assertions you require:
self.assertTrue(update_form.is_valid())
entry = update_form.save()
self.assertEqual(
entry.status,
1
)
I got, following Error messages,
TypeError at /save/ int() argument must be a string or a number, not
'SimpleLazyObject'
While executing following form.
views.py
def bookmark_save_page(request):
if request.method == 'POST':
form = BookmarkSaveForm(request.POST)
if form.is_valid():
# create or get link
link, dummy = Link.objects.get_or_create(
url = form.cleaned_data['url']
)
# create or get bookmark
bookmark, created = Bookmark.objects.get_or_create(
user=request.user,
link=link
)
# update bookmarks title
bookmarks.title = form.cleaned_data['title']
# if the bookmark is being updated, clear old tag list.
if not created:
bookmark.tag_set.clear()
# create new tag list
tag_names = form.cleaned_data['tags'].split()
for tag_name in tag_names:
tag, dummy = Tag.objects.get_or_create(name=tag_name)
bookmark.tag_set.add(tag)
# save bookmark to database.
bookmark.save()
return HttpResponseRedirect(
'/user/%s/' % request.user.username
)
else:
form = BookmarkSaveForm()
variables = RequestContext(request, {
'form': form
})
return render_to_response('bookmark_save.html', variables)
I thought I got error because I passed link at
bookmark, created = Bookmark.objects.get_or_create(
user=request.user,
link=link
)
But I can not figure out how to fix it.
How can I fix it?
The likely cause is that you're setting user = request.user, where request.user is not a real User object, but a SimpleLazyObject instance. See django: Purpose of django.utils.functional.SimpleLazyObject? for more details, but using request.user.id should fix your issue.
You have to login when running this piece of code on localhost. Otherwise the request.user will be a SimpleLazyObject, then the errors comes out.
Here you trying to create a Bookmark object based on request.user , but request.user is a SimpleLazyObject , so we can get a more secure user object by :
from django.contrib import auth
current_user = auth.get_user(request)
and further your query should be
bookmark, created = Bookmark.objects.get_or_create(
user=current_user,
link=link
)
Most likely the user who is loading the page is not authenticated. Therefor the error is thrown. If you want to save a request.user reference to the database, you obviously have to ensure that only authenticated users are able to call the function.
In your case there are two possibilities - add the "#login_required" decorator to the function or check if the user is authenticated inside the code. Here are the snippets:
With Decorator:
from django.contrib.auth.decorators import login_required
#login_required
def bookmark_save_page(request):
if request.method == 'POST':
form = BookmarkSaveForm(request.POST)
if form.is_valid():
# Do something
OR - checking inside the code if the user is authenticated:
def bookmark_save_page(request):
if request.method == 'POST' and request.user.is_authenticated():
form = BookmarkSaveForm(request.POST)
if form.is_valid():
# Do something
Thats strange, I had the same problem and the same solution. After trying a bunch of alternatives I went back to user = request.user and it worked
if you want to set an addition request attr, based on user -> you need to use lazy Django function which is correctly handled by Field.get_prep_value
from django.utils.functional import lazy
request.impersonator = lazy(lambda: request.user.id, int)()
I'm creating a form in one page, then in another page I'm trying to pull out the form (populated with the data saved in it already) and would like to make changes to it so that when I save it it overwrites the instance instead of creating another one.
def edit(request):
a = request.session.get('a', None)
if a is None:
raise Http404('a was not found')
if request.method == 'POST':
form = Name_Form(request.POST, instance=a)
if form.is_valid():
j = form.save( commit=False )
j.save()
else:
form = Name_Form( instance = a )
This is the code I have for the "editting form" view.. When I open this page the form is successfully prepopulated with all the data. However, when I make changes and save, it does not overwrite the existing instance, instead it creates a new one.
Any ideas?
Have a look here: https://docs.djangoproject.com/en/dev/ref/models/instances/#how-django-knows-to-update-vs-insert
I think this may help you.
Update:
What about trying a more "explicit" way.
Assume, id_of_Name stores only the id or pk of your model which you want to edit (I assume the model is called "Name"). Then just retrieve the id/pk from session to query your db for the model instance. Also try to directly call the save method on the form.
def edit(request):
id_of_Name = request.session.get('a', None)
if id_of_Name is None:
raise Http404('id_of_Name was not found')
instance = Name.objects.get(pk=id_of_Name)
if request.method == 'POST':
form = Name_Form(request.POST, instance=instance)
if form.is_valid():
form.save()
else:
form = Name_Form( instance = instance )
I am using Django ModelForms to create a form. I have my form set up and it is working ok.
form = MyForm(data=request.POST)
if form.is_valid():
form.save()
What I now want though is for the form to check first to see if an identical record exists. If it does I want it to get the id of that object and if not I want it to insert it into the database and then give me the id of that object. Is this possible using something like:
form.get_or_create(data=request.POST)
I know I could do
form = MyForm(instance=object)
when creating the form but this would not work as I still want to have the case where there is no instance of an object
edit:
Say my model is
class Book(models.Model):
name = models.CharField(max_length=50)
author = models.CharField(max_length=50)
price = models.CharField(max_length=50)
I want a form which someone can fill in to store books. However if there is already a book in the db which has the same name, author and price I obviously don't want this record adding again so just want to find out its id and not add it.
I know there is a function in Django; get_or_create which does this but is there something similar for forms? or would I have to do something like
if form.is_valid():
f = form.save(commit=false)
id = get_or_create(name=f.name, author=f.author, price=f.price)
Thanks
I like this approach:
if request.method == 'POST':
form = MyForm(request.POST)
if form.is_valid():
book, created = Book.objects.get_or_create(**form.cleaned_data)
That way you get to take advantage of all the functionality of model forms (except .save()) and the get_or_create shortcut.
You just need two cases in the view before the postback has occurred, something like
if id:
form = MyForm(instance=obj)
else
form = MyForm()
then you can call form.save() in the postback and Django will take care of the rest.
What do you mean by "if an identical record exists"? If this is a simple ID check, then your view code would look something like this:
if request.method == 'POST':
form = MyForm(request.POST)
if form.is_valid():
form.save()
else:
if get_id:
obj = MyModel.objects.get(id=get_id)
form = MyForm(instance=obj)
else:
form = MyForm()
The concept here is the check occurs on the GET request, such that on the POST to save, Django will already have determined if this is a new or existing record.
If your check for an identical record is more complex, it might require shifting the logic around a bit.
I would do this -
if request.method == 'POST':
form = MyForm(request.POST)
if form.is_valid():
name = form.cleaned_data['name']
author = form.cleaned_data['author']
price = form.cleaned_data['prince']
if name and author and price:
book, created = Book.objects.get_or_create(name=name, \
author=author, price=price)
if created:
# fresh entry in db.
else:
# already there, maybe update?
book.save()
Based on the answers and comments, I had to create a different solution for my case, which included the use of unique_together on the base model. You may find this code useful as well, as I actually made it fairly generic.
I have custom code in the form.save() method that I want to utilize for creating a new object, so I don't want to simply not use the form.save() call. I do have to put my code check in the form.save() method, which I think is a reasonable place to put it.
I have a utility function to flatten iterables.
def flatten(l, a=list()):
"""
Flattens a list. Just do flatten(l).
Disregard the a since it is used in recursive calls.
"""
for i in l:
if isinstance(i, Iterable):
flatten_layout(i, a)
else:
a.append(i)
return a
In the ModelForm, I overwrite the validate_unique() method:
def validate_unique(self):
pass
This is about what my save method looks like:
def save(self, commit=True):
unique_fields = flatten(MyObject._meta.unique_together)
unique_cleaned_data = {k: v for k, v in self.cleaned_data.items() if k in unique_fields}
# check if the object exists in the database based on unique data
try:
my_object = MyObject.objects.get(**unique_cleaned_data)
except MyObject.DoesNotExist:
my_object = super(MyModelFormAjax, self).save(commit)
# -- insert extra code for saving a new object here ---
else:
for data, value in self.cleaned_data.items():
if data not in unique_fields:
# only update the field if it has data; otherwise, retain
# the old value; you may want to comment or remove this
# next line
if value:
setattr(my_object, data, value)
if commit:
my_object.save()
return my_object