Django how to get two models in relation? - python

At my django application users are able to buy specific posted elements. To later-on display a content_preview or the full content of a post i created a "helper_model" -> Post_Paid_Sell_Tut to check if a user has paid for the post or not. My target is that i can later on display the peview or full content accordingly to the paid or unpaid status but i dont clearly understand how to get those two models in relations at my views.py
i created the following two models for this:
now i want to understand how i can bring those two models in relations at my views.py.
In the end the user will see a form with only a Buy button and some Text. after he hits the button the status should get changed from unpaid to paid for the paying user.
Do i really need a Form at this point?
and if so, how does it have to look like?
Thanks for help in adavance :)

First of all, you should change your status choices a little bit.
STATUSES = (
(0, 'unpaid'),
(1, 'paid')
)
class Post_Paid_Sell_Tut(models.Model):
paying_user = models.ForeignKey(User, on_delete=models.CASCADE)
post_sell_tut = models.ForeignKey(Post_Sell_Tut, on_delete=models.CASCADE)
STATUS = models.IntegerField(choices=STATUSES, default=0)
This will ease later database searches and will clarify the issues. Then if you are just updating the status then there is no need for any form.
def post_sell_tut_buy(request, pk):
post = get_object_or_404(Post_Sell_Tut, pk=pk)
if request.user == post.author:
messages.error(request, 'You cant buy your own Post!')
return redirect('post_sell_tut_detail', pk=pk)
else:
template = 'Post_Sell_Tut/post_sell_tut_buy.html'
post.STATUS = 1 # You are updating the STATUS
post.save() # you are writing the change to database
context = {
'post': post
}
return render(request, template, context)
In addition by passing post instance to the template you are desired to view the informations you should follow this:
def post_sell_tut_buy(request, pk):
post = Post_Paid_Sell_Tut.objects.select_related('post_sell_tut').filter(pk=pk)
if request.user == post.author:
messages.error(request, 'You cant buy your own Post!')
return redirect('post_sell_tut_detail', pk=pk)
else:
template = 'Post_Sell_Tut/post_sell_tut_buy.html'
post.STATUS = 1 # You are updating the STATUS
post.save() # you are writing the change to database
context = {
'post': post
}
return render(request, template, context)
I added select_related because when you try to fetch information by the foreign key in from post it will not cause an extra DB request.
UPDATE
def post_sell_tut_buy(request, pk):
post = Post_Sell_Tut.objects.select_related('author).filter(pk=pk)
if request.user == post.author:
messages.error(request, 'You cannot buy POst(s) you created by your own!')
return redirect('post_sell_tut_detail', pk=post.pk)
else:
template = 'Post_Sell_Tut/post_sell_tut_buy.html'
context = {
'post': post,
}
return render(request, template, context)
You cannot access STATUS from Post_Sell_Tut model. It does not have that field.
def post_sell_tut_buy_exec(request, pk):
post_sell_tut = get_object_or_404(Post_Sell_Tut, pk=pk)
post_paid_sell_tut = Post_Paid_Sell_Tut.objects.filter(post_sell_tut=post_sell_tut)
if request.user == post.author:
messages.error(request, 'You cannot buy Post(s) you created by your own!')
return redirect('post_sell_tut_detail', pk=post.pk)
else:
template = 'Post_Sell_Tut/post_sell_tut_buy.html'
post_paid_sell_tut.STATUS = 1
post_paid_sell_tut.save()
context = {
'post': post
}
return render(request, template, context)

just create a "Post_Paid_Sell_Tut" object when a user requests to buy a post
def post_sell_tut_buy(request, pk):
post = get_object_or_404(Post_Sell_Tut, pk=pk)
if request.user == post.author:
messages.error(request, 'You cant buy your own Post!')
return redirect('post_sell_tut_detail', pk=post.pk)
else:
try:
# throws an exception if not bought yet
Post_Paid_Sell_Tut.get(paying_user=request.user, post_sell_tut=post)
messages.success(request, 'you allready have this post!')
# ... other stuff
except Post_Paid_Sell_Tut.DoesNotExist:
# create Post_Paid_Sell_Tut object indicating that the user bought the post
ppst = Post_Paid_Sell_Tut(paying_user=request.user,
post_sell_tut=post, status="paid")
ppst.save()
messages.success(request, 'post is yours :)!')
# ... other stuff

Related

Django - Unable to find object using pk (Matching query DoesNotExist)

Whenever I try to create a "Tour" for a "User" I get this error:
"DoesNotExist at /add-tour/FAjK5CryF8/ - User matching query does not exist."
Specifically the problems seems to come from this line of code:
user = User.objects.get(pk=pk)
models.py
class Tour(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
tour_date = models.DateField(default=date.today)
tour_fans = models.ForeignKey(FanAccount, on_delete=models.PROTECT)
def __str__(self):
return f"{self.user} del {self.tour_date}"
views.py
def tour_new(request, pk):
user = User.objects.get(pk=pk)
if request.method == "POST":
form = TourForm(request.POST)
if form.is_valid():
instance = form.save(commit=False)
instance.tour_fans = request.user
form.instance.user = user
instance.save()
form.save()
return render(request, "tour.html", {"form": TourForm(), "success": True})
else:
form = TourForm()
return render(request, "tour.html", {"form": form})
For "User" I'm using a custom Primary Key (ShortUUID).
I'm new to Python and Django so it may be something easily solvable, but after hours of attempts I seem unable to solve it.
You need to make sure your user instance does exist, so you should instead of user = User.objects.get(pk=pk)call user = get_object_or_404(User, pk=pk), then you need to pass user as an instance:
if request.method == "POST":
form = TourForm(request.POST, instance=user)

How to remove "this field is not required" in django?

I found posts with similar problem, but the solutions dont seem to work with me. Or maybe I am missing something.
I created a form in Django, but as a default it seems that every mandatory fields have this "this field is required" text above.
Ideally, I would like to have this only when someone tries to submit a form and a field is missing.
form.py
class ElderFlowerChampFormAdmin(ModelForm):
fieldsets=[
("Look",{'fields':[
('look_colour','look_clarity','look_effervescence')]}),
}
widgets = {
'user': forms.Select(attrs={'class':'form-control','required':'True'}),
'look_colour':forms.Select(attrs={'class':'form-control','required':'True'}),
}
view.py
def elderflowerchamp(request, product_id):
global ChampageRating
product = Product.objects.get(pk=product_id)
url = request.META.get('HTTP_REFERER')
submitted = False
try:
if request.method == "POST":
reviews = ChampageRating.objects.get(pk=product_id)
if request.user.is_superuser:
form = ElderFlowerChampFormAdmin(request.POST, instance=reviews)
if form.is_valid():
form.save()
return redirect('home')
else:
form = ElderFlowerChampForm(request.POST, instance=reviews)
if form.is_valid():
ChampageRating = form.save(commit=False)
ChampageRating.user = request.user
ChampageRating.save()
return redirect('home')
else:
#This part goes to the page, but doesnt submit
reviews = ChampageRating.objects.get(pk=product_id)
if request.user.is_superuser:
form = ElderFlowerChampFormAdmin
else:
form = ElderFlowerChampForm
if 'submitted' in request.GET:
submitted = True
except:
reviews = None
if request.user.is_superuser:
form = ElderFlowerChampFormAdmin(request.POST)
if form.is_valid():
data = ChampageRating()
data.rating = form.cleaned_data['rating']
data.look_colour = form.cleaned_data['look_colour']
data.ip = request.META.get('REMOTE_ADDR')
data.product_id = product_id
data.user_id = request.user.id
data.save()
messages.success(request, 'Thank you! Your review has been submitted.')
return redirect('home')
else:
form = ElderFlowerChampForm(request.POST)
if form.is_valid():
data = ChampageRating()
data.rating = form.cleaned_data['rating']
data.look_colour = form.cleaned_data['look_colour']
data.ip = request.META.get('REMOTE_ADDR')
data.product_id = product_id
data.user_id = request.user.id
data.save()
messages.success(request, 'Thank you! Your review has been submitted.')
return redirect('home')
return render(request,"main/ElderFlowerReview.html", {'form':form, 'submitted':submitted,'reviews':reviews, 'product':product})
models.py
LOOKCOLOUR=(
(1,'Straw'),
(2,'Yellow'),
(3,'Gold'),
(4,'Amber'),
)
class ChampageRating(models.Model):
user = models.ForeignKey(User,blank=True, on_delete=models.CASCADE)
product=models.ForeignKey(Product,related_name="champcomments", on_delete=models.CASCADE)
look_colour=models.IntegerField(choices=LOOKCOLOUR, default=0)
def __str__(self):
return '%s - %s - %s'%(self.user, self.product, self.date_added)
Any ideas
something wrong on case request.GET here:
if request.user.is_superuser:
form = ElderFlowerChampFormAdmin
else:
form = ElderFlowerChampForm
You send the FormClass into the template context, and not the form instance.
Also see eror on the except case: If i have a GET, i should not render BoundedForm, here should be form.bounded = false (form is not bounded with any data). But you are always made the BoundedForm, with the request.POST data after error here:
reviews = ChampageRating.objects.get(pk=product_id)
My opinion is - you should try to read about Django-GCBV, it is better way to avoid complex errors, like in your question.
https://docs.djangoproject.com/en/4.0/topics/class-based-views/

how to redirect in django through select option in forms.py

I need help. I am makig a sign up page in django In my forms.py I have two select optins. option 1) free trial & option 2)monthly subscription I want user to go to login page if he selects option1 and to checkout page if he selects option2. here is my code.
forms.py
class RegisterForm(UserCreationForm):
email = forms.EmailField()
CHOICES = (('Option 1', 'Free 30 days trial'),('Option 2', '$9.99 Monthly subscription'))
plan = forms.ChoiceField(choices=CHOICES)
class Meta:
model = User
fields = ['username', 'email', "plan", "password1", "password2"
views.py
def signupUser(request):
if request.method == "POST":
form = RegisterForm(request.POST)
if form.is_valid():
if plan == 'Free 30 days trial':
form.save()
return redirect("/main/login/")
else:
form.save()
return redirect("/main/checkout/")
else:
form = RegisterForm()
return render(request, 'signup.html', {"form":form})
but this gives error: plan is not defined
Need help please.
Well, you haven't defined plan in the scope.
Change plan to form.plan since you are referring to the plan inside the form.
Whatever the data submitted with a form, once it has been successfully validated by calling is_valid() (and is_valid() has returned True), the validated form data will be in the form.cleaned_data dictionary. This data will have been nicely converted into Python types for you.
Code in views.py goes like this
if request.method == "POST":
form = RegisterForm(request.POST)
if form.is_valid():
form.save()
plan = form.cleaned_data['plan']
print(plan)
if plan == 'Option 1':
return redirect("/main/login/")
else:
return redirect("/main/checkout/")
else:
form = RegisterForm()
return render(request, 'signup.html', {"form":form})

Django model form, adding a user id when creating new note

I'm pretty new to Django, I've been stuck on this view for a little while. My goal with this form is to be able to create a small note on a "Property" about maintenance or other information. The note would log the time, date, note and the user that recorded the note. Any help would be appreciated.
View:
#login_required(login_url="login")
def createNote(request, pk):
PropertyNoteFormSet = inlineformset_factory(
Property, PropertyNote, fields=('note', 'user',))
property_note = Property.objects.get(id=pk)
form = PropertyNoteFormSet(instance=property_note)
# form = OrderForm(initial={'customer': customer})
if request.method == "POST":
print(request.POST)
form = PropertyNoteFormSet(
request.POST, instance=property_note)
if form.is_valid():
form.save()
return redirect("/")
context = {"form": form}
return render(request, "dashboard/create_note.html", context)
Here is the ModelForm:
class PropertyNoteForm(ModelForm):
class Meta:
model = PropertyNote
fields = ['note']
exclude = ['user']
Here is the Model:
class PropertyNote(models.Model):
airbnb_name = models.ForeignKey(Property, blank=True,
null=True,on_delete=models.CASCADE)
note = models.TextField(blank=True, null=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
created_on = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.note
The form comes out with around 4 boxes to fill in. Currently it works, but you have to actually select the user that is posting the note, I would like this part to be handled automatically and use the current logged in user. I think I still have a whole lot of holes in my knowledge around this stuff, I just can't seem to work it out.
Thanks in advance.
Edit:
I've tried this:
def createNote(request, pk):
PropertyNoteFormSet = inlineformset_factory(
Property, PropertyNote, fields=('note',), extra=1)
property_note = Property.objects.get(id=pk)
form = PropertyNoteFormSet(
queryset=PropertyNote.objects.none(), instance=property_note)
# form = OrderForm(initial={'customer': customer})
if request.method == "POST":
print(request.POST)
form = PropertyNoteFormSet(
request.POST, instance=property_note)
if form.is_valid():
instance = form.save(commit=False)
instance.user = request.user
print(instance.user)
instance.save()
return redirect("/")
context = {
"form": form,
'pk': pk,
}
return render(request, "dashboard/create_note.html", context)
But I get this:
AttributeError at /create_note/75/
'list' object has no attribute 'user'
Request Method: POST
Request URL: http://127.0.0.1:8000/create_note/75/
Django Version: 3.0.4
Exception Type: AttributeError
Exception Value:
'list' object has no attribute 'user'
you can use request.user.id to get the logged user id in your view.
See Documentation in Django
#login_required(login_url="login")
def createNote(request, pk, **kwargs):
note_form = PropertyNoteForm()
if request.method == "POST":
note_form = PropertyNoteForm(request.POST)
if note_form.is_valid():
add_note = note_form.save(commit=False)
add_note.user = request.user
add_note.airbnb_name =
Property.objects.get(id=pk)
add_note.save()
return redirect('/property/' + pk + '/')
context = {
"form": note_form,
'pk': pk,
}
return render(request, "dashboard/create_note.html", context)
I solved it with the above code. Using instance was the incorrect thing to do here. I didn't need to create an instance and I didn't need the inline form. I simply needed a new form:
note_form = PropertyNoteForm()
The user input information, I need to send that information to check if it's valid:
if request.method == "POST":
note_form = PropertyNoteForm(request.POST)
if note_form.is_valid():
Then I needed to populate the form with information that was not already in the form from the user:
add_note = note_form.save(commit=False)
add_note.user = request.user
add_note.airbnb_name = Property.objects.get(id=pk)
add_note.save()
return redirect('/property/' + pk + '/')

Why whenever I click on a link within my site, any logged in user gets logged out?

I have built a hackernews type clone with login system, upvotes etc.
I just have one problem at the moment. Whenever I click a link that redirects me to somewhere else on the site (i.e. localhost/ to localhost/science) the logged in user gets logged out.
Here are some of the key views associted with the problem I think:
def index(request, category_id=1):
stories = top_stories(top=30)
category = Category.objects.get(id = category_id)
if request.user.is_authenticated():
liked_stories = request.user.liked_stories.filter(id__in = [story.id for story in stories])
else:
liked_stories = []
return render(request, 'stories/index.html', {
'stories': stories,
'user': request.user,
'liked_stories': liked_stories,
'category': category,
})
#login_required(login_url = "/login/")
def story(request):
if request.method == 'POST':
form = StoryForm(request.POST)
if form.is_valid():
story = form.save(commit = False)
story.moderator = request.user
story.save()
return HttpResponseRedirect('/')
else:
form = StoryForm()
return render(request, 'stories/story.html', {'form': form})
#login_required
def vote(request):
story = get_object_or_404(Story, pk = request.POST.get('story'))
story.points += 1
story.save()
user = request.user
user.liked_stories.add(story)
user.save()
return HttpResponse()
Is there a 'next' parameter I can include somewhere that will keep each user logged in as they jump from link to link?
If you need any other parts of the code let me know.

Categories