Django url patterns for two related models - django

I have two models (School and Student) with one to many relationship.
my models.py are set as follows:
class School(models.Model):
name = models.CharField(max_length=256)
principal = models.CharField(max_length=256)
location = models.CharField(max_length=256)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse("basic_app:school_detail",kwargs={'pk':self.pk})
class Student(models.Model):
name = models.CharField(max_length=256)
age = models.PositiveIntegerField()
school = models.ForeignKey(School,related_name='students',on_delete=models.CASCADE,default=None)
and the urls.py file will have the following:
urlpatterns = [
url(r'^$',views.SchoolListView.as_view(),name='school_list'),
url(r'^(?P<pk>\d+)/$',views.SchoolDetailView.as_view(),name='school_detail'),
url(r'^create/$',views.SchoolCreateView.as_view(),name='school_create'),
url(r'^update/(?P<pk>\d+)/$',views.SchoolUpdateView.as_view(),name='school_update'),
url(r'^delete/(?P<pk>\d+)/$',views.SchoolDeleteView.as_view(),name='school_delete'),
my question is I want to add to the urlpatterns list more urls for students:something like
#url(r'^$',views.StudentListView.as_view(),name='student_list'),
# url(r'^(?P<pk>\d+)/$',views.StudentDetailView.as_view(),name='student_detail'),
# url(r'^create/$',views.StudentCreateView.as_view(),name='student_create'),
# url(r'^update/(?P<pk>\d+)/$',views.StudentUpdateView.as_view(),name='student_update'),
# url(r'^delete/(?P<pk>\d+)/$',views.StudentDeleteView.as_view(),name='student_delete')
I know my addition is not correct because each group of students should be related to a specific school. I am confused how to use id/pk in the url because for example student_detail.html url should contain both school id and student id.
sorry if this looks naive question.. but I am still learning and any help will be highly appreciated..
thanks

You could add another argument school_pk to the URL pattern, for example:
url(r'^school/(?P<school_pk>\d+)/update/(?P<pk>\d+)/$',views.StudentUpdateView.as_view(),name='student_update'),
Then filter the queryset to only include students from that school.
class StudentUpdateView(UpdateView):
def get_queryset(self):
queryset = super(StudentUpdateView, self).get_queryset()
return queryset.filter(school=self.kwargs['school_pk'])
The UpdateView will take care of fetching the student, because you're still using pk for the student pk.

You need to add 'student(s)' to the urls to make them distinct. You may not need to add school_id to student urls as they are related by ForeignKey
url(r'^students$',views.StudentListView.as_view(),
name='student_list'),
url(r'^student/(?P<pk>\d+)/$',views.StudentDetailView.as_view(),
name='student_detail'),
url(r'^student/create/$',views.StudentCreateView.as_view(),
name='student_create'),
url(r'^student/update/(?P<pk>\d+)/$',views.StudentUpdateView.as_view(),
name='student_update'),
url(r'^student/delete/(?P<pk>\d+)/$',views.StudentDeleteView.as_view(),
name='student_delete')

Related

How to change url path to name in django instead of id

sorry if I ask very a simple question, I'm just starting to learn about WebDev and I have a question about django url and I used rest framework. I have http://localhost:8000/api/projectList/1 and I want to change id to the name in the url, for example http://localhost:8000/api/projectList/project
This is the code:
model.py
class ProjectList(models.Model):
project = models.CharField(max_length=200)
project_name = models.CharField(max_length=200)
category = models.CharField(max_length=200)
academic = models.CharField(max_length=200)
view.py
class ProjectListSerializer(serializers.ModelSerializer):
class Meta :
model = ProjectList
fields = '__all__'
class ProjectListViewset(viewsets.ModelViewSet):
queryset = ProjectList.objects.all()
serializers_class = ProjectListSerializer
class ProjectListListView(generics.ListAPIView):
serializer_class = ProjectListSerializer
def get_queryset(self):
return ProjectList.objects.all()
class ProjectId(generics.RetrieveUpdateDestroyAPIView):
queryset = ProjectList.objects.all()
serializer_class = ProjectListSerializer
urls.py
urlpatterns = [
path("", include(router.urls)),
path("projectList/", ProjectListListView.as_view()),
path("projectList/<int:pk>", ProjectId.as_view()),
]
Thank you, sorry for my simple question and my bad English.
Django Rest Framework ModelViewset doesn't require to declare separate view for detail. In ProjectListListView declare
lookup_field = 'project'
and delete
path("projectList/<int:pk>", ProjectId.as_view()),
from urlpatterns
In views and serializer define lookup_field = project, this will override the default id field.
Ps - make sure project is unique and primary key.
also change your url to accept string instead of int(id)

Django) How to connect urls-views-models in ManyToMany, OneToMany relationship

I made some models which have ManyToMany, OneToMany relationships, and then I tried to make appropriate class in views.py, so that one can see sub models related to the chosen model.
But in terms of connecting models-serializers-views-urls, I just couldn't figure out how to make it work...
So, what I want to do is : (simplified)
There are 3 models.
Party
People
Food
So Party has ManyToMany relationship with People, and OneToMany relationship with Food. When I reached url like /party_id/people_id, then I want to get specific person's information from given party id.
Here goes my code.
models.py
class Party(models.Model):
par_id = models.TextField()
par_people = models.ManyToManyField(People)
class People(models.Model):
peo_id = models.TextField()
peo_name = models.TextField()
peo_type = models.TextField()
class Food(models.Model):
foo_id = models.TextField()
foo_party = models.ForeignKey(Party, on_delete=models.CASCADE)
serializers.py
class PartySerializer(serializers.ModelSerializer):
class Meta:
model = Party
fields = ('par_id', 'par_people')
# People, Food has same structure...
views.py
class PartyList(generics.ListAPIView):
queryset = Party.objects.all()
serializer_class = PartySerializer
# People, Food has same structure...
urls.py
Here's the part where I got lost
#redundancy reduced...(e.g. import)
urlpatterns = [
path('party/<int:par_id>/<int:peo_id>', views.PartyList.as_view()),
path('party/<int:par_id>/<int:foo_id>', views.PartyList.as_view()),
]
So If I reach website/party/1/3, I want to see person's information(whose peo_id is 3) of party(whose par_id is 1). For food, It goes the same.
Should I make new class in views.py to make it work? But how can url check par_id and foo_id at the same time if I use PartyList view class..? Any help would be much appreciated.
I think something like this should work. The basic principle if work out if using peo_id or foo_id and then filter the queryset on that basis.
def get (self, *args, **kwargs):
id = kwargs.get(peo_id, None)
if id:
self.queryset.filter(par_people__peo_id=id)
else:
id = kwargs.get(foo_id, None)
self.queryset.filter(foo_party=id)

django how to rename PK field in a url [duplicate]

This question already has an answer here:
django use Pk field in a url
(1 answer)
Closed 4 years ago.
if anyone can help me with how to rename pk for a class(table) when I use it in the urlpattern.
(my goal is using many classes(tables ) PK in the same url and I want to know how to rename PK field for each table)
My code below is just for one class(table) for simplicity:
models.py:
class School(models.Model):
name = models.CharField(max_length=256)
principal = models.CharField(max_length=256)
location = models.CharField(max_length=256)
def __str__(self):
return str(self.name)
def get_absolute_url(self):
return reverse("basic_app:school_detail",kwargs={'pk':self.pk})
views.py:
class SchoolListView(ListView):
model = models.School
class SchoolDetailView(DetailView):
context_object_name = 'school_details'
model = models.School
template_name = 'basic_app/school_detail.html'
and my current urls.py (which I want to edit) :
urlpatterns = [
url(r'^$',views.SchoolListView.as_view(),name='school_list'),
url(r'^(?P<pk>\d+)/$',views.SchoolDetailView.as_view(),name='school_detail'),]
So my goal is to make the urls.py file look like this(school_pk instead of pk):
urlpatterns = [
url(r'^$',views.SchoolListView.as_view(),name='school_list'),
url(r'^(?P<school_pk>\d+)/$',views.SchoolDetailView.as_view(),name='school_detail'),]
I know I should add a function below class SchoolDetailView in views.py but I don’t know how ?
I am still learning so any help will be highly appreciated..Thanks in Advance
When declaring your model you can make a field primary by including primary_key=True, eg
class School(models.Model):
name = models.CharField(max_length=256, primary_key=True)
You can then use name within your URL.
I would recommend using unique slug fields.
EDIT
The URL isn't interested if it is called pk or slug or name. It is interested in the pattern. If you have a URL patterns
url(r'^(?P<slug>[\w\\-]+)/$', views.Type1View.as_view(), name="slug"),
url(r'^(?P<city>[\w\\-]+)/$', views.Type2View.as_view(), name="city"),
Both {% url 'slug' slug %} and {% url 'city' slug %} will produce a URL or /slug/ and both will call Type1View.as_view()
You need to ensure your URLs are unique.
If you want to refer to 3 tables then your url pattern is
url(r'^(?P<slug>[\w\\-]+)/(?P<slug1>[\w\\-]+)/(?P<slug2>[\w\\-]+)/$', MyView.as_view(), name="someName"),
And then within your view define def get_objects(self) or def get_queryset(self) to pick up the info you want.

Django Query Does not exist

I'm been trying to create an app that allows users to follow each other profile since yesterday and today and I haven't been successful so far.
I'm having trouble creating a following function that allows me to retrieve users from a particular user he follows.
Example . If John follows Diana . I want to able to retrieve the user called Diana and use it with my modules.
I'm really sorry if this doesn't make sense . I'm trying my hardest to explain my situation.
class Person(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=100)
image = models.FileField(upload_to="images/",blank=True,null=True)
class Board(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=100)
def __unicode__(self):
return self.name
Most of these solutions gave me no query
This was one of the solutions I tried.
class UserLink(models.Model):
from_user = models.ForeignKey(User , related_name = "following_set")
to_user = models.ForeignKey(User , related_name = "follower_set")
date_added = models.DateTimeField(default = datetime.now)
def __unicode__(self):
return "%s is following %s" % (self.from_user.username,self.to_user.username)
def save(self,**kwargs):
if self.from_user == self.to_user:
raise ValueError("Cannot follow yourself ")
super(UserLink , self).save(**kwargs)
class Meta:
unique_together = (('to_user','from_user'),)
I tried to retrieve the users that a particular user followed and use it against my modules such as Person but it gave me an error No query exist.
def Follow(request,username=""):
if request.method == "POST":
username = request.POST.get('follow',False)
user = User.objects.get(username=username)
UserLink.objects.create(from_user=request.user,to_user=user)
return HttpResponseRedirect(reverse('world:Profile'))
return HttpResponseRedirect(reverse('world:Profile'))
I also tried this following function but it only followed himself and I changed self to User but it didn't allow me to put the person to follow
class UserProfile(models.Model):
user = models.OneToOneField(User)
follows = models.ManyToManyField('self', related_name='followed_by', symmetrical=False)
>>>from pet.models import *
>>>from django.contrib.auth.models import User
>>>user = User.objects.get(username='Peter')
>>>user1 = User.objects.get(username='Sarah')
>>>p = UserProfile.objects.filter(user=user,follows=user1)
>>>Error no field called follows
How can I create a following class that allows retrieve the people that they followed and use it with my modules such as Person?
Can someone help me . Thannk you community!
If I understand correctly, youu are on the right track with the many to many relationship. What you need is to modify your existing Person class to include this information.
Since information about who someone follows or is following is essentially information about that person and so you shouldn't really need to define a new class to implement that functionality.
I would suggest modifying your Person like so.
class Person(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=100)
image = models.FileField(upload_to="images/",blank=True,null=True)
following = models.ManyToManyField('self', related_name='followers', symmetrical=False, blank=True, null=True)
What this line does is makes a many to many relationship between the class Person and its self.
Many to many relationships work a little different to other relationships and I suggest you read the Django documentation https://docs.djangoproject.com/en/dev/topics/db/examples/many_to_many/.
But you should now be able to setup and access the relationship like this.
>>>john = Person.objects.get(name="John")
>>>diana = Person.objects.get(name="Diana")
>>>john.following.add(diana)//setup the many to many relationship
>>>john.save()
>>>john.following.all()
//This should return a queryset of Person objects which john is following.
//eg Diana
>>>diana.followers.all()
//This should return a queryset of Person objects which are following Diana.
//eg. John.
Easy, how awesome is Django!

Viewing subset of objects in Django, Views, URLs, Models

I know this is a very basic concept in Django, and I have tried the tutorial but it is not working. I am working on a comic book database with the models set like this (at least, a sample of two of the models):
Class Title(models.Model):
title = models.CharField(max_length=256)
vol = models.IntegerField("Vol.")
slug = models.SlugField(blank=True, null=True)
#desc = models.CharField(max_length=256)
class Meta:
ordering = ['title']
def get_absolute_url(self):
return "/comics2/title/%s" % self.slug
def __unicode__(self):
return self.title
class Issue(models.Model):
title = models.ForeignKey(Title)
number = models.IntegerField(help_text="Enter the number only. Do not include the hashtag.")
writer = models.ManyToManyField(Creator)
What I am trying to do is create a page that shows a list of all the issues within that Title.
But, I have it setup in the views like this:
class AstonishingXMenIssueListView(ListView):
context_object_name = "astonishing_list"
queryset = Issue.objects.filter(title__title="Astonishing X-Men").order_by("number")
template_name = "comics2/astonishing_list.html"
My urls.py look like this:
(r'^comics2/title/(?P<title_slug>[-\w]+)/$', AstonishingXMenIssueListView.as_view(
)),
Of course, going to /uncanny-xmen-v1/ shows the same thing as the Astonishing link above.
Obviously, this is not a practical way to list issues by title for future issues and titles, so I need it setup so that I don't have to individually do this. Now, I have tried following the Django generic views tutorial, but I got an index tuple error.
I've tried this, but it doesn't work. This is what gets me the index tuple error.
class IssuesByTitleView(ListView):
context_object_name = "issues_by_title_list"
template_name = "comics2/issues_by_title.html",
def get_queryset(self):
title = get_object_or_404(Title, title__iexact=self.args[0])
return Issue.objects.filter(title=title)
Any ideas? And can someone please reply in baby-language, as I am new to Django and Python, so simply telling me to look at the Tutorial again isn't going to help. So, maybe writing out the code would help! Thanks!
Generally, your IssueByTitleView is the right way to do it. But as you use named groups in your URL regex (the (?P<title_slug>[-\w]+) part of your URL), you have to access the URL parameters through self.kwargs instead of self.args. Also, you have to filter on the slug field, not the title field:
title = get_object_or_404(Title, slug=self.kwargs['title_slug'])