This is probably very simple and basic but I'm struggling with grabbing a newly-created object in Django. It is for a basic library-style app. Over in models, I do this to create a Book object:
def add_book(self, postData, user_id):
title = postData['title']
first_name = postData['first_name']
last_name = postData['last_name']
user_obj = User.objects.get(id=user_id)
if not Author.objects.filter(first_name=first_name, last_name=last_name).exists():
author_obj = Author.objects.create(first_name=first_name, last_name=last_name)
else:
author_obj = Author.objects.get(first_name=first_name, last_name=last_name)
return self.create(title=postData['title'], created_by=user_obj, author=author_obj)
Then in views, I call that method and wish to redirect to a page specifically for that newly-created object. I think you can see that I have most of the code down, but don't know what to put in place of the "????".
def books_add(request):
if request.method == "POST":
errors = Book.objects.book_validation(request.POST)
if not errors:
Book.objects.add_book(request.POST, request.session['uid'])
book_id = Book.objects.get(????).id
return redirect('/books/book/{}/'.format(book_id))
else:
context = {
'errors' : errors,
}
1st part use get_or_create for retrieve or create a model entry
def add_book(self, postData, user_id):
title = postData['title']
first_name = postData['first_name']
last_name = postData['last_name']
user_obj = User.objects.get(id=user_id)
author_obj, created = Author.objects.get_or_create(first_name=first_name, last_name=last_name)
return self.create(title=postData['title'], created_by=user_obj, author=author_obj)
2nd part, return self.create return a Book entity :
def books_add(request):
if request.method == "POST":
errors = Book.objects.book_validation(request.POST)
if not errors:
book = Book.objects.add_book(request.POST, request.session['uid'])
return redirect('/books/book/{}/'.format(book.id))
else:
context = {
'errors' : errors,
}
There are some issues here. At the very least, look at Django Forms before you go much further. This is what a view that creates an object could look like:
def add_book(request):
if request.POST:
author, created = Author.objects.get_or_create(first_name=first_name,
last_name=last_name)
book = Book(title = request.POST['title'],
user_obj = request.GET['user'],
author = author,)
book.save()
return redirect('/books/book/{}/'.format(book.id))
else:
return render(request, 'book_form.html')
You really need to look into ModelForms to handle your POSTs. But start with looking at Forms.
Related
I have the below two models
# models.py
class Applicant(models.Model):
"""
A table to store all applicants, relates 1-n to an offer
"""
name = models.CharField(max_length=50)
job = models.CharField(max_length=50)
start = models.DateField(null=True, blank=True)
def __str__(self):
return f'{self.name} applying for {self.job} starting {self.start}'
class Offer(models.Model):
"""
A table to store created offers
"""
# Relations
applicant = models.ForeignKey(Applicant, on_delete=models.CASCADE)
# Self
monthly_raise = models.FloatField()
months = models.PositiveIntegerField(validators=[MinValueValidator(1), MaxValueValidator(60)])
start_salary = models.FloatField()
In my template I render all fields except for start (which I don't render at all) in the same <form></form> wrapper. Now in my view I want to create new instances for each of the modelforms but only if both are valid.
This is what I have which throws
NOT NULL constraint failed: planner_offer.applicant_id
def render_dashboard_planner(request):
site = 'planner'
if request.method == 'GET':
applicant_form = ApplicantForm()
offer_form = OfferForm()
context = {
'applicant_form': applicant_form,
'offer_form': offer_form,
'site': site
}
return render(request, "dashboard/dashboard_planner.html", context)
else:
# Process the created Offer
applicant_form = ApplicantForm()
offer_form = OfferForm()
form_applicant = ApplicantForm(request.POST)
form_offer = OfferForm(request.POST)
if form_applicant.is_valid() and form_offer.is_valid():
# Grab the data
form_applicant.save(commit=True)
# Create Offer instance
form_offer.save(commit=False)
form_offer.applicant = form_applicant
form_offer.save(commit=True)
context = {
'site': site,
'offer_form': offer_form,
'applicant_form': applicant_form,
}
return render(request, "dashboard/dashboard_planner.html", context)
How would I fix the relation issue and is this a proper way to handle the workflow in that manner at all?
You should set the .applicant on the .instance of the form, and use the instance of the form_applicant, not the form_applicant itself, so:
from django.shortcuts import redirect
def render_dashboard_planner(request):
site = 'planner'
if request.method == 'POST':
form_applicant = ApplicantForm(request.POST, request.FILES)
form_offer = OfferForm(request.POST, request.FILES)
if form_applicant.is_valid() and form_offer.is_valid():
# Grab the data
applicant = form_applicant.save()
form_offer.instance.applicant = applicant
form_offer.save()
return redirect('name-of-some-view')
else:
applicant_form = ApplicantForm()
offer_form = OfferForm()
context = {
'applicant_form': applicant_form,
'offer_form': offer_form,
'site': site
}
return render(request, 'dashboard/dashboard_planner.html', context)
i've created a page which has a formset, i want to check all forms if they have error, then call save method, but create() automatically call save method! is there away to prevent it please ?
here is my views.py
def addNewGuestPopup(request):
if request.method == "POST":
form_no = int(request.POST.get('form_no'))
removed_form = request.POST.get('removed_form').split(",")
error_form_exits = []
new_guests = []
for i in range(form_no):
if str(i) not in removed_form:
full_name = request.POST.get('fullname-'+str(i))
dob = request.POST.get('dob-'+str(i)).split("-")
try:
visitor = Vistor.objects.get(full_name=full_name, dob=datetime.datetime(int(dob[0]), int(dob[1]), int(dob[2])))
error_form_exits.append(i)
except Vistor.MultipleObjectsReturned:
pass
except Vistor.DoesNotExist:
visitor = Vistor.objects.create(full_name=full_name,
dob=datetime.datetime(int(dob[0]), int(dob[1]), int(dob[2])),
admin=request.user)
new_guests.append(visitor)
# return JsonResponse({'error_form':error_form})
print(len(error_form_exits))
return JsonResponse({'data':list(Vistor.objects.values_list('full_name', flat=True)),
'error_form':error_form_exits}, safe=True)
return render(request, 'main/forms.html')
i dont want to use django formset is there a way to prevent create from save until all forms been checked please?
note : dob and full_name are unique together
thank you ..
I'm a beginner and I'm trying to create a small network project in which users can follow each other. I have implemented the follow button right, so it updates my models and displays proper info to users, but I can't get unfollow to work properly. I'm guessing it's something to do with the way I implemented follow model (with many to many field), but I'd like to implement it this way for practice... Anyhow, here's the code:
Models:
class User(AbstractUser):
pass
class Follow(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="user_follow")
following = models.ManyToManyField(User, blank=True, related_name="followers")
And view:
def users(request, username):
"""Displaying user profiles"""
if request.method == "POST":
user = request.user
profile = User.objects.get(username=username)
follow = Follow(user=user)
follow.save()
if "unfollow" in request.POST:
profile.followers.remove(user)
follow.following.remove(profile)
return HttpResponseRedirect(reverse('users', args=(username,)))
elif "follow" in request.POST:
follow.following.add(profile)
return HttpResponseRedirect(reverse('users', args=(username,)))
This code yields in: "ValueError at /users/test
Cannot query "admin": Must be "Follow" instance." at the profile.followers.remove(user) line...
Playing with it in shell I found out (at least I think so) that the line under it (follow.following.remove(profile) - which by the way was there before I tried with the profile.followers.remove(user)) removes the profile from Follow model, but for some reason it is not by itself updated in the Users model (for followers) ???
from django.db import models
# Create your models here.
class User(models.Model):
name = models.CharField(max_length=40)
pwd = models.CharField(max_length=40)
def __str__(self):
return self.name
class Follow(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
another_user = models.ManyToManyField(User, related_name='another_user')
def __str__(self):
return self.user.name
============================================================================
views.py
from django.shortcuts import render, redirect
from django.http import HttpResponse
from .models import User, Follow
# Create your views here.
def index(request):
if 'user' in request.session:
return render(request, 'index.html')
else:
return redirect('login')
def profile(request, user_name):
user_obj = User.objects.get(name=user_name)
session_user = User.objects.get(name=request.session['user'])
session_following, create = Followers.objects.get_or_create(user=session_user)
following, create = Followers.objects.get_or_create(user=session_user.id)
check_user_followers = Followers.objects.filter(another_user=user_obj)
is_followed = False
if session_following.another_user.filter(name=user_name).exists() or following.another_user.filter(name=user_name).exists():
is_followed=True
else:
is_followed=False
param = {'user_obj': user_obj,'followers':check_user_followers, 'following': following,'is_followed':is_followed}
if 'user' in request.session:
return render(request, 'profile.html', param)
else:
return redirect('index')
def follow_user(request, user_name):
other_user = User.objects.get(name=user_name)
session_user = request.session['user']
get_user = User.objects.get(name=session_user)
check_follower = Followers.objects.get(user=get_user.id)
is_followed = False
if other_user.name != session_user:
if check_follower.another_user.filter(name=other_user).exists():
add_usr = Followers.objects.get(user=get_user)
add_usr.another_user.remove(other_user)
is_followed = False
return redirect(f'/profile/{session_user}')
else:
add_usr = Followers.objects.get(user=get_user)
add_usr.another_user.add(other_user)
is_followed = True
return redirect(f'/profile/{session_user}')
return redirect(f'/profile/{session_user}')
else:
return redirect(f'/profile/{session_user}')
=============================================================================
User This For Reference...Follow And Unfollw Logic
i am working on a website where users can send friend request, accept request, cancel request. I have an error AttributeError object has no attribute 'delete'. This happens when i cancel friend request. This my code i tried:
Model:
class FriendRequest(models.Model):
to_user = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE, related_name='to_user')
from_user = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE, related_name='from_user')
date = models.DateTimeField(auto_now_add=True, null= True)
class Meta:
verbose_name = 'Friend request'
verbose_name_plural = 'Friend requests'
ordering = ['-date']
def __str__(self):
return "from {}, to {}".format(self.from_user.username, self.to_user.username)
Views.py:
#login_required
def cancel_friend_request_view(request, id):
user = get_object_or_404(User, id=id)
frequest = FriendRequest.objects.filter(from_user=request.user, to_user=user).first()
frequest.delete()
print(frequest)
return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
I solved it like this(I do not know if it is the best way, but it worked), removing .first():
#login_required
def cancel_friend_request_view(request, id):
user = get_object_or_404(User, id=id)
frequest = FriendRequest.objects.filter(from_user=request.user, to_user=user)
frequest.delete()
print(frequest)
return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
It may be better to pass through the FriendRequest's ID instead, to entirely skip this section of code:
user = get_object_or_404(User, id=id)
frequest = FriendRequest.objects.filter(from_user=request.user, to_user=user).first()
You could rather do this:
friend_request = get_object_or_404(FriendRequest, id=id)
friend_request.delete()
Also consider not deleting data entirely from your database, and rather making use of deleted flags in order to keep a behavioural history throughout your software.
.first() will return None if no matching row is found.
https://docs.djangoproject.com/en/3.0/ref/models/querysets/#first
Note that first() is a convenience method, the following code sample is equivalent to the above example:
try:
p = Article.objects.order_by('title', 'pub_date')[0]
except IndexError:
p = None
[edit] you need to handle the None-case, which should have been clear from the above explanation. Also, I recommend to learn using the python debugger to inspect types of variables instead of relying on debug-prints.
#login_required
def cancel_friend_request_view(request, id):
user = get_object_or_404(User, id=id)
frequest = FriendRequest.objects.filter(from_user=request.user, to_user=user)
if frequest is None:
raise Http404()
frequest.delete()
So I'm trying to build a Django site that collects Mod Applications to learn Django Forms. Except that I'm an idiot and I don't know what am I doing.
The thing that I'm trying to do is collect and save the Form data the current part and later try to show that data in the Django Admin the part I still haven't done and don't know how.
When I fill out the form I get [06/May/2017 19:38:29] "POST /modapp HTTP/1.1" 200 2354
This is my forms.py:
class Application(forms.ModelForm):
class Meta:
model = ModApplication
fields = ('discord', 'reddit', 'serverrank','finds','serverstay','active','timezone','reason','helped','help')
def __init__(self, *args, **kwargs):
super(Application, self).__init__(*args, **kwargs)
self.fields['discord'].widget.attrs['placeholder'] = 'UnknownDeveloper#2068'
self.fields['reddit'].widget.attrs['placeholder'] = '/u/UnknownDeveloper'
self.fields['serverrank'].widget.attrs['placeholder'] = 'GEOCACHING + RANK'
self.fields['serverstay'].label = "How long have you been on the server"
self.fields['active'].label = "How active have you been on the server"
self.fields['timezone'].widget.attrs['placeholder'] = 'CET'
self.fields['reason'].label = "Why do you want to become a mod?"
self.fields['helped'].label = "How have you helped the server so far?"
self.fields['help'].label = "How will you help the server if you'll become a mod"
models.py
class ModApplication(models.Model):
def __unicode__(self):
return "Discord User: " + self.discord + " aka " + self.reddit
reddit = models.CharField("Reddit Username", max_length=30)
discord = models.CharField("Discord Username", max_length=30)
serverrank = models.CharField("Server Rank", max_length=60)
finds = models.CharField("Finds", max_length=12)
serverstay = models.CharField("Stayed on the server for",max_length=200)
active = models.CharField("Is Actice on Discord for", max_length=500)
timezone = models.CharField("Timezone", max_length=20)
reason = models.TextField("He likes to become a mod because", max_length=5000)
helped = models.TextField("He helped by", max_length=5000)
help = models.TextField("He'll help by", max_length=5000)
views.py
def formtofill(request):
form = Application()
return render(request, 'appmod.html', {'form': form,})
if request.method == "POST":
form = Application(request.POST)
print(request.POST)
if form.is_valid():
user = form.save()
user.discord = request.discord
user.reddit = request.reddit
user.serverrank = request.serverrank
user.finds = request.finds
user.serverstay = request.serverstay
user.active = request.active
user.timezone = request.timezone
user.reason = request.reason
user.helped = request.helped
user.help = request.help
user.save()
print(user)
messages.success(request, 'Your Mod Application has been successfully submitted!')
print(form)
return HttpResponse('Successful')
else:
form_class = Application
I searched a lot but I didn't find anything. I tried to print debug messages but they didn't print anything. I put the messages module but nothing happened. HTTPResponse just reloads back to the form. Help will be gladly accepted. Thanks for your time. If I am missing something please tell me and i'll edit my post
It's a suprise that this code runs at all, it should be producing attribute errors for these:
user.discord = request.discord
user.reddit = request.reddit
But the reason that it doesn't is because the execution path never reaches that point
def formtofill(request):
form = Application()
return render(request, 'appmod.html', {'form': form,})
Because of that return statement.
Your corrected code should look like
def formtofill(request):
form = Application()
if request.method == "POST":
form = Application(request.POST)
print(request.POST)
if form.is_valid():
user = form.save()
messages.success(request, 'Your Mod Application has been successfully submitted!')
return HttpResponseRedirect('/success_url')
else:
form_class = Application
return render(request, 'appmod.html', {'form': form,})
Dont save the form upfront. Save but put commit=false.
Also remove that return statement as in the answer above mine.
user = form.save(commit=False).
Then an instance is created, but its not written into the database. Now you can do the assignments.
user = form.save(commit=False).
#Now....
user.discord = request.POST['discord']
user.reddit = request.POST['reddit']
user.serverrank = request.POST['serverrank']
user.finds = request.POST['finds']
user.serverstay = request.POST['serverstay']
....................
user.save()
return HttpResponse('Successful')
Instead you were trying to access the data as an attribute of the request object itself. The form data are contained in request.POST, then you have to access it from there.
Also,
else:
form = Application()
You need to instantiate the form class.