Comments (14)
Taking a look at option 1, I've run into a small problem: Category is a Page, but Product is not.
So Category has a "fully qualified" slug ("store/hardware") served by a mezzanine view, but Product has a relative slug ("product-1") served by a cartridge view.
Simply joining these almost works, except it only makes sense to do so in shop.urls
, which is presumably rooted at ^store/
-- so the resolved URL becomes store/store/hardware/product-1
. Hrm..
from cartridge.
See above quick-and-dirty hack, which seems to work for my purposes..
from cartridge.
Won't your new urlpattern prevent regular Mezzanine pages from being matched?
from cartridge.
Yes, I suppose it would, for any Page created within the ^store/
url path (and containing another slash). Not an issue in my case but I can certainly see how it might be.
Some possible remedies, all a bit icky:
- In the
category_product
view, add a fallback to lookup and render a matching Page on product slug miss. Suboptimal DB performance for these pages, but maybe enough of a special case not to care.. - Tack something on to product urls, ie match the regex
store/<category_slug>/<product_slug>/detail
. Just reduces the size of the conflicting namespace (to store///detail). This token could be anywhere in the URL, ie store/detail// instead. - Make products Displayable (/Page?). However the category then becomes a static property of the product's slug (no longer changeable); there are probably other good reasons to avoid such a change.
Other ideas...?
from cartridge.
Here's a variation on the second bullet, which on balance doesn't seem very nasty: ac345f4. See the justification there.
from cartridge.
(Bizarre that the commit hash auto-linked & renders within this repo rather than mine. I think this is a github bug, shot it over to support.)
from cartridge.
Firstly I just wanna say that I really do appreciate what you're trying to solve here. I've had the exact same problem in the past with ecommerce sites, and working out what the canonical category is for the sake of a nicer URL, and more importantly for breadcrumb navigation. Interestingly, it's actually a broader problem that comes up in other cases as well, such as news sites where stories can appear in multiple sections of a site.
Let's forget about breadcrumbs for a moment and just think about the URL structure.
I think with all the options you've come up with (which are all really clever, and it's great they actually work), you've basically shown that no matter which way we wrangle this, we're gonna end up with an ugly overall design whereby we end up with multiple code paths for handling the category and product views. Categories are Mezzanine pages - they can pretty much fall under any urlpattern - this is a great feature I think, it allows people to set up site hierarchies however they choose to. But products aren't pages, and I'd argue rightly so - they don't belong in the navigation structure of the site.
So taking Mezzanine pages into account, taking Django urlpatterns into account, and specifically the need for a specific urlpattern that matches products (eg /product/some-slug/), I think the whole idea of trying to include category slugs in the URLs for products really just falls apart. I guess we could somehow have product slugs actually include the slug of their canonical category, but we'd still need the urlpattern prefixed with the unique /product/ part, so we wouldn't end up with perfect URLs anyway.
To top all that off - if someone really wants this, and can actually get this working in the context of their own project, then that's great and I'd totally suggest doing it. Perhaps we can take some of the stuff you've put together here and put it into a separate app, cartridge-canonical-categories or some such. I just think that if we try and implement this in Cartridge itself, it's a slippery slope downward towards corrupting the overall flow of how each of the urlpatterns and views work together. We'd lose a great deal of simplicity at the cost of changing the URLs slightly in some cases. I just don't think it's worth it.
Now for my mind, I think the urlpatterns are of little relative importance when compared to the breadcrumb issue - I think in the case of each product only belonging to single category, having the breadcrumb nav in the product template reflect this would actually be an extremely useful feature. So I'd actually really like to solve that, and I think we can do it in a pretty clean way, clean at least when compared to all the issues that come up with trying to make this happen for URLs.
Not sure what the end result for getting breadcrumbs working might look like - it could be a setting like you described, and that controls in the template whether we use a special template tag that handles rendering the breadcrumbs for a product and its one and only category.
from cartridge.
Thanks for your thoughts! I appreciate the consideration. More inline.
you've basically shown that no matter which way we wrangle this, we're gonna end up with an ugly overall design whereby we end up with multiple code paths for handling the category and product views.
Agreed; I think this is the status quo and not worth changing.
Categories are Mezzanine pages - they can pretty much fall under any urlpattern - this is a great feature I think, it allows people to set up site hierarchies however they choose to. But products aren't pages, and I'd argue rightly so - they don't belong in the navigation structure of the site.
I think I've got my head around the distinction now, thanks.
So taking Mezzanine pages into account, taking Django urlpatterns into account, and specifically the need for a specific urlpattern that matches products (eg /product/some-slug/), I think the whole idea of trying to include category slugs in the URLs for products really just falls apart.
I think I see now.
It specifically breaks down if a Category is rooted outside of the shop, ie, the Category's slug is not a child of / does not begin with shop/
(or wherever cartridge.shop.urls
is rooted). In this case my change borrow's the Category's slug to create shop/<category>/<product>
, for a category that actually lives at anywhere/<category>
-- shop/<category>/
does not exist..
Curious, do you think this is common? Though Categories have all the flexibility of Pages and can be scattered anywhere, do many cartridge sites take advantage of this this? I couldn't find any examples in spot checking a few of the sites on the list: for example, Cotton On (by all accounts an impressively customized site!) seems to use shop/
for all categories.
This issue aside, the resulting logic should be straightforward: A product's URL is either:
shop/product/<product-slug>
-- if the feature is disabled or the product does not correspond to exactly one Category (existing behavior), orshop/<category-slug>/<product-slug>/<product-id>
otherwise.
(I would separately propose tacking product-id
on to the shop/product/<product-slug>
URL, for symmetry and resilience to product slug changes -- but slugs aren't editable, and this orthogonal to the matter at hand.)
I guess we could somehow have product slugs actually include the slug of their canonical category, but we'd still need the urlpattern prefixed with the unique /product/ part, so we wouldn't end up with perfect URLs anyway.
It's probably a bad idea; the product's slug would be brittle in the face of changes to its canonical category.
To top all that off - if someone really wants this, and can actually get this working in the context of their own project, then that's great and I'd totally suggest doing it. Perhaps we can take some of the stuff you've put together here and put it into a separate app, cartridge-canonical-categories or some such.
I do like cartridge's philosophy of intentionally minimizing bundled functionality, though I'm not quite sure how to package this separately (it would no doubt involve monkey-patching Product.get_absolute_url
).. I mean, I can always maintain and deploy from my fork, but that's not why I'm here :-)
We'd lose a great deal of simplicity at the cost of changing the URLs slightly in some cases. I just don't think it's worth it.
Acknowledged. From my perspective -- which is very limited -- perhaps there are at least two broad "styles" of stores that could be supported in cartridge, with slightly different requirements:
- Small stores: those with a limited number of products, and correspondingly limited number of "1-deep" categories. Examples: me!, "The Peculiar Store"
- Large stores: those with large inventories and multivariate Categories, eg {men's, women's} x {shirts, jackets} x {sale, not sale}. Examples: "Adrenaline", "Cotton On".
In my case, I don't ever envision needing (a) categories outside of shop/
, nor (b) products corresponding to more than one category (or nested categories). So achieving descriptive URLs and breadcumbs feels within reach -- though maybe it's a lost cause for larger multi-category operations like "Cotton On".
Now for my mind, I think the urlpatterns are of little relative importance when compared to the breadcrumb issue - I think in the case of each product only belonging to single category, having the breadcrumb nav in the product template reflect this would actually be an extremely useful feature.
I'm certainly fine for separating the issues! The loss of context in the breadcrumbs (for example, on "Adrenaline") once you drill down into a product is jarring. I can live with opaque URLs, but loss of context while browsing my store is what originally sent me down this route..
FWIW and to my surprise, breadcrumbs "just worked" with my change -- the store and category breadcrumbs are correctly displayed and linked on the (category-slugified) product page. I suspect it may break with sub-categories, but I haven't tried. This also relies on the earlier assumption that categories are children of the main shop/ category.
Whew, that was longer than expected, sorry for the verbosity..
[edit: typos]
from cartridge.
FYI: Not adding anything new to the discussion, but here's a consolidated change: 51e5f7d
from cartridge.
Sorry about the delay on this - I'm just giving it a lot of thought. The last commit you linked to is really useful and with everything boiled down into that, I think we're on the right track. We might be able to achieve it even a bit more simply, but still trying to flesh that out in my head :-)
from cartridge.
No worries! I'm on vacation this week, take your time. Glad I at least have you intrigued :)
from cartridge.
FYI (again nothing new, just for illustration) my store is now online with this change: https://kegbot.org/store/
from cartridge.
Rebased change for anyone still following along: 655154c
from cartridge.
will it be included in cartridge, or I should patch it my self?
from cartridge.
Related Issues (20)
- Paypal payment for the current version HOT 1
- New release with the fixes merged in HOT 1
- Translation into Spanish HOT 2
- 'max_digits' must be great or equal to 'decimal_places' on OpenBSD HOT 5
- Screenshots on main page
- Missing migration for mezzanine.core Slugged HOT 2
- Travis checks fail with pip --allow-unverified for pyPdf HOT 1
- django.urlresolvers was moved in Django 1.10 HOT 1
- Travis is not testing current Django builds HOT 1
- Requirements missing from project_template HOT 1
- Duplicate admin order confirmation email sent upon "Re-send order email"
- is it possible to show all products in one page? HOT 1
- Executing management import and export products
- Link to Model Graph in Documentation is broken HOT 2
- Fix simple typo: remaning -> remaining HOT 1
- Stripe integration no longer works HOT 1
- How to remove a checkout field if cart item is from some specific product category
- Security concern HOT 3
- 'Cart' instance needs to have a primary key value before this relationship can be used. HOT 6
- Add online-shop and ecommerce tags to the repository
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from cartridge.