I'm new to Django and have a Q&A project. For each question you may have multiple tags which already exist or put new ones. The new tags should be created before the question is saved. How do I solve this properly? So far I have:
def question_add(request):
# redirect user to login page if not authenticated
if not request.user.is_authenticated():
return render(request, 'account/login.html')
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = QuestionForm(request.POST)
if form.is_valid():
# process the data in form.cleaned_data as required
instance = form.save(commit=False)
instance.created_by = request.user
instance.save()
messages.success(request, 'Question added with success.')
# redirect to the main page:
return HttpResponseRedirect('/')
else:
messages.warning(request, 'Please correct the errors.')
# if a GET (or any other method) we'll create a blank form
else:
form = QuestionForm()
return render(request, 'question/add.html', {'form': form})
This should be done prior form.is_valid() or does it exist a magic method for doing this?
I am assuming tag is ManyToMany field for Question model.
Inside form.is_valid() to add manyToMany field data.
if form.is_valid():
instance = form.save(commit=False)
instance.created_by = request.user
instance.save()
# returns the list of tag names
tags = request.POST.get('tags')
for tag in tags:
# create if tag not found with given name or return existing tag
obj, created = Tag.objects.get_or_create(name=tag)
instance.tags.add(obj)
If the Tag is ForiegnKey:
if form.is_valid():
instance = form.save(commit=False)
instance.created_by = request.user
tag_name = request.POST.get('tag')
obj, created = Tag.objects.get_or_create(name=tag_name)
instance.tag = obj.id
instance.save()
Related
I already have seen this bug in other post, but still in trouble.
I'm trying to create a social network like instagram where users will be able to publish posts (photos).
I have User class which herit from AbstractUser, and got a OneToMany field of posts: each user can publish many posts.
After successfully pulling my photo from: PostForm(request.POST, request.FILES) and saving it correctly, I cannot add this photo to the current user's publications/posts and got error:
'NoneType' object has no attribute 'add'
def blog_and_photo_upload(request):
form = PostForm()
if request.method == 'POST':
form = PostForm(request.POST, request.FILES)
if form.is_valid():
user = get_user(request) # user instance is correct with good pk
post = Post.objects.create(image=form.cleaned_data['image']) # post instance looks correct also
post.save()
user.save()
user.posts.add(post) # row doesnt work
redirect('home')
return render(request, 'base/upload_post.html', {'form': form})
models.py
class Post(models.Model):
...
image = ResizedImageField(size=[300, 300], blank=True, upload_to='posts')
class User(AbstractUser):
...
posts = models.ForeignKey(Post, on_delete=models.Cascade, null=True)
You can simply update the form like this:
post = Post.objects.create(image=form.cleaned_data['image']) # post instance looks correct also
post.save()
user.posts = post
user.save()
return redirect('home')
But, I think the design of the model is wrong, User to Post relation should be like this:
Class User(...):
posts = models.ManyToManyField(Post)
In that way, your original implementation should work. (Probably you don't need user.save() call in your view).
At first there should be return redirect(...) not only redirect() and secondly try to use the following view:
def blog_and_photo_upload(request):
form = PostForm()
if request.method == 'POST':
form = PostForm(request.POST, request.FILES)
if form.is_valid():
user = get_user(request) # user instance is correct with good pk
post = Post.objects.create(image=form.cleaned_data['image']) # post instance looks correct also
post.save()
user.posts.add(post) # add post to user's posts field
user.save()
return redirect('home')
return render(request, 'base/upload_post.html', {'form': form})
You need to bind first Post with User model like add a ForeignKey or a ManyToManyFields to relate them
posts = models.ForeignKey(User)
then you will be able to call it like you did
user.posts # this won't return None
Check this many to many field docs: https://docs.djangoproject.com/en/4.1/topics/db/examples/many_to_many/
What I'm trying to do?
I want to display 2 registration forms separately of each other on the same page. The forms are: built-in User model and my self created UserProfile. To track, on what form user is now, I use sessions. It some sort of flags for me at the moment.
Why I don't want to use sessions?
I discovered a 'bug', at least for me, that I don't know how to fix. Bug appears if user passed first registration form, and close browser/tab. Next time user opens registration page, it will show second registration form, instead of first, as expected.
Where bug happens, but now with code.
When user opens register page first time, built-in UserCreationForm will be show, because there is no session called username yet.
def get(self, request):
if request.session.get("username", None):
self.context["form"] = RegisterProfile()
else:
self.context["form"] = UserCreationForm()
I'm using CBV, so it's OK that function called get and first argument is self. Also I created context dictionary as instance variable, so I can just add new field form to it.
Next, if user fill in given form (note, that first form is built-in User's form) built-in User instance will be created and it's username will be stored in username session.
If you confused at the moment don't worry much, I leave full view code at the bottom.
form = UserCreationForm(request.POST)
if form.is_valid():
form.save()
request.session["username"] = request.POST["username"]
return redirect("register")
Now, when session username exsists, and user redirected to same view, my self-created form will be shown. As in first code example.
Now, bug happens. User can freely leave page, and when he come back, second registration form will be shown again. That's not what I want.
Full view code:
class Register(View):
context = {"title": "Register new account"}
def get(self, request):
if request.session.get("username", None):
self.context["form"] = RegisterProfile()
else:
self.context["form"] = UserCreationForm()
return render(request, "users/register.html", context=self.context)
def post(self, request):
if request.session.get("username", None):
form = RegisterProfile(request.POST, request.FILES)
if form.is_valid():
username = request.session.get("username", None)
if not username:
messages.error(request, "We are sorry, but error happend. Try again!")
return redirect("index")
user = User.objects.filter(username=username).first()
profile = UserProfile(
user=user,
nickname=request.POST["nickname"],
sex=request.POST["sex"],
age=request.POST["age"],
profile_picture=form.files["profile_picture"],
)
profile.save()
del request.session["username"]
messages.success(request, "Profile created successfully!")
return redirect("index")
else:
form = UserCreationForm(request.POST)
if form.is_valid():
form.save()
request.session["username"] = request.POST["username"]
return redirect("register")
self.context["form"] = form
return render(request, "users/register.html", context=self.context)
UPD 1:
I changed register logic a little, now full code looks like this:
class Register(View):
context = {"title": "Register user page"}
def get(self, request):
if request.session.get("user_data", None):
form = ProfileRegisterForm()
else:
form = UserCreationForm()
self.context["form"] = form
return render(request, "users/register.html", context=self.context)
def post(self, request):
if request.session.get("user_data", None):
form = ProfileRegisterForm(request.POST, request.FILES)
if form.is_valid():
user = User.objects.create_user(*request.session["user_data"])
user.save()
UserProfile.objects.create(
user=user,
nickname=request.POST["nickname"],
sex=request.POST["sex"],
age=request.POST["age"],
profile_picture=form.files["profile_picture"],
)
del request.session["user_data"]
messages.success(request, "Profile created successfully!")
return redirect("index")
else:
form = UserCreationForm(request.POST)
if form.is_valid():
request.session["user_data"] = [
request.POST["username"],
request.POST["password1"],
request.POST["password2"]
]
return redirect("register")
self.context["form"] = form
return redirect("register")
But anyway, I need place to store temporary data like username, password1 and password2. If someone knows, where I can store data like in sessions, please, answer bellow.
When i try to upload file it gives me template error, that its required to fill in. Code:
models:
class ahoja(models.Model):
image = models.ImageField(upload_to='smayat')
forms:
class ahojaForm(ModelForm):
class Meta:
model = ahoja
exclude = ()
view:
def testview(request):
if request.method == 'POST': # pokud form byl odeslan
form = ahojaForm(request.POST, request.FILES) # formular s daty
if form.is_valid():
form.save() #vytvoří událost
return HttpResponseRedirect('/hlavni_stranka/kalendar/')
else:
form = ahojaForm() # prázdný formulář
return render(request, 'hlavni_stranka/test.html', {'form': form,})
The first thing to check is the enctype attribute in your template. From the docs:
Note that request.FILES will only contain data if the request method was POST and the <form> that posted the request has the attribute enctype="multipart/form-data". Otherwise, request.FILES will be empty.
I have a Django form where I'm trying to save user profile details. My UserProfile has a many to many field, which I'm having trouble saving. Here is my attempted view code:
#login_required
def updateProfile(request, uid):
import pdb; pdb.set_trace()
"""
First, grab the existing user data out of the db.
If it's not there, we'll create it, then fill in the blanks from user input on post.
"""
requested_user = get_object_or_404(User, pk=uid)
user_profile = None
try:
user_profile = UserProfile.objects.get(user = requested_user)
except UserProfile.DoesNotExist:
default_skill_level = SkillLevel.objects.all()[0] # default value.
user_profile = UserProfile(user = requested_user, skill_level = default_skill_level)
user_profile.save()
if request.method == 'POST':
form = UserProfileForm(request.POST, instance = user_profile)
if form.is_valid() and (request.user.id == uid or request.user.is_superuser):
obj = form.save(commit=False) # get just the object but don't commit it yet.
obj.save() # finally save it.
obj.save_m2m() # this is failing. UserProfile has no attribute save_m2m
return index(request)
else:
print "Not authorized to do that! Implement real authorization someday."
return index(request)
else:
profile_form = UserProfileForm(instance=user_profile)
context = {
'user' : request.user,
'form' : profile_form
}
return render(request, 'booker/profile.html', context)
On a POST, once the form is validated I'm able to save the basic object but afterwards saving the many to many fields fails with the given exception. What is the right way to go about this?
Example:
...
if formset.is_valid():
items = formset.save(commit=False)
for item in items:
item.save()
formset.save_m2m()
E:
Try this:
if form.is_valid() and (request.user.id == uid or request.user.is_superuser):
obj = form.save(commit=False) # get just the object but don't commit it yet.
obj.save() # finally save it.
form.save_m2m()
The save_m2m() is only required if you have previously saved with commit=False. In your example the commit=False save does not appear to be necessary.
E.g. you could replace
obj = form.save(commit=False) # get just the object but don't commit it yet.
obj.save() # finally save it.
obj.save_m2m() # this is failing. UserProfile has no attribute save_m2m
With:
form.save()
I am trying to update my user account info through a form. I have the form ok which just displays a password/email field and cleans the email field. I am having a problem with my views. This is the error I get: Manager isn't accessible via User instances.
This is my views: my_account function.
def my_account(request):
user = request.user
if request.method == 'POST':
form = MyAccountForm(request.POST)
if form.is_valid():
user = user.objects.get(username=username),
password = user.set_password('password2'),
email = forms.cleaned_data['email']
user.save()
return HttpResponseRedirect('/')
else:
form = MyAccountForm()
variables = RequestContext(request, {
'form': form,
})
return render_to_response(
'my_account.html',
variables
)
where you have
user.objects.get
you want
User.objects.get
objects is the manager referred to in the error message, and user is the instance referred to (an instance of User, the actual class)