Django model store information for each user - django

I am building a competition website where challenges will be released weekly. For each user I want to track if they have completed a challenge but cannot see how this would be done. Currently the challenges are stored as a model and am using the ListView and DetailView to display them.
from django.db import models
from django.contrib.auth.models import User
STATUS = (
(0, 'Draft'),
(1, 'Publish'),
)
class Challenge(models.Model):
title = models.CharField(max_length=200, unique=True)
slug = models.SlugField(max_length=200, unique=True)
release_date = models.DateTimeField()
preamble = models.TextField()
ciphertext = models.TextField()
plaintext = models.TextField()
status = models.IntegerField(choices=STATUS, default=0)
class Meta:
ordering = ['-release_date']
def __str__(self):
return self.title
Thank you in advance to anyone who helps me with this. Oh and a solution will be submitted and then checked with this form.
<div class='form'>
{% if user.is_authenticated %}
<textarea rows="10" name="plaintext" form="submitAnswer" wrap="soft" placeholder="Plaintext.."></textarea>
<form method="post" id="submitAnswer">
{% csrf_token %}
<input type="submit" value="Submit">
</form>
{% else %}
<p>Must be logged in to submit answer.</p>
{% endif %}
</div>

A really basic implementation is to add a ManyToManyField between your Challenge model and your the User model :
from django.conf import settings
class Challenge(models.Model):
users = models.ManyToManyField(settings.AUTH_USER_MODEL)
# Other fields...
In the above example, you can just activate the relationship if the user has passed the test.
Now, maybe, you want to add informations about this relationship. You can do it with 'through' argument. This model tells if a user has passed the challenge or not and how many tentatives has been done. Modify it as you wish.
from django.conf import settings
class Challenge(models.Model):
users = models.ManyToManyField(settings.AUTH_USER_MODEL,
through='ChallengeUsers')
# Other fields...
class ChallengeUsers(models.Model):
challenge = models.ForeignKey(Challenge, on_delete=models.CASCADE)
users = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
hasPassed = models.BooleanField(default=False)
tentatives = models.IntegerField()

Related

Trying to delete a comment from a post in django

I am currently trying to delete a comment from my database via a button in django template.
Model looks like this
from django.db import models
from django.contrib.auth.models import User
from cloudinary.models import CloudinaryField
from profiles.models import UserProfile
class Post(models.Model):
user_profile = models.ForeignKey(UserProfile, on_delete=models.CASCADE, null=True, related_name='user_posts')
title = models.CharField(max_length=220, unique=True)
location = models.CharField(max_length=220)
rating = models.DecimalField(
max_digits=6, decimal_places=2)
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name="activity_post")
updated_on = models.DateTimeField(auto_now=True)
description = models.TextField()
featured_image = CloudinaryField('image', blank=False)
created_on = models.DateTimeField(auto_now_add=True)
likes = models.ManyToManyField(User, related_name='activity_likes', blank=True)
like_count = models.BigIntegerField(default='0')
class Meta:
ordering = ['-created_on']
def __str__(self):
return self.title
def number_of_likes(self):
return self.likes.count()
def liked_by_user(self):
return self.likes.values_list('id', flat=True)
class Comment(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True, related_name="user_comment")
post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')
name = models.CharField(max_length=80)
email = models.EmailField()
body = models.TextField()
created_on = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['created_on']
def __str__(self):
return f"Comment {self.body} by {self.name}"
Delete function
def delete_comment(request, post_id):
users_comment = get_object_or_404(Comment, post=post_id)
users_comment.delete()
return redirect(reverse('activity'))
URLS
from . import views
from django.urls import path
urlpatterns = [
path('like/', views.like, name='like'),
path("add/", views.add_post, name="add_post"),
path('edit/<int:post_id>/', views.edit_post, name='edit_post'),
path('delete/<int:post_id>/', views.delete_post, name='delete_post'),
path('edit_comment/<int:id>/', views.edit_comment, name='edit_comment'),
path('delete_comment/<int:post_id>/', views.delete_comment, name='delete_comment'),
path("activity/", views.PostList.as_view(), name="activity"),
path('comment/<int:post_id>/', views.Comment.as_view(), name='comment'),
path('searched_posts/', views.search_posts, name='searched_posts'),
path('post/<int:post_id>/', views.post_detail, name='post_detail')
]
here is the comment part that is showing the button.
{%if comments %}
{% for comment in comments %}
{% if comment.user == request.user %}
{{comment.body}} :comment
{{comment.id}} id
<a class="btn tbn-success" href="{% url 'edit_comment' comment.id %}" aria-label="edit button">Edit</a>
<button class="btn btn-warning">Delete</button>
{% endif %}
{% endfor%}
{% endif%}
When I click delete i get an error
Error
Any help would be greatly appreciated, I have tried a ton of different ways from online but nothing seems to work. can anyone point me in the right direction
The first thing I can see is that your delete function uses post = post_id.
Every comment on a particular post will share that post foreign key, so if there is more than one comment on a post, you can't use get_or_404() - it's limited to returning 1 item.
The URL you create for your button is using comment.id so it makes sense to use that instead - this will make it easier to see what's happening.
urls.py
path('delete_comment/<int:comment_id>/', views.delete_comment, name='delete_comment'),
views.py
def delete_comment(request, comment_id):
users_comment = get_object_or_404(Comment, pk=comment_id)
users_comment.delete()
return redirect(reverse('activity'))

How to add condition to a manytomany relationship

I'm a little new to Django, so my question may be basic, but bare with me. Let's say I'm sharing my posts with some of my friends (who are manytomany relation with the post), but also giving an extra condition for whether they can comment on it, or not. This condition, together with the name of the user to be shared with are submitted through a forum. Now my problem is that I don't know how/where to save this condition. I will show you some of my code.
Models.py
class Task(models.Model):
name = models.CharField(max_length=50)
text = models.TextField()
deadline = models.DateTimeField()
created = models.DateField(auto_now_add=True)
updated = models.DateField(auto_now=True)
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='taskset')
shared = models.ManyToManyField(User, blank=True, related_name = 'shared_list')
def __str__(self):
return f"{self.name}-{self.user.username}"
class Comment(models.Model):
text = models.TextField()
task = models.ForeignKey(Task, on_delete=models.CASCADE, related_name='comments')
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='comments')
created = models.DateField(auto_now_add=True)
def __str__(self):
return f"{self.user.username}-{self.task}"
Share form html
{% extends 'base.html'%}
{% load crispy_forms_tags %}
{% block content %}
<h3>Enter the Username of the Friend you want to share with</h3>
<form method="POST">
{% csrf_token %}
{{form|crispy}}
<input type="submit", value="Share">
</form>
{% endblock content %}
And the view processing it
def share(request, id):
task = Task.objects.get(id = id)
if request.method == 'POST':
share_with = User.objects.get(username = request.POST['username'])
if share_with is not None:
task.shared.add(share_with)
task.save()
return redirect('index')
else:
form = ShareForm()
return render(request, 'share.html', {'form':form})
Thanks a lot, I've been stuck for two hours, PLEASE HELP!

first_name in django model

how can I access to first_name of a user in django template?. for example my writer in django model is like this below :
writer = models.ForeignKey(User, on_delete=models.CASCADE)
If User is the Django default user model, it's simply
writer.first_name
-- e.g. if your example is in a post model you're rendering,
{{ post.writer.first_name }}
in a template.
I have somewhat of a similar setup and this works for me:
models.py
class Customers(models.Model):
name = models.CharField(("Customer name"), max_length=200)
class Licenses(models.Model):
customer = models.ForeignKey(Customers, on_delete=models.CASCADE)
views.py
def licenses (request):
lic = Licenses.objects.all()
return render(request, 'licenses.html',{'lic': lic})
licenses.html
{% for license in lic %}
{{ license.customer.name }}
{% endfor %}

django data in form only appear after refresh

I am using custom user authentication for verifying user. I have table named voter and I am tacking username and password via from and matching that with username and password of table if it match user will be logged in and allowed them to pass to next page which contain form. In that form I initiated data but it will not appear automatically it will appear only when i refresh the page
code of my files is bellow (for some big file only relevant code is included that's why it is partial)
model.py (partial)
class Voter(models.Model):
serial_voter_id = models.AutoField(primary_key=True)
voter_id = models.CharField(unique=True, max_length=10)
voter_name = models.CharField(max_length=255)
voter_constituency = models.ForeignKey(Constituency, models.DO_NOTHING, blank=True, null=True)
username = models.CharField(unique=True, max_length=32)
password = models.TextField()
voter_address = models.CharField(max_length=255, blank=True, null=True)
area = models.CharField(max_length=10, blank=True, null=True)
city = models.CharField(max_length=10, blank=True, null=True)
pincode = models.IntegerField(blank=True, null=True)
adhar_no = models.BigIntegerField(unique=True)
birth_date = models.DateField()
age = models.IntegerField()
fingerprint = models.TextField(blank=True, null=True)
authenticity = models.CharField(max_length=3, blank=True, null=True)
wallet_id = models.TextField()
class Meta:
managed = False
db_table = 'voter'
forms.py
from django import forms
from .models import Voter
class VoterForm(forms.ModelForm):
class Meta:
model = Voter
fields = [
'serial_voter_id',
'voter_id',
'voter_name',
'voter_constituency',
'username',
'voter_address',
'area',
'city',
'pincode',
'adhar_no',
'birth_date',
'age',
'authenticity',
'wallet_id'
]
views.py (partial)
from .models import Voter
from .forms import VoterForm
def voter_login(request, *args, **kwargs):
contex = {}
return render(request, "poll/voter_login.html", contex)
def voter_verification(request, *args, **kwargs):
f_username = request.POST.get('username')
voter = Voter.objects.get(voter_id=1) # thing need to be dynamic hear by replacing it with username
f_username = request.POST.get('username')
f_password = request.POST.get('password')
u_password = voter.password # fetching the password from voter object
u_password = u_password.decode() # decoding binary password to string
form = VoterForm(request.POST or None, instance=voter)
if form.is_valid():
form.save()
form = VoterForm()
contex = {
'voter' : voter,
'f_username' : f_username,
'f_password' : f_password,
'u_password' : u_password,
'form' : form
}
# compare hear username and password entered by user and from database if these are correcgt then allow this view or redirect to voter_login view
if voter.username == f_username and u_password == f_password:
return render(request, "poll/voter_verification.html", contex)
else:
return render(request, "poll/voter_login.html", {})
voter_login.html
{% extends 'header.html' %}
{% block content %}
<table>
<form method="get" action='voter_verification'> {% csrf_token %}
username <input type="text" name="username">
password <input type="password" name="password">
<input type="submit" name="login" value="login">
</form>
{% endblock %}
voter_verification.html (template file)
<!DOCTYPE html>
<html>
<body>
{% if f_username == voter.username and f_password == u_password %}
<h1>verified</h1>
{% else %}
<h1>wrong id and password</h1>
{% endif %}
<form method='post' action='vote_page'> {% csrf_token %}
{{ form.as_p }}
<input type='submit' value="sumbit">
</form>
</body>
</html>
changes query in view model ( def voter_verification(request, *args, **kwargs):)
def voter_verification(request, *args, **kwargs):
f_username = request.POST.get('username')
voter = Voter.objects.get(username=f_username)
then request user check in voter table which have exits with same user name.
Thanks to DrMaxwellEdison from reddit for providing answer
https://www.reddit.com/r/djangolearning/comments/fecn1f/question_django_data_in_form_only_appear_after/
Please do not have a separate model that stores usernames and passwords aside from your User model. You can simply add a OneToOneField to the User model to connect this Voter model to the authenticated User, and you don't need to do any extra data storage (plus, you are more likely to be handling the password information incorrectly, exposing it to being compromised if your site is breached).
Also per your comment on SO, the POST is not working because of CSRF protection (the traceback of your error would likely have indicated this already). Please see those docs for details on how to proceed (hint: do not disable CSRF!).

How to access extended User attributes in django template

I am trying to access extended field of User model in Django template but it doesn't work, there are my files:
models.py:
class Author(models.Model):
user = models.OneToOneField(User, related_name='user', on_delete=models.SET_NULL, null=True)
bio = models.TextField(
max_length=1400, help_text="Enter author biography.")
def __str__(self):
return self.user.username
def create_profile(sender, **kwargs):
user = kwargs["instance"]
if kwargs["created"]:
user_profile = Author(user=user, bio='my bio')
user_profile.save()
post_save.connect(create_profile, sender=User)
template:
{% extends "base_generic.html" %}
{% block title %}
<title>Author {{user}}</title>
{% endblock %}
{% block content %}
<h1>{{user}}</h1>
<h2>Bio:</h2>
<p>{{user.author.bio}}</p>
<div>
{%for item in user.author.blogs_set.all%}
<p>{{item.title}}</p>
<hr>
{%endfor%}
</div>
{% endblock %}
views:
class UserDetailView(generic.DetailView):
model = User
template_name = 'blogapp/user_detail.html'
I want to get access to the bio field through user.author.bio but nothing displays I have also tried user.bio is there any tricky way to get access to this field?
You set the related_name to:
class Author(models.Model):
user = models.OneToOneField(
User,
related_name='user',
on_delete=models.SET_NULL, null=True
)
But the related_name is the name to access the related Author from a User object (so the name of the relation in reverse). You thus should set it to author (or leave it blank), like:
class Author(models.Model):
user = models.OneToOneField(
User,
related_name='author',
on_delete=models.SET_NULL, null=True
)
By setting it to user, you could have accessed the Author object with user.user, but I strongly advise not to do this, since in the end, it will only result in code that is hard to understand. For Django it of course does not matter (given no two relations originating from User have the same name), but for programmers, it gives a wrong impression.