Django admin - Raw Id Input on intermediate page - django

I've have a Topic model in the django admin (v1.6). I'm trying to make an action that takes the queryset and makes the objects aliases of another Topic. This other Topic will be selected in an intermediate page. I am having a hard time understanding how to get the Raw ID input into the intermediate page, and I haven't seen any code like this.
Here are my models
class Topic(models.Model):
name = models.CharField(max_length=200)
slug = models.SlugField(max_length=200, unique=True)
class Alias(models.Model):
name = models.CharField(max_length=200)
slug = models.SlugField(max_length=200, unique=True)
topic = models.ForeignKey(Topic, related_name='aliases')
My admin.py is something like this:
from django.template.response import TemplateResponse
from breakingnews.topics.models import Topic, Alias
class TopicAdmin(admin.ModelAdmin):
def make_alias(self, request, queryset):
if request.POST.get('post'):
# process the queryset here
head = request.POST.get('head')
tail = queryset
for topic in tail:
a, is_new = Alias.objects.get_or_create(name=topic.name, slug=topic.slug, topic=head)
else:
context = {
'title': "To what topic would you like the alias to point?",
'queryset': queryset,
'action_checkbox_name': helpers.ACTION_CHECKBOX_NAME,
}
return TemplateResponse(request, 'admin/make_alias.html',
context, current_app=self.admin_site.name)
add_tag.short_description = "Make these topics an alias to another"
...
actions = [
add_tag,
]
admin.site.register(Topic, TopicAdmin)
And the make_alias.html is this:
{% extends "admin/base_site.html" %}
{% load i18n l10n admin_urls %}
{% block content %}
<p>{% blocktrans %}To what topic would you like the alias to point? {% endblocktrans %}</p>
<ul>{{ queryset|unordered_list }}</ul>
<form action="" method="post">{% csrf_token %}
<div>
<input type="text" name="head" value="" />
{% for obj in queryset %}
<input type="hidden" name="{{ action_checkbox_name }}" value="{{ obj.pk|unlocalize }}" />
{% endfor %}
<input type="hidden" name="action" value="make_alias" />
<input type="hidden" name="post" value="yes" />
<input type="submit" value="Confirm" />
</div>
<!-- <ul>{{ queryset|unordered_list }}</ul> -->
</form>
{% endblock %}

Here's what happened to make it work:
Add this to Admin.py:
from django.template.response import TemplateResponse
from breakingnews.topics.models import Topic, Alias
class AliasCreateForm(forms.ModelForm):
parents = forms.ModelChoiceField(
queryset=Topic.objects.all(),
widget=ManyToManyRawIdWidget(
Topic._meta.get_field('parents').rel, admin.site)
)
class Meta:
model = Topic
fields = ('parents',)
def make_alias(self, request, queryset):
if request.POST.get('post'):
# Handle the response
else:
formset = AliasCreateForm()
context = {
'title': "To what topic would you like the alias to point?",
'queryset': queryset,
'formset': formset,
'action_checkbox_name': helpers.ACTION_CHECKBOX_NAME,
'action':'make_alias',
}
return TemplateResponse(request, 'admin/make_alias.html',
context, current_app=self.admin_site.name)
make_alias.short_description = "Make these topics an alias to another"
And make_alias.html:
{% extends "admin/base_site.html" %}
{% load i18n l10n admin_urls %}
{% block extrahead %}
<script type="text/javascript" src="/static/admin/js/admin/RelatedObjectLookups.js"></script>
{% endblock %}
{% block content %}
<form action="" method="post">{% csrf_token %}
<ul>{{ queryset|unordered_list }}</ul>
{{ formset }}
<br /><br />
{% for obj in queryset %}
<input type="hidden" name="{{ action_checkbox_name }}" value="{{ obj.pk|unlocalize }}" />
{% endfor %}
<input type="hidden" name="action" value="{{action}}" />
<input type="hidden" name="post" value="yes" />
<input type="submit" value="Submit" />
</form>
{% endblock %}

Related

pass data to form filed in django templae

How can I pass data to form fields in django templat ? , for example I have below code in my project:
<td class="col-3">
{{form.number|as_crispy_field}}
</td>
Can I use
<td class="col-3">
{{form.number}} = 10
</td>
in django template ?
#mosi -
<td class="col-3">
{{form.number}} = 10
</td>
No, you cannot use this. If you are planning to pass data from views to template then do something like this
Let's say you have a form something like this
forms.py
from django import forms
class ContactForm(forms.Form):
name = forms.CharField(max_length=30)
email = forms.EmailField(max_length=254)
views.py
def home(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
pass # your logic here
else:
form = ContactForm()
return render(request, 'home.html', {'form': form})
template.html
<form method="post" novalidate>
{% csrf_token %}
{{ form.name }}
{{form.email}}
<button type="submit">Submit</button>
</form>
OR
Simply
<form method="post" novalidate>
{% csrf_token %}
{{ form }}
<button type="submit">Submit</button>
</form>
Now, if you want to set initial values to your form in template
Lets say you have the following
class ContactForm(forms.Form):
name = forms.CharField(max_length=30,initial='test')
Then in your template you do something like this
<form method="post" novalidate>
{% csrf_token %}
<input type="text" name="name" id="name" value="{{ form.name.value }}">
<button type="submit">Submit</button>
</form>
Now, in case of an UpdateView where data is pulled in dynamically from the Database based on let's say product id. The following is just an example
class ProductForm(forms.ModelForm):
class Meta:
model = Product
exclude = (
"created_by",
"slug",
)
class ProductUpdateView(UpdateView):
# specify the model you want to use
model = Product
form_class = ProductForm
template_name = "catalog/product/update_product.html"
product_update.html
<form method="post" enctype="multipart/form-data">
<div class="card-body">
{% csrf_token %}
{{ form.as_p}}
<button type="submit" class="btn btn-primary">Update</button>
</div>
</form>
Or
<form method="post" enctype="multipart/form-data">
<div class="card-body">
{% csrf_token %}
<input type="text" name="name" id="name" value="{{ form.name.value }}">
<input type="text" name="description" id="description" value="{{ form.description.value }}">
.........
<button type="submit" class="btn btn-primary">Update</button>
</div>
</form>

How add follow button to profile in django getstream

I try to add follow button in django with Getstream.io app.
Following the getstream tutorial, django twitter, I managed to create a list of users with a functioning follow button as well as active activity feed. But when i try add follow button on user profile page, form send POST but nothing happends later.
I spend lot of time trying resolve this, but i'm still begginer in Django.
Code:
Follow model:
class Follow(models.Model):
user = models.ForeignKey('auth.User', related_name = 'follow', on_delete = models.CASCADE)
target = models.ForeignKey('auth.User', related_name ='followers', on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add = True)
class Meta:
unique_together = ('user', 'target')
def unfollow_feed(sender, instance, **kwargs):
feed_manager.unfollow_user(instance.user_id, instance.target_id)
def follow_feed(sender, instance, **kwargs):
feed_manager.follow_user(instance.user_id, instance.target_id)
signals.post_delete.connect(unfollow_feed, sender=Follow)
signals.post_save.connect(follow_feed, sender=Follow)
Views:
def user(request, username):
user = get_object_or_404(User, username=username)
feeds = feed_manager.get_user_feed(user.id)
activities = feeds.get()['results']
activities = enricher.enrich_activities(activities)
context = {
'user': user,
'form': FollowForm(),
'login_user': request.user,
'activities': activities,
}
return render(request, 'profile/user.html', context)
def follow(request):
form = FollowForm(request.POST)
if form.is_valid():
follow = form.instance
follow.user = request.user
follow.save()
return redirect("/timeline/")
def unfollow(request, target_id):
follow = Follow.objects.filter(user=request.user, target_id=target_id).first()
if follow is not None:
follow.delete()
return redirect("/timeline/")
Forms:
class FollowForm(ModelForm):
class Meta:
exclude = set()
model = Follow
Urls:
path('follow/', login_required(views.follow), name='follow'),
path('unfollow/<target_id>/', login_required(views.unfollow), name='unfollow'),
And user.html
<form action="{% if request.user in User.followers.all %}{% url 'unfollow' target.id %}{% else %}{% url 'follow' %}{% endif %}" method="post">
{% csrf_token %}
<input type="hidden" id="id_target" name="target" value="{{target.id}}">
<input type="hidden" id="id_user" name="user" value="{{user.id}}">
<button type="submit" class="btn btn-primary btn-sm" value="Create" />
{% if request.user in User.followers.all %}
Unfollow
{% else %}
Follow
{% endif %}
</button>
</form>
This form work in list user page:
{% for one, followed in following %}
<div class="col-md-3 col-sm-6 col-xs-12">
<div class="card">
<div class="card-body">
{% include "profile/_user.html" with user=one %}
<form action="{% if followed %}{% url 'unfollow' one.id %}{% else %}{% url 'follow' %}{% endif %}" method="post">
{% csrf_token %}
<input type="hidden" id="id_target" name="target" value="{{one.id}}">
<input type="hidden" id="id_user" name="user" value="{{user.id}}">
<button type="submit" class="btn btn-primary btn-sm" value="Create" />
{% if followed %}
Przestań obserwować
{% else %}
Obserwuj
{% endif %}
</button>
</form>
</div>
</div>
</div>
{% if forloop.counter|divisibleby:'4' %}
<div class="clearfix visible-sm-block visible-md-block visible-lg-block"></div>
{% elif forloop.counter|divisibleby:'2' %}
<div class="clearfix visible-sm-block"></div>
{% endif %}
{% endfor %}
</div>
And user list Views.py
def discover(request):
users = User.objects.order_by('date_joined')[:50]
login_user = User.objects.get(username=request.user)
following = []
for i in users:
if len(i.followers.filter(user=login_user.id)) == 0:
following.append((i, False))
else:
following.append((i, True))
login_user = User.objects.get(username=request.user)
context = {
'users': users,
'form': FollowForm(),
'login_user': request.user,
'following': following
}
return render(request, 'uzytkownicy.html', context)

Django Admin Action Confirmation Page

In my Django project I have an admin action which requires an confirmation page. I oriented it on the delete_selected action, but it does not work. Here is what I have.
part of my admin.py
def my_action(modeladmin, request, queryset):
if request.POST.get('post'):
print "Performing action"
# action code here
return None
else:
return TemplateResponse(request, "admin/my_action_confirmation.html")
admin/my_action_confirmation.html
<form action="" method="post">{% csrf_token %}
<div>
<input type="hidden" name="post" value="yes" />
<input type="hidden" name="action" value="my_action" />
<input type="submit" value="Confirm" />
</div>
</form>
This works almost. I get to the confirmation page but if I click "confirm" I just get back to the original page. The part with the action code is never reached. In fact the my_action function isn't called a second time. So how do I tell django, that the my_action function should be called a second time, once I clicked confirm?
Edit: I was more missing then I thought
The corrected my_action
def my_action(modeladmin, request, queryset):
if request.POST.get('post'):
print "Performing action"
# action code here
return None
else:
request.current_app = modeladmin.admin_site.name
return TemplateResponse(request, "admin/my_action_confirmation.html")
admin/my_action_confirmation.html
{% load l10n %}
<form action="" method="post">{% csrf_token %}
<div>
{% for obj in queryset %}
<input type="hidden" name="{{ action_checkbox_name }}" value="{{ obj.pk|unlocalize }}" />
{% endfor %}
<input type="hidden" name="post" value="yes" />
<input type="hidden" name="action" value="my_action" />
<input type="submit" value="Confirm" />
</div>
</form>
admin.py
def require_confirmation(func):
def wrapper(modeladmin, request, queryset):
if request.POST.get("confirmation") is None:
request.current_app = modeladmin.admin_site.name
context = {"action": request.POST["action"], "queryset": queryset}
return TemplateResponse(request, "admin/action_confirmation.html", context)
return func(modeladmin, request, queryset)
wrapper.__name__ = func.__name__
return wrapper
#require_confirmation
def do_dangerous_action(modeladmin, request, queryset):
return 42/0
admin/action_confirmation.html
{% extends "admin/base_site.html" %}
{% load i18n l10n admin_urls %}
{% block bodyclass %}{{ block.super }} app-{{ opts.app_label }} model-{{ opts.model_name }} delete-confirmation
delete-selected-confirmation{% endblock %}
{% block content %}
<p>Are you sure you want to {{ action }}?</p>
<ul style="padding: 0">
{% for object in queryset.all %}
<li style="list-style: none; float: left; margin: 5px">
{{ object }}
</li>
{% endfor %}
</ul>
<hr>
<br>
<form action="" method="post">{% csrf_token %}
<fieldset class="module aligned">
{% for obj in queryset.all %}
<input type="hidden" name="_selected_action" value="{{ obj.pk|unlocalize }}"/>
{% endfor %}
</fieldset>
<div class="submit-row">
<input type="hidden" name="action" value="{{ action }}"/>
<input type="submit" name="confirmation" value="Confirm"/>
<a href="#" onclick="window.history.back(); return false;"
class="button cancel-link">{% trans "No, take me back" %}</a>
</div>
</form>
{% endblock %}
Just in case of anyone wanting to add a confirmation view to something more than an action.
I wanted to make the save of an admin creation view go to a confirmation view. My model was very complex and created a lot of implications for the system. Adding the confirmation view would make sure that the admin was aware of these implications.
The solution would be overriding some _changeform_view method which is called on the creation and the edition.
The full code is here: https://gist.github.com/rsarai/d475c766871f40e52b8b4d1b12dedea2
Here is what worked for me:
Add confirm action method (in admin.py)
from django.template.response import TemplateResponse
def confirm_my_action(modeladmin, request, queryset):
response = TemplateResponse(request,
'admin/confirm_my_action.html',
{'queryset': queryset})
return response
and point to it from your admin model (in admin.py)
class SomeModelAdmin(admin.ModelAdmin):
actions = [confirm_my_action]
Add template, which has a form whose action is pointing to my_action endpoint.
{% extends "admin/base_site.html" %}
{% block content %}
<div id="content" class="colM delete-confirmation">
<form method="post" action="/admin/my_action/">
{% csrf_token %}
<div>
{% for obj in queryset %}
<input type="hidden" name="obj_ids[]" value="{{ obj.pk }}" />
<ul><li>Obj: ">{{obj}}</a></li></ul>
{% endfor %}
</div>
<input type="submit" value="Yes, I'm sure">
No, take me back
</form>
<br class="clear">
<div id="footer"></div>
</div>
{% endblock %}
Add appropriate endpoint (e.g. in urls.py).
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^admin/my_action/', my_action_method),
]

Rewrite form with django forms

I want to rewrite the vote form of the django tutorial polls application. But I can't figure out how to make a radio list for all choices of a question:
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
{% for choice in question.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" />
<label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br />
{% endfor %}
<input type="submit" value="Vote" />
</form>
After a lot of experimenting this was the solution:
#forms.py
class VoteForm(forms.ModelForm):
choice = forms.ModelChoiceField(queryset=None, widget=forms.RadioSelect)
class Meta:
model = Question
exclude = ('question_text', 'pub_date')
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['choice'].error_messages = {
'required': 'No choice selected.',
'invalid_choice': 'Invalid choice selected.'
}
instance = getattr(self, 'instance', None)
if instance:
self.fields['choice'].queryset = instance.choice_set
#vote.html
{% load static %}
<link rel="stylesheet" type="text/css" href="{% static 'polls/css/style.css' %}" />
<h2>{{ question.question_text }}</h2>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
{% if voted %}
<p><strong>Already voted on this question.</strong><p>
{% else %}
<form action="{% url 'polls:vote' question.id %}" method="post">
{% csrf_token %}
{{ form.non_field_errors }}
<div class="fieldWrapper">
{{ form.choice.errors }}
{{ form.choice }}
</div>
<input type="submit" value="Vote" />
</form>
{% endif %}
<p>View results?</p>
#views.py
class VoteView(generic.UpdateView):
template_name = 'polls/vote.html'
model = Question
form_class = VoteForm
def get_queryset(self):
return Question.objects.filter(pub_date__lte=timezone.now()).exclude(choice__isnull=True)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# Check duplicate vote cookie
cookie = self.request.COOKIES.get(cookie_name)
if has_voted(cookie, self.object.id):
context['voted'] = True
return context
def get_success_url(self):
return reverse('polls:results', args=(self.object.id,))
def form_valid(self, form):
choice = form.cleaned_data['choice']
choice.votes = F('votes') + 1
choice.save()
redirect = super().form_valid(form)
# Set duplicate vote cookie.
cookie = self.request.COOKIES.get(cookie_name)
half_year = timedelta(weeks=26)
expires = datetime.utcnow() + half_year
if cookie and re.match(cookie_pattern, cookie):
redirect.set_cookie(cookie_name, "{}-{}".format(cookie, self.object.id), expires=expires)
else:
redirect.set_cookie(cookie_name, self.object.id, expires=expires)
return redirect

haystack on existing template

How to implement working SearchView in existing views.py?
I already have CBV, and added in urls.py as /moderate and want to apply search form in it. but always got "Results No results found."
This is my /moderate page with 3 forms, using SearchView and piece of code from tutorial in template.
And this from /search page, with urls(r'^search/$', include('haystack.urls'))
urls.py
urlpatterns= [
url(r'^search/', include('haystack.urls')),
url(r'^moderate/', Moderate.as_view(), name='moderate'),
]
views.py
class Moderate(SearchView):
#method_decorator(staff_member_required)
def dispatch(self, *args, **kwargs):
return super(Moderate, self).dispatch(*args, **kwargs)
#model = Ad
template_name = 'adapp/ad_moderate.html'
#template_name = 'search/search.html'
paginator_class = DiggPaginator
paginate_by = 10
ad_type = None
ad_sub_type = None
def get_queryset(self):
qs = super(Moderate, self).get_queryset().filter(ad_type__isnull=False,
ad_sub_type__isnull=False)
return qs
def get_context_data(self, **kwargs):
context = super(Moderate, self).get_context_data(**kwargs)
context['filter'] = ModerateFilter(self.request.GET)
return context
# define method to recieve fields from form, and change data accordings
def post(self, request, *args, **kwargs):
selected = request.POST['selected']
record = Ad.objects.get(pk=int(selected))
form = ModerateForm(request.POST, instance=record)
if form.is_valid():
form.save(commit=True)
return HttpResponseRedirect('')
template/ad_moderate.html
{% extends 'base.html' %}
{% load i18n url_tags %}
{% block content %}
<div id="casing">
<div id="content">
{# filter form, to show only models with moderated=True #}
<form action="" method="get">
{{ filter.form.as_p }}
<input type="submit">
</form>
<h2>Search</h2>
{# search form right from tutorial #}
<form method="get" action="">
<table>
{{ form.as_table }}
<tr>
<td> </td>
<td>
<input type="submit" value="Search">
</td>
</tr>
</table>
{% if query %}
<h3>Results</h3>
{% for result in page.object_list %}
<p>
{{ result.object.title }}
</p>
{% empty %}
<p>No results found.</p>
{% endfor %}
{% else %}
{# Show some example queries to run, maybe query syntax, something else? #}
{% endif %}
</form>
{% for object in filter %}
{# a lot of template tags and third form to change value of model #}
<form action="" method="POST">
{% csrf_token %}
<input type="radio" name="moderated" value="True">Accept
<br>
<input type="radio" name="moderated" value="False">Decline
<input type="hidden" value="{{ object.id }}"
name="selected">
<input class="btn" type="submit" value="moderate">
</form>
search_indexes.py
from .models import Ad
class AdIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True, use_template=True)
def get_model(self):
# my model, with one search should be
return Ad
templates/search/indexes/app/ad_text.txt
{{ object.title }}
{{ object.short_desc }}
{{ object.description }}
{{ object.experience }}
{{ object.skills }}
{{ object.name }}
{{ object.city }}
get_context_data():
context['search'] = SearchForm(self.request.GET).search()
Would solve a problem.
That means, I should create form and send return from .save() method, rather that django-like form instance.