matching django url with views using a model slug - django

my problem is that I can not establish a reverse match, most likely doing something wrong with my url definition (?). Ultimately what I am trying to do is the following:
User selects 2 location points which the 'new_pointview' view, saves into a DB. I also define a unique slug which contains location information and save it to the DB via the save() within the model. Then the user should be redirected to a url (pointview view) which uses the slug I created in the previous step i.e /pointview/slug. Here is the code:
models.py
class Points(models.Model):
starting_point_longitude = models.FloatField(null=True)
starting_point_latitude = models.FloatField(null=True)
ending_point_longitude = models.FloatField(null=True)
ending_point_latitude = models.FloatField(null=True)
url = models.SlugField(max_length=250, null=True, unique=True, blank=False)
def save(self, *args, **kwargs):
self.url = 'start_lon-{0}-start_lat-{1}-end_lon-{2}-end_lat-' \
'{3}'.format(self.starting_point_longitude,
self.starting_point_latitude,
self.ending_point_longitude,
self.ending_point_latitude)
super(Points, self).save(*args, **kwargs)
def get_absolute_url(self):
return reverse('pointview', kwargs={'url': self.url})
views.py
def pointview(request, url):
point = get_object_or_404(Points, url=url)
content = {'starting_point_longitude':
point.starting_point_longitude,
'starting_point_latitude':
point.starting_point_latitude,
'ending_point_longitude':
point.ending_point_longitude,
'ending_point_latitude':
point.ending_point_latitude}
return render(request, 'points.html', {'user_bundle': content})
def new_pointview(request):
Points.objects.create(
starting_point_longitude=request.POST['starting_point_longitude'],
starting_point_latitude=request.POST['starting_point_latitude'],
ending_point_longitude=request.POST['ending_point_longitude'],
ending_point_latitude=request.POST['ending_point_latitude'],
)
points_filtered = Points.objects.filter(
starting_point_longitude=request.POST[
'starting_point_longitude']).filter(
starting_point_latitude=request.POST[
'starting_point_latitude'])
unique_url = points_filtered.values()[0]['url']
return redirect('/pointview/{0}/'.format(unique_url))
urls.py
urlpatterns = [
path(r'^pointview/(?P<url>[-\w]+)/$', views.pointview, name='pointview'),
path('^new_pointview/', views.new_pointview, name='new_pointview'),
]
The error:
The current path, pointview/start_lon-738949.9146592747-start_lat--153698.8751025315-end_lon-759997.8063993475-end_lat--168467.65638300427/, didn't match any of URL patterns. Hope you can give me some feedback here..

For future reference, it was a regex problem, using the following non intuitive regex solved it:
url('^pointview/(?P<url>start_lon[--W]+start_lat[--W]+end_lon[--W]+end_lat[--W]+)/', views.pointview, name='pointview')
I would be very interesting though if someone can give a more elegant solution.

Related

change my url from depending on id to title | django

I've a url for checking books by its id:
path('book/<int:book_id>', views.book, name='book'),
view:
def book(request, book_id):
book = get_object_or_404(Book, pk=book_id)
context = {
'book': book
}
return render(request, 'media/book.html', context)
but my client asked me to change it for the title instead but I tried it and it didn't seem to work, there are no examples for it in the docs either.
The NOTE in the answer above does not take SEO into account. For SEO purposes, it is much better to have a url that includes the name of the book rather than just the ID. If you are already in production, then remember to do a permanent redirect in your view from all ID-based urls to the slug-based url. Your Book model definition (or Product or whatever you've called it) should include a slugified field:
class Book(models.Model):
name = models.CharField(...)
slug = models.CharField(max_length=255, default='', unique=True, blank=True)
other_fields...
def save(self, *args, **kwargs):
# Create slug for SEO
#Don't ever change once established since is part of the URI
if self.slug is None or self.slug == '':
self.slug = slugify(self.name)
super(Book, self).save(*args, **kwargs)
You need to change the url to 'book/<str:book_title>', and also adjust your function accordingly:
def book(request, book_title):
book = get_object_or_404(Book, yourfieldfortitle=book_title)
...
It might be helpful to try accessing the url first with a pattern that you know must work. NOTE: this makes the strong assumption that a book is identified by its title, otherwise using the primary key is the proper way even if it doesn't "look nice" as a url.

Django - get_redirect_url() causes Page not found (404)

I'm trying to implement favorite feature so that user can choose favorite stores. I'm currently referencing the video https://www.youtube.com/watch?v=pkPRtQf6oQ8&t=542s and stuck with the beginning.
When I try to move to the url https://www.fake-domain.com/my-domain/like, it throws the error message saying No Store matches the given query. So, I guess self.kwargs.get("domainKey") this snippet seems to throw the error, but I don't know why.
I'm not sure if I'm showing my codes enough, so please let me know I need to show more.
models.py
class Store(models.Model):
...
domainKey = models.CharField(max_length=100)
likes = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True)
...
urls.py
url(r'^(?P<store_domainKey>.*)/$', views.detail, name='detail'),
url(r'^(?P<store_domainKey>.*)/like/$', views.StoreLikeRedirect.as_view(), name='like'),
views.py
class StoreLikeRedirect(RedirectView):
def get_redirect_url(self, *args, **kwargs):
store_domainKey = self.kwargs.get("domainKey")
print(store_domainKey)
obj = get_object_or_404(Store, pk='store_domainKey')
return obj.get_absolute_url()
--------------------------------EDIT------------------------------
Revised the codes based on the feedback, but still not working.
When I typed the url, the terminal says the following:
None <-- this is shown by print(store_domainKey) in views.py
Not Found: /down-east/like/
Since the print function in views.py prints None, I think there's something wrong on the line store_domainKey = self.kwargs.get("domainKey"). The part self.kwargs.get() seems not working. In the example video at the top of the post, the guy used SlugField(), but I used CharField() for my domainKey. Can it be an issue to use self.kwargs.get()?
views.py
class StoreLikeRedirect(RedirectView):
def get_redirect_url(self, *args, **kwargs):
store_domainKey = self.kwargs.get("domainKey")
print(store_domainKey)
obj = get_object_or_404(Store, domainKey=store_domainKey)
return obj.get_absolute_url()
urls.py
url(r'^(?P<store_domainKey>.*)/like/$', views.StoreLikeRedirect.as_view(), name='like'),
url(r'^(?P<store_domainKey>.*)/$', views.detail, name='detail'),
models.py
class Store(models.Model):
...
domainKey = models.CharField(max_length=100)
likes = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True)
...
def get_absolute_url(self):
return reverse('boutique:detail', kwargs={"domainKey":self.domainKey})
----------------------------2nd Update-----------------------------
So, now self.kwargs.get("domainKey") returns the domain key very well!
but having
NoReverseMatch at /down-east/like/
Reverse for 'detail' with arguments '()' and keyword arguments '{'domainKey': 'down-east'}' not found. 1 pattern(s) tried: ['(?P<store_domainKey>.*)/$']
In your view you are using a string instead of the variable you created. And you probably need to filter on the field domainKey instead of pk.
Try changing
obj = get_object_or_404(Store, pk='store_domainKey')
to
obj = get_object_or_404(Store, domainKey=store_domainKey)

Conflicting Django URL's

I have been chopping away at this for a few days with no clue as to why its not working. I have two views, one to list tools and one to list parts. I also have the list and detail URL's for both. Both list views work and the tool detail view works, but when I click on a part item to see the detail, the correct url appears in the browser, but I get an error shown in the screenshot below, which as you can see is trying to use the tool_detail view. Thank you for looking.
Here is my code for review:
url:
from .views import tool_list, part_list, tool_detail, part_detail
urlpatterns = [
url(r'^products/tools/$', tool_list, name='tool_list'),
url(r'^products/(?P<category>[^\.]+)/(?P<slug>[^\.]+)/$', tool_detail, name='tool_detail'),
url(r'^products/parts/$', part_list, name='part_list'),
url(r'^products/(?P<category>[^\.]+)/(?P<slug>[^\.]+)/$', part_detail, name='part_detail'),
]
view:
def tool_list(request):
tools = Tool.objects.prefetch_related('uploads').all()
return render(request, 'tool_list.html', {'tools': tools})
def tool_detail(request, **kwargs):
tool = get_object_or_404(Tool, slug=kwargs.get('slug'))
return render(request, 'tool_detail.html', {'tool': tool})
def part_list(request):
parts = Part.objects.prefetch_related('uploads').all()
return render(request, 'part_list.html', {'parts': parts})
def part_detail(request, **kwargs):
part = get_object_or_404(Part, slug=kwargs.get('slug'))
return render(request, 'part_detail.html', {'part': part})
models
class Part(Timestamp):
model_number = models.ForeignKey(ModelNumber, related_name='part_model_number')
category = models.ForeignKey(Category, related_name='part_category')
price = models.DecimalField(max_digits=10, decimal_places=2)
title = models.CharField(max_length=250)
slug = models.SlugField(help_text="slug-title-should-be-like-this")
...
class Tool(Timestamp):
model_number = models.ForeignKey(ModelNumber, related_name='tool_model_number')
price = models.DecimalField(max_digits=10, decimal_places=2)
title = models.CharField(max_length=250)
slug = models.SlugField(help_text="slug-title-should-be-like-this")
category = models.ForeignKey(Category, related_name='tool_category')
...
The first url pattern that matches is what Django will use to dispatch to a view. The 2nd url matches, so it's using the tool_detail view.

django modeltranslation 404

I'm trying to set up my app in two languages, however I'm getting 404 error on all app's urls, even though I've set up another app a while ago the exact same way.
models.py:
class New(models.Model):
title = models.CharField(max_length=300)
slug = models.SlugField(max_length=300, editable=False)
pub_date = models.DateTimeField(auto_now_add=True)
text = models.TextField()
def __unicode__(self):
return self.title
def save(self, *args, **kwargs):
if not self.id:
# Newly created object, so set slug
self.slug = slugify(self.title)
super(New, self).save(*args, **kwargs)
translation.py:
class NewTranslationOptions(TranslationOptions):
fields = ('title','text')
translator.register(New, NewTranslationOptions)
urls.py:
urlpatterns += i18n_patterns('',
url(r'^categories/$', 'products.views.categories_index', name='categories_index'),
url(r'^(?P<category_slug>[\w-]+)/$', 'products.views.specific_category', name='specific_category'),
url(r'^(?P<category_slug>[\w-]+)/(?P<product_slug>[\w-]+)/$', 'products.views.specific_product', name='specific_product'),
url(r'^news/$', 'news.views.news_index', name='news_index'),
url(r'^news/(?P<news_slug>[\w-]+)/$', 'news.views.specific_new', name='specific_new'),
)
Here you can also see urls of my other app products, it works just fine. If you need anything else please let me know.
Your specific_category and specific_product url patterns are catching urls from news app:
>>> re.match("(?P<category_slug>[\w-]+)", "news").groups()
('news',)
Reorder your urls patterns:
urlpatterns += i18n_patterns('',
url(r'^categories/$', 'products.views.categories_index', name='categories_index'),
url(r'^news/$', 'news.views.news_index', name='news_index'),
url(r'^news/(?P<news_slug>[\w-]+)/$', 'news.views.specific_new', name='specific_new'),
url(r'^(?P<category_slug>[\w-]+)/$', 'products.views.specific_category', name='specific_category'),
url(r'^(?P<category_slug>[\w-]+)/(?P<product_slug>[\w-]+)/$', 'products.views.specific_product', name='specific_product'),
)
Or, consider adding category/ prefix to patterns from products app:
url(r'^category/(?P<category_slug>[\w-]+)/$', 'products.views.specific_category', name='specific_category'),
url(r'^category/(?P<category_slug>[\w-]+)/(?P<product_slug>[\w-]+)/$', 'products.views.specific_product', name='specific_product'),

Django filebrowser, model specific directory parameter for FileBrowserField

Using django-filebrowser and the FileBrowserField I am attempting to assign the directory parameter based off a key in the model itself. So using a blog example, if I were saving photos for different posts, the photos would be in directories named after the blog id. So if the MEDIA_ROOT was/some/path/to/media/filebrowser_files/ I wish to dynamically assign the directory paramter to be MEDIA_ROOT+str(model_pk)
At this point I have attempted to do something resembling the following, but do not understand how to obtain the id of the current object. (DoesNotExist exception with "No exception supplied") I know the error exists within the attempt to use self.page, but I do not know how to do this correctly. Could someone provide some insight as to where my logic is flawed and what I can do to fix it? Thanks much.
class PageImage(models.Model):
page = models.ForeignKey(Page)
page_photo = FileBrowseField("Image", max_length=200, blank=True, null=True)
def __init__(self, *args, **kwargs):
super(PageImage, self).__init__(*args, **kwargs)
path = settings.MEDIA_ROOT+'pages/unfiled/'
if self.page:
path = settings.MEDIA_ROOT+'pages/'+str(self.page)+'/'
if not os.path.exists(path):
os.makedirs(path)
self._meta.get_field_by_name("page_photo")[0].directory = path
I realize I didn't look closer at your code. self.page will not work because you're initializing the Model instance and self.page has not been set to a page in the database. You should try instead:
class PageImage(models.Model):
page = models.ForeignKey(Page)
page_photo = FileBrowseField("Image", max_length=200, blank=True, null=True)
def save(self, *args, **kwargs):
path = settings.MEDIA_ROOT+'pages/unfiled/'
if self.page:
path = settings.MEDIA_ROOT+'pages/'+str(self.page)+'/'
if not os.path.exists(path):
os.makedirs(path)
self._meta.get_field_by_name("page_photo")[0].directory = path
super(PageImage, self).save(*args, **kwargs)
doing what you want only after you've assigned a Page to the field in PageImage.