Using URL in Django Views? Possible? - python

I have content = 'Please get me the Python book you talked about, #friend'
Then this in my views.py:
new_content = re.sub(r'(#\w+)', r"<a href='#'>\g<0></a>>", content)
This returns
new_content = 'Please get me the Python book you talked about, <a href='#'>#friend</a>'
I want if a user clicks of #friend, it should redirect to this url:
url(r'^user/(?P<user_name>\w+)/$', views.profile, name='profile'),
How do I include this url(profile) in #{{user.username}}?

You use reverse()
return HttpResponseRedirect(reverse('url_name'))
You can check this answer for reference.
And the documentation for the function.
You may need to pass arguments. You can do it like this:
reverse('profile', kwargs={'user_name': 'auth'})
For your case you can try:
content = 'Please get me the Python book you talked about, #friend'
new_content = re.sub(r'(#\w+)', r"<a href='%s'>\g<0></a>>" % (reverse('profile', kwargs={'user_name': 'friend_username'})), content)

You already named argument it's user_name
# urls.py
url(r'^user/(?P<user_name>\w+)/$', views.profile, name='profile'),
# views.py
from django.views.generic.detail import DetailView
class UserDetailView(DetailView):
"""
Takes keyword argument 'user_name'
and looks for it in database:
User.objects.get(username='dude')
"""
model = User
slug_field = 'username'
context_object_name = 'user'
slug_url_kwarg = 'user_name'
template_name = 'user_detail.html'
# Pass your keyword argument
#{{ user.username }}

Related

How to resolve Profile matching query doesnot exist error in django

I am new to Django framework. This problem "profile matching query does not exist" comes and I don't understand where this problem is generating from. Please Let me know what else code is needed to resolve this error. I will update this question.
profile matching query does not exist
!["profile matching query does not exist"](https://i.stack.imgur.com/YfHio.png)
I have rechecked the code in urls.py, views.py, index file. But I could not resolve this.
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('',views.index, name = 'index'),
path('signup',views.signup, name = 'signup'),
path('signin',views.signin, name = 'signin'),
path('logout',views.logout, name = 'logout'),
path('settings',views.settings, name = 'settings'),
path('upload',views.upload, name = 'upload'),
]
views.py -> index
#login_required(login_url='signin')
def index(request):
user_object = User.objects.get(username=request.user.username)
user_profile = Profile.objects.get(user=user_object)
return render(request, 'index.html', {'user_profile':user_profile})
OK, so, it looks as though you don't have a Profile record associated with the User object.
def index(request):
user_object = User.objects.get(username=request.user.username)
user_profile = Profile.objects.get(user=user_object)
You need to check the value of user_object before looking for the profile, though pretty sure this is OK, then handle that Profile.objects.get if it doesn't actually find an associated Profile record.
You could do this by
try:
user_profile = Profile.objects.get(user=user_object)
except Profile.DoesNotExist:
... handle the error here
Alternatively, you could use the get_object_or_404 method, which would redirect you to your 404 page if it didn't find a record.
https://docs.djangoproject.com/en/4.1/topics/http/shortcuts/#get-object-or-404

Django 3.0.8 URL/Template/Routing Troubles "No reverse match"

first post so please forgive my ignorance as this is my first django app.
I am trying to create a template that displays all of the information regarding a specific "Ticket" from a list of all open tickets.
Unfortunately I am receiving following message whenever I attempt to add an anchor with a template url tag:
NoReverseMatch at /tickets/tasks/ Reverse for 'order' with arguments
'('',)' not found. 1 pattern(s) tried:
['tickets/order/(?P<ticket_id>[^/]+)/$']
Error message updated. Please see Update below.
And it is ONLY on this one HTML Template.
Below is all of the code I believe will be able to shed some light into the issue:
models.py:
from django.db import models
# Create your models here.
class Ticket(models.Model):
"""A basic support ticket"""
# User ticket title.
ticket_Name = models.CharField(max_length=50)
# When the request was submitted.
ticket_Submitted = models.DateTimeField(auto_now_add=True)
#Ticket Type
ticketTypeChoices=[
('Update', 'Article Edit/Update'),
('Addition', 'New Content/Article Request'),
('Typo', 'Article Typo/Formatting Issue'),
('Issue', 'Website Error/Issue'),
('Other', 'Other'),
]
# Type of ticket (Update, Addition, Typo, Site Issue)
ticket_Type = models.CharField(
max_length=50,
choices=ticketTypeChoices,
default= 'Other'
)
# Users Name
ticket_Contact = models.CharField(max_length=50)
# User Email (for follow up)
ticket_Email = models.EmailField(max_length=254)
# Article URL (if applicable)
ticket_URL = models.CharField(blank=True, max_length=254)
# User description of the issue.
ticket_Description = models.TextField()
#Ticket Status Choices
StatusChoices = [
('Pending', 'Pending'),
('Open', 'Open'),
('Complete', 'Complete'),
('Deferred', 'Deferred'),
('Awaiting Response', 'Awaiting Response'),
]
# Status of the Ticket
ticket_Status = models.CharField(
max_length=50,
choices=StatusChoices,
default= 'Pending'
)
# Comments from HelpDesk Staff
ticket_Comments = models.TextField(blank=True )
#Shows when the ticket was last saved.
ticket_Last_Updated = models.DateTimeField(auto_now=True)
def __str__(self):
"""Return a string representation of the model"""
return self.ticket_Name
views.py:
# Imports Models from the app
from . models import *
# Imports from the Forms List
from . forms import TicketForm
# Create your views here.
# View of all active tickets
def ticket(request):
tickets = Ticket.objects.all().order_by('-ticket_Submitted')
context = {'ticket': tickets}
return render(request, 'tickets/joblist.html', context)
# User can view details about a Ticket
def order(request, ticket_id):
order = Ticket.objects.get(id=ticket_id)
context= {'order': order}
return render(request, 'tickets/tix.html', context)
urls.py
from django.urls import path,include
from . import views
app_name='tickets'
urlpatterns = [
# Include default auth urls.
path('', include('django.contrib.auth.urls')),
# Support Ticket Form
path('submit/', views.submit, name='submit'),
# Contact Us Form
path('contact/', views.contact, name='contact'),
# TicketWeblist
path('tasks/', views.ticket, name='tasks'),
# Ticket Details
path('order/<str:ticket_id>/', views.order, name='order' )
]
Template (joblist.html):
{% for tickets in ticket %}
<tr>
<td>{{tickets.ticket_Name}}</td>
<td>{{tickets.ticket_Type}}</td>
<td>{{tickets.ticket_Contact}}</td>
<td>{{tickets.ticket_Status}}</td>
<td>{{tickets.ticket_Submitted}}</td>
<td>{{tickets.ticket_Last_Updated}}</td>
<td><a class="btn btn-sm btn-info" href="{% url 'tickets:order' ticket.id %}">View</a>
</tr>
{% endfor %}
After reviewing the code a dozen time, all I can be sure of is that is an issue that begins with the template anchor template url tag. (View) but no matter what format I try it comes up with this or a similar error.
UPDATE: At Mel's suggestion changed the url 'order' to 'tickets:order' and am now receiving the following message:
NoReverseMatch at /tickets/tasks/ Reverse for 'order' with arguments
'('',)' not found. 1 pattern(s) tried:
['tickets/order/(?P<ticket_id>[^/]+)/$']
I have been attempting to resolve this issue for about three days and was determined to solve it myself. Any type of help is appreciated and please feel free to point out any spaghetti code or lack of notes as well as I am looking for ways to grow.
Thanks!
You've set a namespace for your urls: app_name = 'tickets'
So correct reverse url would be.
{% url 'tickets:order' tickets.id %}
Can you try changing your order view function to this -
def order(request, ticket_id):
active_order = Ticket.objects.get(id=ticket_id)
context= {'order': active_order}
return render(request, 'tickets/tix.html', context)
You have created a separate urls.py for you app (it looks like it), so be sure to include namespace = tickets in your project urls.py file. And then in your template, you should do as follows:
{% url 'tickets:order' ticket.id %}
In other words, you need to include the name of the app as well.
I just saw that you are passing ticket.id from your template to the view, however there is no ticket.id anywhere in the code. Why don't you try passing a value that is there in the template. It should work.

How to connect Detail Class Based View to Template URL Mapping?

How to connect Detail Class Based View to Template URL Mapping?
Here is views.py file in myapp:
class ModelDetailView(DetailView):
model = models.mymodel
template_name = 'mymodel_detail.html'
Here is urls.py of myapp
.....path('<pk>', ModelDetailView.as_view(), name = 'detail')...........
Here is mymodel_detail.html file:
........<li>{{ object.title }}</li>.......
I want that when I click on object.title, it leads me to its detailed view? How do I do that?
Have also tried: (urls.py)
path('(?P<pk>[-\W]+)/', ModelDetailView.as_view(), name = 'detail')
and
path('detail<pk>', ModelDetailView.as_view(), name = 'detail'),
path('detail/<int:pk>/', ModelDetailView.as_view(), name ='detail'),

Django Slug raising error NoReverse Match

I am working on a django project(Django v2.0) which has users from different groups, this group is set up within the user profile. I would like to make the website more personal and have the user's group at the start of the website's url (added in through a slug), after they login.
Ideally once they login they would then be redirected to the right page with that slug at the beginning of the url. Within the login page I access the user's group, this group is called and will from now on be referred to as troop, to minimise confusion with Django groups. Here's my login class post view where I retrieve this:
def post(self, request):
def normal_user(user):
return user.groups.filter(name='Normal_User').exists()
username = request.POST['username']
password = request.POST['password']
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
if normal_user(user):
redirecting_url = 'accounts:home'
elif user.is_superuser:
redirecting_url = 'admin:index'
slug = user.userprofile.troop
return redirect(redirecting_url, slug=slug)
else:
form = AuthenticationForm()
error = True
args = {'form': form, 'error': error}
return render(request, self.template_name, args)
In this case I am trying to access the url "account" which I have called "home" and is in my app "accounts".
My home function in views.py in the app accounts has this code:
def home(request, slug):
args = {'user': request.user}
return render(request, 'accounts/home.html', args)
I do not want to do anything with the slug except display it in the url.
My template view looks like this:
<div class="container">
<br>
<h2><strong>Your Progress:</strong></h2><br>
<h3>
<strong>50% progress</strong>
<div class="progress">
<div class="progress-bar bg-danger progress-bar-striped progress-bar-
animated" role="progressbar" style="width:50%" aria-valuenow="50" aria-
valuemin="0" aria-valuemax="100">50%</div> </div>
</div></h3>
<br><br>
{% endblock %}
I also have a link to 'home' within my navbar and I link it in the similar fashion than the link above, using {% url 'accounts:home' slug = instance.slug %}
I'm currently having the following error:
"NoReverseMatch at /BC/account/
Reverse for 'home' with keyword arguments '{'slug': ''}' not found. 1 pattern(s) tried: ['(?P[-a-zA-Z0-9_]+)/account/$']"
The slug in this case is 'BC'.
My urls.py look like this:
In the root folder:
main_urls = [
path('leaders/admin/', admin.site.urls),
path('account/', include('accounts.urls', namespace='accounts'))
]
urlpatterns = [
path('', include('home.urls', namespace='home_page')),
path('login/', include('login.urls', namespace='login')),
path('<slug:slug>/', include(main_urls))
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
And my urls.py in my accounts app looks something like this:
app_name="accounts"
urlpatterns = [
path('', views.home, name="home")
]
Sorry for the long description, but I've been reading every possible site/video I could find on Django slugs and have not been able to find anything which works yet. Could someone please help me with this problem?
Your regular expression for your url requires the slug to be at least one character long. However, the exception you're getting suggests that the troop name (which is used as the slug named argument) is empty:
Reverse for 'home' with keyword arguments '{'slug': ''}'
If the user isn't required to have a troop, in which case you want to just redirect him to /accounts/ instead of /troop/accounts, I suggest you add a separate URL for just accounts/$, or tweak the regular expression to allow an empty troop.
After poking around my code I found something which works. This is as it seems to be that I should be able to have views which take in a slug argument whilst still working if the slug is empty. To fix this all I did was change the slug part in my view function definitions to **kwargs.
Then I added a varaiable which accessed what the slug was and passed that through my templates for when I have a link.
For example:
def home(request, **kwargs):
slug = request.user.userprofile.troop
args = {'slug_arg': slug}
return render(request, 'accounts/home.html', args)
My links in my templates then look like this: {% url 'accounts:home' slug=slug_arg %}
Edit
I have found that the problem was that during my rendering, I should be able to pass through the slug, and in this case slug=instance.slug was not working and was sometimes coming up as being empty. However if I have it at slug=request.user.userprofile.troop then this works without having to accept an argument from the view.
In having said such, I am unable to do this for the admin site as I do not know how to access the views.py for the admin and thus add the parameter to take in the slug.

How do I add a link from the Django admin page of one object to the admin page of a related object?

To deal with the lack of nested inlines in django-admin, I've put special cases into two of the templates to create links between the admin change pages and inline admins of two models.
My question is: how do I create a link from the admin change page or inline admin of one model to the admin change page or inline admin of a related model cleanly, without nasty hacks in the template?
I would like a general solution that I can apply to the admin change page or inline admin of any model.
I have one model, post (not its real name) that is both an inline on the blog admin page, and also has its own admin page. The reason it can't just be inline is that it has models with foreign keys to it that only make sense when edited with it, and it only makes sense when edited with blog.
For the post admin page, I changed part of "fieldset.html" from:
{% if field.is_readonly %}
<p>{{ field.contents }}</p>
{% else %}
{{ field.field }}
{% endif %}
to
{% if field.is_readonly %}
<p>{{ field.contents }}</p>
{% else %}
{% ifequal field.field.name "blog" %}
<p>{{ field.field.form.instance.blog_link|safe }}</p>
{% else %}
{{ field.field }}
{% endifequal %}
{% endif %}
to create a link to the blog admin page, where blog_link is a method on the model:
def blog_link(self):
return '%s' % (reverse("admin:myblog_blog_change",
args=(self.blog.id,)), escape(self.blog))
I couldn't find the id of the blog instance anywhere outside field.field.form.instance.
On the blog admin page, where post is inline, I modified part of "stacked.html" from:
<h3><b>{{ inline_admin_formset.opts.verbose_name|title }}:</b>
<span class="inline_label">{% if inline_admin_form.original %}
{{ inline_admin_form.original }}
{% else %}#{{ forloop.counter }}{% endif %}</span>
to
<h3><b>{{ inline_admin_formset.opts.verbose_name|title }}:</b>
<span class="inline_label">{% if inline_admin_form.original %}
{% ifequal inline_admin_formset.opts.verbose_name "post" %}
<a href="/admin/myblog/post/{{ inline_admin_form.pk_field.field.value }}/">
{{ inline_admin_form.original }}</a>
{% else %}{{ inline_admin_form.original }}{% endifequal %}
{% else %}#{{ forloop.counter }}{% endif %}</span>
to create a link to the post admin page since here I was able to find the id stored in the foreign key field.
I'm sure there is a better, more general way to do add links to admin forms without repeating myself; what is it?
Use readonly_fields:
class MyInline(admin.TabularInline):
model = MyModel
readonly_fields = ['link']
def link(self, obj):
url = reverse(...)
return mark_safe("<a href='%s'>edit</a>" % url)
# the following is necessary if 'link' method is also used in list_display
link.allow_tags = True
New in Django 1.8 : show_change_link for inline admin.
Set show_change_link to True (False by default) in your inline model, so that inline objects have a link to their change form (where they can have their own inlines).
from django.contrib import admin
class PostInline(admin.StackedInline):
model = Post
show_change_link = True
...
class BlogAdmin(admin.ModelAdmin):
inlines = [PostInline]
...
class ImageInline(admin.StackedInline):
# Assume Image model has foreign key to Post
model = Image
show_change_link = True
...
class PostAdmin(admin.ModelAdmin):
inlines = [ImageInline]
...
admin.site.register(Blog, BlogAdmin)
admin.site.register(Post, PostAdmin)
This is my current solution, based on what was suggested by Pannu (in his edit) and Mikhail.
I have a couple of top-level admin change view I need to link to a top-level admin change view of a related object, and a couple of inline admin change views I need to link to the top-level admin change view of the same object. Because of that, I want to factor out the link method rather than repeating variations of it for every admin change view.
I use a class decorator to create the link callable, and add it to readonly_fields.
def add_link_field(target_model = None, field = '', link_text = unicode):
def add_link(cls):
reverse_name = target_model or cls.model.__name__.lower()
def link(self, instance):
app_name = instance._meta.app_label
reverse_path = "admin:%s_%s_change" % (app_name, reverse_name)
link_obj = getattr(instance, field, None) or instance
url = reverse(reverse_path, args = (link_obj.id,))
return mark_safe("<a href='%s'>%s</a>" % (url, link_text(link_obj)))
link.allow_tags = True
link.short_description = reverse_name + ' link'
cls.link = link
cls.readonly_fields = list(getattr(cls, 'readonly_fields', [])) + ['link']
return cls
return add_link
You can also pass a custom callable if you need to get your link text in some way than just calling unicode on the object you're linking to.
I use it like this:
# the first 'blog' is the name of the model who's change page you want to link to
# the second is the name of the field on the model you're linking from
# so here, Post.blog is a foreign key to a Blog object.
#add_link_field('blog', 'blog')
class PostAdmin(admin.ModelAdmin):
inlines = [SubPostInline, DefinitionInline]
fieldsets = ((None, {'fields': (('link', 'enabled'),)}),)
list_display = ('__unicode__', 'enabled', 'link')
# can call without arguments when you want to link to the model change page
# for the model of an inline model admin.
#add_link_field()
class PostInline(admin.StackedInline):
model = Post
fieldsets = ((None, {'fields': (('link', 'enabled'),)}),)
extra = 0
Of course none of this would be necessary if I could nest the admin change views for SubPost and Definition inside the inline admin of Post on the Blog admin change page without patching Django.
I think that agf's solution is pretty awesome -- lots of kudos to him. But I needed a couple more features:
to be able to have multiple links for one admin
to be able to link to model in different app
Solution:
def add_link_field(target_model = None, field = '', app='', field_name='link',
link_text=unicode):
def add_link(cls):
reverse_name = target_model or cls.model.__name__.lower()
def link(self, instance):
app_name = app or instance._meta.app_label
reverse_path = "admin:%s_%s_change" % (app_name, reverse_name)
link_obj = getattr(instance, field, None) or instance
url = reverse(reverse_path, args = (link_obj.id,))
return mark_safe("<a href='%s'>%s</a>" % (url, link_text(link_obj)))
link.allow_tags = True
link.short_description = reverse_name + ' link'
setattr(cls, field_name, link)
cls.readonly_fields = list(getattr(cls, 'readonly_fields', [])) + \
[field_name]
return cls
return add_link
Usage:
# 'apple' is name of model to link to
# 'fruit_food' is field name in `instance`, so instance.fruit_food = Apple()
# 'link2' will be name of this field
#add_link_field('apple','fruit_food',field_name='link2')
# 'cheese' is name of model to link to
# 'milk_food' is field name in `instance`, so instance.milk_food = Cheese()
# 'milk' is the name of the app where Cheese lives
#add_link_field('cheese','milk_food', 'milk')
class FoodAdmin(admin.ModelAdmin):
list_display = ("id", "...", 'link', 'link2')
I am sorry that the example is so illogical, but I didn't want to use my data.
I agree that its hard to do template editing so, I create a custom widget to show an anchor on the admin change view page(can be used on both forms and inline forms).
So, I used the anchor widget, along with form overriding to get the link on the page.
forms.py:
class AnchorWidget(forms.Widget):
def _format_value(self,value):
if self.is_localized:
return formats.localize_input(value)
return value
def render(self, name, value, attrs=None):
if not value:
value = u''
text = unicode("")
if self.attrs.has_key('text'):
text = self.attrs.pop('text')
final_attrs = self.build_attrs(attrs,name=name)
return mark_safe(u"<a %s>%s</a>" %(flatatt(final_attrs),unicode(text)))
class PostAdminForm(forms.ModelForm):
.......
def __init__(self,*args,**kwargs):
super(PostAdminForm, self).__init__(*args, **kwargs)
instance = kwargs.get('instance',None)
if instance.blog:
href = reverse("admin:appname_Blog_change",args=(instance.blog))
self.fields["link"] = forms.CharField(label="View Blog",required=False,widget=AnchorWidget(attrs={'text':'go to blog','href':href}))
class BlogAdminForm(forms.ModelForm):
.......
link = forms..CharField(label="View Post",required=False,widget=AnchorWidget(attrs={'text':'go to post'}))
def __init__(self,*args,**kwargs):
super(BlogAdminForm, self).__init__(*args, **kwargs)
instance = kwargs.get('instance',None)
href = ""
if instance:
posts = Post.objects.filter(blog=instance.pk)
for idx,post in enumerate(posts):
href = reverse("admin:appname_Post_change",args=(post["id"]))
self.fields["link_%s" % idx] = forms..CharField(label=Post["name"],required=False,widget=AnchorWidget(attrs={'text':post["desc"],'href':href}))
now in your ModelAdmin override the form attribute and you should get the desired result. I assumed you have a OneToOne relationship between these tables, If you have one to many then the BlogAdmin side will not work.
update:
I've made some changes to dynamically add links and that also solves the OneToMany issue with the Blog to Post hope this solves the issue. :)
After Pastebin:
In Your PostAdmin I noticed blog_link, that means your trying to show the blog link on changelist_view which lists all the posts. If I'm correct then you should add a method to show the link on the page.
class PostAdmin(admin.ModelAdmin):
model = Post
inlines = [SubPostInline, DefinitionInline]
list_display = ('__unicode__', 'enabled', 'blog_on_site')
def blog_on_site(self, obj):
href = reverse("admin:appname_Blog_change",args=(obj.blog))
return mark_safe(u"<a href='%s'>%s</a>" %(href,obj.desc))
blog_on_site.allow_tags = True
blog_on_site.short_description = 'Blog'
As far as the showing post links on BlogAdmin changelist_view you can do the same as above. My earlier solution will show you the link one level lower at the change_view page where you can edit each instance.
If you want the BlogAdmin page to show the links to the post in the change_view page then you will have to include each in the fieldsets dynamically by overriding the get_form method for class BlogAdmin and adding the link's dynamically, in get_form set the self.fieldsets, but first don't use tuples to for fieldsets instead use a list.
Based on agfs and SummerBreeze's suggestions, I've improved the decorator to handle unicode better and to be able to link to backwards-foreignkey fields (ManyRelatedManager with one result). Also you can now add a short_description as a list header:
from django.core.urlresolvers import reverse
from django.core.exceptions import MultipleObjectsReturned
from django.utils.safestring import mark_safe
def add_link_field(target_model=None, field='', app='', field_name='link',
link_text=unicode, short_description=None):
"""
decorator that automatically links to a model instance in the admin;
inspired by http://stackoverflow.com/questions/9919780/how-do-i-add-a-link-from-the-django-admin-page-of-one-object-
to-the-admin-page-o
:param target_model: modelname.lower or model
:param field: fieldname
:param app: appname
:param field_name: resulting field name
:param link_text: callback to link text function
:param short_description: list header
:return:
"""
def add_link(cls):
reverse_name = target_model or cls.model.__name__.lower()
def link(self, instance):
app_name = app or instance._meta.app_label
reverse_path = "admin:%s_%s_change" % (app_name, reverse_name)
link_obj = getattr(instance, field, None) or instance
# manyrelatedmanager with one result?
if link_obj.__class__.__name__ == "RelatedManager":
try:
link_obj = link_obj.get()
except MultipleObjectsReturned:
return u"multiple, can't link"
except link_obj.model.DoesNotExist:
return u""
url = reverse(reverse_path, args = (link_obj.id,))
return mark_safe(u"<a href='%s'>%s</a>" % (url, link_text(link_obj)))
link.allow_tags = True
link.short_description = short_description or (reverse_name + ' link')
setattr(cls, field_name, link)
cls.readonly_fields = list(getattr(cls, 'readonly_fields', [])) + \
[field_name]
return cls
return add_link
Edit: updated due to link being gone.
Looking through the source of the admin classes is enlightening: it shows that there is an object in context available to an admin view called "original".
Here is a similar situation, where I needed some info added to a change list view: Adding data to admin templates (on my blog).

Categories

Resources