Django : in a ManyToManyField how can I find if a relationship exists? - django

I'm creating a Truth System for my project PoopFacts, where people can vote for True, False, or remove their vote.
I have the voting system working, but
I'm trying to make the button change colors to show if they've voted for True of False already or uncasted their vote.
I'm showing the "Like button" code, cause it's simpler and uses the same logic.
.models
PoopFact(models.Model):
likes = models.ManyToManyField(User, related_name='likes')
.views
def home(request):
poopfacts = PoopFact.objects.all().order_by('-date')
context = {'form': form, 'poopfacts':poopfacts,}
return render(request, 'home.html', context)
The idea is pretty much something like this
html
{% for poopfact in poopfacts %}
{% if poopfact.likes.user.exists() %}
<button type="submit" class="btn btn-primary btn-block">Like</button>
{% else %}
<button type="submit" class="btn btn-block">Like</button>
{% endif %}
So if they've liked it, the button will be blue, and if they click it again it will uncast their vote and make it normal.
Does anybody have a good idea to make this work? I've been trying so many things with no luck.

in html
{% for poopfact in poopfacts %}
{% if user in poopfact.likes.all %}
<button type="submit" class="btn btn-primary btn-block">Like</button>
{% else %}
<button type="submit" class="btn btn-block">Like</button>
{% endif %}
{% endfor %}

Related

Quick help on how to format a logic statement

this might seem silly, but i need help,
I have a model, in which if "is_vendor" is True, I want it to display something, while if "is_vendor" is False, I dont want the item to display. I already figured how to switch the is_vendor from True to False or vice versa, What i want now is to know how to complete {% if user_profile.is vendor... statement (Plus Im not sure if want i typed there is close to correct. Thank you
Model:
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.CharField(max_length=245, null=True)
image = models.ImageField(default='default.png', upload_to='profile_pics')
is_vendor = models.BooleanField(default=True)
My template:
**{% if user_profile.is_vendor**
<div style="margin-left: 40px">
<a class="btn btn-sm btn-outline-primary mb-4 mr-3 "href="{% url 'vendor_register' %}">
Register
</a>
</div>
{% if user_profile.isVendor %}
<div style="margin-left: 40px">
<a class="btn btn-sm btn-outline-primary mb-4 mr-3 "href="{% url 'vendor_register' %}">
Register
</a>
</div>
{% endif %}
{% if user_profile.isVendor %}
your code in here
{%endif %}
If the user is logged in, you can access that user with {{ user }}. Since you have a OneToOneField to the Profile model, you thus can access the Profile record of the logged in user with {{ user.profile }}, and thus check if it is a vendor with {{ user.profile.is_vendor }}, we thus can wrap this in an {% if … %} … {% endif %} template tag [Django-doc]:
{% if user.profile.is_vendor %}
…
{% endif %}

Ifequal in django templates

Models.py
solution_req = models.CharField(max_length=250, default=0, choices=(('FLC', 'FLC'), ('FSC', 'FSC'),
('Crate', 'Crate'), ('PPBox', 'PP Box')))
HTML
{% ifequal l.solution_req PPBox %}
Create Solution
{% else %}
<button class="btn btn-primary" disabled>
Create Solution
</button>
{% endifequal %}
The above are my models and django templates
The problem is when the object has solution_req as PPBox it is still showing the disabled button instead of the link

Delete object with form in django

I'm displaying a table. In every line there should be a delete button which deletes the element from the table.
My problem is, I'm not sure how to pass the id of the element to the view.
html:
{% for post in posts %}
<div>
<h3>Zuletzt ausgewählt:</h3>
<p>published: <b>{{ post.pub_date }}</b>
</p>
<p>
name: <b>{{ post.Name }}</b>
anmeldung: <b>{{ post.get_Anmeldung_display }}</b>
essen: <b>{{ post.get_Essen_display }}</b>
<form action="" method="POST">
{% csrf_token %}
<input class="btn btn-default btn-danger" name="delete" type="submit" value="Löschen"/>
</form>
</p>
<p>
Email: <b>{{ post.Email }}</b>
</p>
</div>
{% endfor %}
views.py
if request.method == 'POST' and 'delete' in request.POST:
Eintrag.objects.filter(pk=id).delete()
return HttpResponseRedirect(request.path)
So I need to pass post.pub_date of every post to the view, how can I accomplish that?
My problem is, I'm not sure how to pass the id of the element to the view.
I can think of two ways to do this. I'll cover them both one by one.
1. Create a separate url route in your app specifically for deleting objects:
('/post/<pk>/delete/', name="delete_post"),
Then point your form's action to this url:
<form action="{% url 'delete_post' post.pk %}" method="POST">
...
Finally, modify your view function to accept the pk argument:
def my_view(request, pk):
...
2. Second method is to just create another field in your form and pass it the pk of the object:
Just create another field in your form.
<form action="" method="POST">
<input type="hidden" value="{{ post.pk }}" name="pk">
...
Then in your view just look at request.POST['pk'] to get the pk of the post.
A non-ajax way which is super easy to implement as it uses the Django generic views is this:
template.html
{% for post in posts %}
<div>
<h3>Zuletzt ausgewählt:</h3>
<p>published: <b>{{ post.pub_date }}</b>
</p>
<p>
name: <b>{{ post.Name }}</b>
anmeldung: <b>{{ post.get_Anmeldung_display }}</b>
essen: <b>{{ post.get_Essen_display }}</b>
<form action="" method="POST">
{% csrf_token %}
<input class="btn btn-default btn-danger" name="delete" type="submit" value="Löschen"/>
</form>
</p>
<p>
Email: <b>{{ post.Email }}</b>
</p>
<a href="/deleteurl/{{ post.pk }}">
Delete this!
</a>
</div>
{% endfor %}
Once the user clicks on the delete link they will be redirected to the delete view and template which will have a URL that looks like this "/deleteurl/1/".
Then your set of views, url, and template for processing the delete could look like this:
views.py
class DeleteMe(generic.DeleteView):
template_name = 'deleteconfirmation.html'
model = YourModel
success_url = '/YourRedirectUrl/'
urls.py
url(r'^deleteurl/(?P<pk>\d+)/$',
views.DeleteMe.as_view(), name='deletemeview'),
deleteconfirmation.html
<form action="" method="post">{% csrf_token %}
<p>Are you sure you want to delete "{{ object }}"?</p>
<input type="submit" value="Confirm" />
</form>
Again, this is without the use of Ajax.
The views and template are taken directly from the Django Docs
Using POST is our priority, but I thought that adding another form will be redundant.
Found solution in django-allauth' email view.
Though it doesn't include confirmation step (as in docs, mentioned by #HoneyNutIchiros or in more details, or via onclick), it can be useful.
They add name (action_remove) to button and check it in the request.POST dict:
# account/email.html
<button type="submit" name="action_primary" >{% trans 'Make Primary' %}</button>
<button type="submit" name="action_send" >{% trans 'Re-send Verification' %}</button>
<button type="submit" name="action_remove" >{% trans 'Remove' %}</button>
...
<button name="action_add" type="submit">{% trans "Add E-mail" %}</button>
# account/views.py
class EmailView(AjaxCapableProcessFormViewMixin, FormView):
...
def post(self, request, *args, **kwargs):
...
if "action_add" in request.POST:
res = super(EmailView, self).post(request, *args, **kwargs)
elif "action_remove" in request.POST:
res = self._action_remove(request)
...
return res

Django Model Form does not display Image field properly and does not Post it

The look of the File Upload for the picture in the Form is not OK as the button is inside the field. While it shows in the form as uploaded, it won't post. When I look in the firebug, I can see that the field for the File image is not being sent through with the other name fields, so the form never validates.
Here is how it looks
enter image description here
Here is the definition in the Model.
picture = models.ImageField(upload_to=user_directory_path)
So when Django creates the Form it does it in that weird way for the File filed
How should I then define the Field for File in the Model? Or where is the error lying?
The Form had this instruction>
{% load widget_tweaks %}
<form method="post" action="{% url 'book_create' %}" class="js-book-create-form" enctype="multipart/form-data">
{% csrf_token %}
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title">Create a new book</h4>
</div>
<div class="modal-body">
{% for field in form %}
<div class="form-group{% if field.errors %} has-error{% endif %}">
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
{% render_field field class="form-control" %}
{% for error in field.errors %}
<p class="help-block">{{ error }}</p>
{% endfor %}
</div>
{% endfor %}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Create book</button>
</div>
</form>
The handling of the form was like this:
data = dict()
if request.method == 'POST':
form = NewStockOfBookssForm(request.POST, request.FILES)
if form.is_valid():
form.save()
data['form_is_valid'] = True
else:
data['form_is_valid'] = False
Have you set enctype="multipart/form-data" for the form tag? This is required for fields with upload/image inputs, as described in the documentation.
How are you managing the form? If you use the FormView (or derivative) CBVs, this is done for you, but if not, you'll need to explicitly also pass files=(request.FILES or None) to the form's constructor.
You can save link,this way is better i think beacuse of:
1: in image field you save in database.(too heavy)but in link way you have too light.
2: in link way you can set it with static file way.(can delete easy).(imagefield have many problem but link it easy too manage)
I hope it will help you to choose.
The look of the File Upload for the picture in the Form is not OK as
the button is inside the field.
As for this problem, the solution I found is to add a custom css class to the button, an then tweak as neccesary. The whole field span acts as a button, but it doesn't look awful.

django delete model entry from selected form option

I have the following form displaying entries of a model for user settings. When selected, I would like that a button catches its pk and send it to a Delete view.Here is the current code but I am missing this part.
user_detail template html
<form id="SettingsListForm"><label>&nbsp Settings List : &nbsp &nbsp &nbsp</label>
{% if user.usersetting.first %}
<select class="form-control" name="settingslist" id = "settingslist" form="SettingsListForm" >
{% for settings in user.usersetting.all %}
<option value="{{ settings.file.url }}">{{ settings }}
</option>
{% endfor %}
</select>
{% else %}
<li class="list-group-item">NO SETTINGS YET</li>
{% endif %}
<button class="btn btn-outline-light btn-circle"><i class="glyphicon glyphicon-minus" href="{% url 'my_app:setting_delete' pk=user.usersetting.last.id %}"></i></button>
{% block delete_setting_confirm_block %}
{% endblock %}
</form>
setting_confirm_delete html template with delete_setting_confirm_block
{% extends 'login_app/user_detail.html' %}
{% block delete_setting_confirm_block %}
<h4>
ARE YOU <b>REALLY</b> SURE YOU WANT TO <b>DELETE</b> THIS SETTING ?
<form method="POST">
{% csrf_token %}
<button type="submit" class="btn btn-outline-light btn-danger" value="Delete">YES</button>
<a class="btn btn-outline-light btn-default" href="{% url 'login_app:user_detail' pk=user.id %}"><b>NO</b></a>
</form>
</h4>
{% endblock %}
my_app urls
url(r'^setting/(?P<pk>\d+)/$',views.UserSettingDeleteView.as_view(),name='setting_delete'),
UserSettingDeleteView in my_app views
class UserSettingDeleteView(DeleteView):
model = models.UserSetting
template_name = 'my_app/setting_confirm_delete.html'
def get_success_url(self):
return reverse('my_app:user_detail', kwargs={'pk': self.object.user.pk})
Somehow, a similar technique works fine when using listgroups:
working sample in user_detail html
<ul class="list-group">
{% if user.userdata.first %}
{% for data in user.userdata.all %}
<li class="list-group-item">{{ data }}<a class="btn btn-outline-light btn-circle" href="{% url 'my_app:data_delete' pk=data.pk %}"><i class="glyphicon glyphicon-remove"></i></a></i></li>
{% endfor %}
{% block delete_data_confirm_block %}
{% endblock %}
{% else %}
<li class="list-group-item">NOTHING RECORDED YET</li>
{% endif %}
</ul>
In your template.html, you should create a form for deletion, like this:
<form action="{% url 'my_app:setting_delete' pk=user.usersetting.last.id %}" method="post">
{% csrf_token %}
<input type="submit" value="Delete" class="btn btn-outline-light btn-circle">
</form>
Because in HTML you can not send directly PUT or DELETE, you should fake it via a POST request. It will be useful to read this, it is explained well.
Your UserSettingDeleteView can be as simple as that:
from django.views.generic.edit import DeleteView
from django.urls import reverse_lazy
class UserSettingDeleteView(DeleteView):
model = MyModel
# Replace with the model you want to delete (User)
success_url = reverse_lazy('my_app:setting_list')
# After deletion, possibly you will want to redirect the user to the list view
The built-in DeleteView cares itself to find your model by the pk parameter you pass through your url and delete it, you just have to configure the model and success_url fields.
Now if you click on your Delete button, you should expect your desired entry to be deleted and the user to be redirected to the list view.
EDIT:
I forgot that you want to get this entry via options. Here you will have to use some JavaScript in order to find the currently selected element and send it's pk to your DeleteView.
At first, add id's to your option tags, like this:
<select class="form-control" name="settingslist" id="settingslist" form="SettingsListForm">
{% for settings in user.usersetting.all %}
<option value="{{ settings.file.url }}" id="{{ settings.id }}">{{ settings }}</option>
{% endfor %}
</select>
And then add some jQuery:
var settingId = $('#SettingsListName').find(":selected").attr('id');
In the end, you need to send settingId to the corresponding url, but I am not very familiar with JavaScript.
Try putting a hidden input in your form. Right now, nothing is passing through the form.
<input type="hidden" name="del_setting" value="{{user.usersetting.last.id}}">
So your form would look like this
<form method="POST">
{% csrf_token %}
<input type="hidden" name="del_setting" value="{{user.usersetting.last.id}}">
<button type="submit" class="btn btn-outline-light btn-danger" value="Delete">YES</button>
<a class="btn btn-outline-light btn-default" href="{% url 'login_app:user_detail' pk=user.id %}"><b>NO</b></a>
</form>
You also probably should move this out of the current form in your user detail template so that you're not putting a form within a form:
{% block delete_setting_confirm_block %}
{% endblock %}
None of the previously mentioned solutions would work so I guess the problem is the nested bootstrap select item which is supposed to display the pk of the setting.
For simplicity I then removed the problem by using list-group instead
<ul class="list-group">
{% if user.usersetting.first %}
{% for settings in user.usersetting.all %}
<li class="list-group-item">{{ settings }}<a class="btn btn-outline-light btn-circle" href="{% url 'my_app:setting_delete' pk=settings.pk %}"><i class="glyphicon glyphicon-remove"></i></a></li>
{% endfor %}
<label>Create a new setting...</label>
<a class="btn btn-outline-light btn-circle"><i class="glyphicon glyphicon-plus"></i></a>
{% else %}
<li class="list-group-item">Create a new setting...<a class="btn btn-outline-light btn-circle"><i class="glyphicon glyphicon-plus"></i></a></li>
{% endif %}
{% block delete_setting_confirm_block %}
{% endblock %}
</ul>
As a workaround,this works well.