Django model defining list of URLFields - django-models

I'm pretty new to relational databases and this may be why I'm having this problem but I have a model - Post.
I want it to have variable number of URLs, however Django only seems to have the OneToManyField which requires a model (not a field - which URLField is).

In relational database design, the fields in a table are always scalar values. in your case, such a field would 'a url'. The way you get a collection to apply to a row, you join that row with the rows of another table. In django parlance, that would mean that you need two models, one for the Post objects, and another that links multiple urls with that post.
class Post(models.Model):
pass
class Url(models.Model):
url = models.URLField()
post = models.ForeignKey(Post)
myPost = Post.objects.all().get()
for url in myPost.url_set.all():
doSomething(url.url)
Now you can access urls through a urls member
But if you want to get the admin page for Post to also let you add urls, you need to do some tricks with InlineModelAdmin.
from django.db import models
from django.contrib import admin
class Post(models.Model):
pass
class Url(models.Model):
url = models.URLField()
post = models.ForeignKey(Post)
class UrlAdmin(admin.TabularInline):
model = Url
class PostAdmin(admin.ModelAdmin):
inlines = [UrlAdmin]
admin.site.register(Post, PostAdmin)

Related

ManyToManyField is not getting saved in Wagtail Page

I have a subclass of Wagtail Page class that has field of django ManyToManyField type. When I try to create a new instance of my page object, I get a list of objects that the the ManyToManyField points to and I am able select multiple items. However, after creating that page when I try to edit the same page, it seems no data got saved for the ManyToMany field. I know in Django ModelAdmin one have to override the save_related() to save ManyToMany field data. Is there a similar method for the Wagtail Page model?
You should define the field as a ParentalManyToManyField relation, as per the example here: http://docs.wagtail.io/en/v1.13.1/getting_started/tutorial.html#categories
This is a variant of ManyToManyField which is able to keep track of the relation in memory, allowing it to work in situations such as previewing and saving as draft (where it doesn't get saved to the normal database records).
I was able to use the 'after_edit_page' and 'after_create_page' hooks to save the data for the page's ManyToMany fields.

Single piece of content, multiple URLs?

I have a use case that I could use some advice on.
We publish multiple products, each of which has it's own subtree on the site. Generally, a piece of content gets published to just a single product, e.g. a news article gets published to product A and can be accessed at one URL.
However, sometimes we have content that we want to publish to multiple products, e.g. a single news article gets published to products A, B, and C and will be available at 3 different URLs.
With our current CMS we end up doing this by copying and pasting the content, which is a hassle for editors, especially if the content needs to be updated.
An ideal scenario would be where and editor edits the content in one place, specifies the products to publish to, and the content is served by more than one URL and with a template that is product-specific.
It seems that RoutablePageMixin could be useful here, but I'm not sure how to handle letting the editor specify the destination products and making the routing aware of that choice.
Has anyone solved a similar problem using Wagtail?
I have solved a similar problem in Wagtail, the RoutablePageMixin is the key to solving this problem.
If you have /blog/A/slug-product/, /blog/B/slug-product/, /blog/C/slug-product/ , then you can get the slug value slug-product here, then use this value to search the distinct content in your db.
class BlogPage(RoutablePageMixin, Page):
def get_posts(self):
return PostPage.objects.descendant_of(self).live()
#route(r'^(\d{4})/(\d{2})/(\d{2})/(.+)/$')
def post_by_date_slug(self, request, year, month, day, slug, *args, **kwargs):
post_page = self.get_posts().filter(slug=slug).first()
return Page.serve(post_page, request, *args, **kwargs)
As you can see, I did not use the date info of the url but the slug value to get the blog post object, you can follow the pattern here to use regex to match the url you want.
If the slug values in urls are also different, this solution might not work very well, but in most cases, this solution can work fine.
I have written a blog post talking about how to use RoutablePageMixin to make the page routable, you can check this link if you wang to get more about RoutablePageMixin.
Routable Page
Rather than thinking of your news articles as being child objects of one or more products, it might help to think of them as one big pool of news articles which are categorised by product. Your product page will then effectively be a filtered index page of news articles.
Here's how I'd model it:
If you want your news articles to exist at a canonical URL that's independent of any particular category, or you want to make use of page moderation and/or previewing, then define NewsArticle as a page model; otherwise, define it as a snippet or a ModelAdmin-managed model.
On the NewsArticle model, have an InlinePanel where editors can associate as many related products as required:
class NewsArticle(Page):
body = RichTextField()
date = models.DateField()
content_panels = Page.content_panels + [
FieldPanel('body'),
FieldPanel('date'),
InlinePanel('related_products', label="Related products"),
]
class NewsArticleRelatedProduct(Orderable):
news_article = ParentalKey(NewsArticle, related_name='related_products')
product = models.ForeignKey(ProductPage, on_delete=models.CASCADE, related_name='news_articles')
panels = [
PageChooserPanel('product'),
]
On your ProductPage model, add a method that returns a queryset of news items, filtered and sorted appropriately:
class ProductPage(Page):
# ...
def get_news_articles(self):
return self.news_articles.live().order_by('-date')
You can then loop over the news articles in your product page template, using a tag like {% for news_article in page.get_news_articles %}.

Dynamic queryset for foreignKey in Single Page Application with Django

I have a single page application with AngularJs and Django. On my main page, I get all the forms needed when loading the page. BUT, some fields are dynamically updated.
Let's say I have
class Model1(models.Model):
pass
class Model2(models.Model):
model_1 = models.ForeignKey(Model1)
forms:
class Model2Form(forms.ModelForm):
class Meta:
model = Model2
fields = ('model_1', )
My SPA allows me to create instances of Model1 (without reloading the page). I know how to filter the options shown and dynamically add the new instances in the select field BUT, doing so, when the html is first rendered, before angular magic takes place and filter the available options, I get the queryset made by django which is by default model.objects.all(). All right, I'd like to display none of that. I tried to add in the init of my function:
self.fields['model_1'].queryset = Model1.objects.none()
and indeed no option is displayed in the select field when the form is first rendered but then, I can't validate my form, I get the error: Select a valid choice. That choice is not one of the available choices. (obviously, it had no option available due to the queryset.none() )
I'd really like not to load forms when called but doing it when my page first load. Is there any option to help me do so?
Cheers guyz,
Keep rocking
You need to specify that the model_1 field of Model2 can be null, as specified here:
Allow null in foreign key to user. Django
model_1 = models.ForeignKey(Model1, null=True, blank=True, default = None)
I find out how to handle that problem. It is quite stupid, I did not give you all the parameters of the problem.
The forms are rendered on load but when I validate it, it goes through a CRUD operation and an OTHER form is initialized at this point which will handle the data I'm sending. So I can override the queryset in the init of that (second) form based on some extra kwargs to differentiate between the form I'm using for the first rendering and the form to handle my data.
No need to make any field nullable or add extra validation.
Hope I'm clear enough. Cheers

Django, relate User with another table

So I got the tables you can see in the image below:
.
What I would like to do is to create a relationship so that each user (of django auth_user) will be enrolled(or able to enrol) to exactly one "course" so that he will be able to see next events for his modules.
Do I have to create another table and place 2 foreign keys or this is a way to do it in 'php' and it's more simple with Django? I was suggested to create 'student' model inheriting from 'User' with extended behavior and one to many relationship on auth. I tried to do that but unfortunately had not results since I'm really new to Django & Python.
If every auth_user (or auth.User) will be or have the opportunity to be enrolled on a course I would create a 'user profile' model that has a 1-to-1 relationship with the django User model. You can store additional User data in this model, including what course they are enrolled on. See https://docs.djangoproject.com/en/dev/topics/auth/customizing/#extending-the-existing-user-model for more details but here is an example:
class UserProfile(models.Model):
user = models.OneToOneField('auth.User')
course = models.ForeignKey('courseapp.Course', null=True)
You would probably need to create a signal that gets fired each time an auth.User object is saved, such that if it is the first time that User object has been saved, it automatically creates the UserProfile:
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from yourusersapp.models import UserProfile
def create_user_profile(sender, instance, created, **kwargs):
# Automatically creates a UserProfile on User creation.
if created:
UserProfile.objects.create(user=instance)
post_save.connect(create_user_profile, sender=User)
When you query a User object, you can then reference the User object's profile like:
user_object.userprofile
You could then create a Course object and link the user_object indirectly via its UserProfile to that Course:
course = Course.objects.create(name='course_name', next_field='whatever')
user_profile = user_object.userprofile
userprofile.course = course
userprofile.save()
Now you have a user object with a UserProfile that is linked to only 1 course. Many users can be on the same course, but a user can only be on 1 course. You can also reference all users on a particular course like:
course = Course.objects.get(name='course_name')
course_users = course.userprofile_set.all()
HTH
I think that you can go about this one of two ways.
Extend the User model. 'Student' would probably be a good name for your new model. It would have a OneToOne relationship with 'User', and a ForeignKey relationship with 'Course'. It can store any other information that is applicable to students only. Documentation for how to do that can be found here https://docs.djangoproject.com/en/1.6/topics/auth/customizing/#extending-the-existing-user-model
Create a custom User model that has a ForeignKey relationship with Course. This approach is a bit more complicated, but yields a slightly cleaner end result. Documentation for that is here. https://docs.djangoproject.com/en/1.6/topics/auth/customizing/#substituting-a-custom-user-model
Sorry if it seems like I'm just sending you to the Django docs, but both of those sections are well written and should explain things pretty clearly. If you'd like to post another question with example code we can try and see why your original attempt at extending the User model didn't work. By the way, your "Student" model shouldn't have to inherit from the User model in order to extend it.

Tastypie ModelResource fields based on methods

So Tastypie automatically generates the fields based on the fields of your Django Model (if you use ModelResource). I would like to use some methods from my Model as fields in the Resource. Is there a good way to do this in Tastypie? I know it's possible to do it using hydrate but that seems a bit hackish.
Try this:
class UserCharField(ModelResource):
stuff = fields.CharField(attribute='get_stuff_method', readonly=True)
class Meta:
queryset = User.objects.all()

Resources