How to add server-side apis to Django admin website? - python

I'm creating a Django app that can be installed on any Django website as a reusable PyPi package, Lets name it locations app. It has its own models.py, admin.py and let's assume that the custom models of this app have the following tables:
class Country(models.Model):
name = models.CharField(max_length=200)
class City(models.Model):
name = models.CharField(max_length=200)
country = models.ForeignKey(Country, on_delete=models.CASCADE)
class Location(models.Model):
name = models.CharField(max_length=200)
country = models.ForeignKey(Country, on_delete=models.CASCADE)
city = models.ForeignKey(City, on_delete=models.CASCADE)
And all these models are added to the admin website so users can access them from there.
What I need to do is to add an API that lists all Cities for a specific Country so that this API is used in the background every time the user selects a country when adding or editing a location so that it then shows a list of all cities in the currently selected country.
My problem is that if I define this API as a view in locations/views.py located somewhere by locations/urls.py. The URI of the API will be subject to the main urls.py of the website not only the locations/urls.py* and the URI of the admin website as well might vary depending on the main urls.py. So how can I make sure the API will still be accessible regardless of whatever configurations in urls.py?
Does Django admin provide any custom APIs for this?

I think that what you're trying to do is something that resembles this https://github.com/garyburgmann/drf-firebase-auth. This is a Django app that can be installed and imported to the INSTALLED_APPS variables. It might help you on your project I suppose.

Related

How to connect models from different apps in Django?

I have a few apps within my Django project. There are two apps that I am currently working with "Application" and "User" and I have two questions related to models:
Question 1:
I want to design it in such a way so that external users submit their contact form on Application/templates/Application/Apply.html and the info would get added to the database. Internal users would be able to add external users as well but from a different template: User/templates/User/AddNewContact.html
I am able to add a new contact from an internal user's perspective:
User/models.py
class Contact(models.Model):
ContactName = models.CharField(max_length = 250, default='')
ContactResidence = models.CharField(max_length = 250, default='')
Tel = models.CharField(max_length = 250, default='')
def get_absolute_url(self):
return reverse('User:ContactDetails', kwargs={'pk': self.pk}
)
def __str__(self):
return self.ContactName
class Locations(models.Model):
contact = models.ForeignKey(Contact, on_delete=models.CASCADE)
Country = models.CharField(max_length=250, default='')
def __str__(self):
return self.Country
I was going to just copy this model and paste it into Application/models.py but there are two problems:
1) I don't want external users to be directed to URL: User:ContactDetails and technically, it is not going to work out because I will build the authentication later on.
2) I feel that by copying and pasting I am breaking the 'don't repeat yourself" rule.
Should I connect two models using the foreign keys? What are the best practices in this case?
Question 2
Am I working with one-to-many relationship according to the model provided? I want to have one contact with his personal info (tel/email/address) and a number of branch locations across the world associated with that contact.
To be used a relationship one to many, you can be doing as after:
On models of father app (father table):
class Department(models.Model):
dept_id = models.AutoField(primary_key=True)
On models of child app (child table):
from appname.models import Department
class Office(models.Model):
office_id = models.AutoField(primary_key=True)
name = models.CharField(max_length=200)
dept = models.ForeignKey(Department, on_delete=models.CASCADE)
It helped me.
Question 1: Well, you don't need to copy paste the model. You can use models from other django apps anytime, just need to import it. Basically what you should do is, instead of linking the url directly to the template in the Applications app, you should connect it to a view. In the view file you can import the models from User.models import *, and use them normally.
Question 2: As far as I understand the question your structure provides what you want: one contact (with personal info) associated with several countries. Except that you should replace Agent by Contact in contact = models.ForeignKey(Agent, on_delete=models.CASCADE)
Question 1: Note that the 'get_absolute_url' method is only called if you don't provide a success url in your view. If you are using a CreateView or FormView you can specify the success url by overriding the get_success_url method, for example:
class ContactCreateView(CreateView):
model = Contact
fields = ['ContactName', 'ContactResidence', 'Tel']
def get_success_url(self):
if not self.request.user.internal: # e.g. internal is a User bool field
return HttpResponseRedirect('some/external/url/')
return super().get_success_url() # call get_absolute_url model method.
The DRY principle is respected.
Question 2: Yes, the question you need to ask yourself is 'does a model instance (In this case Contact) have many instances of another model (Location)?' If the answer is yes, then the M2M field should go into your Contact model. See the django docs explaining the pizza/toppings example.
The apps should be in the same project and you can import one model as:
import appName.models or
from appName.models import ClassName
In app2 models you can use foreignKey or manyTomany after importing the class:
from appsName.models import ClassName
class Person(models.Model):
con = ForeignKey(ClassName)

where to put relation models in django

First the simplified scenario:
from django.db import models
class Product(models.Model):
name = models.TextField()
description = models.TextField()
class Merchant(models.Model):
name = models.TextField()
class MerchantProductMapping(models.Model):
merchant = models.ForeignKey(Merchant)
product = models.ForeignKey(Product)
price = models.IntegerField()
inventory_limit = models.IntegerField()
I have another model for the relation (MerchantProductMapping) because the relation has attributes of its own. Now the requirements of the Merchant and the Product model have grown to a point where they demand separate apps of their own. The merchant app's models.py is where the Merchant model will live and the product app's models.py is where the Product model will live.
What I need help with is the relation model MerchantProductMapping. It is needed by both apps, where should I put it ? I've been reading up on mixins and wondering if they could help me somehow.
EDIT: I should add that the app was rendered server side earlier. Now it will be done using angular client - REST api approach. And django rest framework will be used on top of django.
Create "common" app for such purposes ... you can put there decorators, templatetags, base forms, base models, login|logout redirect views and urls, ajax views, base filters, base tables ... etc
Note: create "apps" python package dir (dir with __init__.py inside it) and (refactor) move all your apps there.
EDIT:
Another way - create "models" python package dir and split your models.py to logically separated files inside package

Django Admin: add custom fields to template pages

I'm new to Django so this might be a simple question. I'm trying to build a portfolio site using Django. I'd like to have a homepage, portfolio page, portfolio detail pages, and contact page. There will be about 20 portfolio detail pages - Project A, Project B, Project C. Each project (portfolio detail page) has multiple areas where I can input text that is populated through the Django admin. How do I create custom fields in the admin for each Portfolio Detail page (headline, project name, url, description) and display them in the page template?
I'm confused as do I use the pages section in the Django admin and add custom fields for each page or do I create a custom app with these custom fields? Then let's say Project B needs an extra field for awards. How do I add that custom field for just the Project B page in the Django admin?
There is no reason why you can't add any number of fields to your project by just linking them with foreign keys.
project/models.py
from django.db import models
class Project(models.model):
name = models.CharField(max_length=100)
class ProjectField(models.model):
project = models.ForeignKey(Project)
fieldname = models.CharField(max_length=50)
value = models.TextField(max_length=2000)
With what you are describing, it sounds like you would like to edit the ProjectField values in the Project admin page. The way that the admin page handles that normally is with inlines.
As an example for the models above:
projects/admin.py
from projects import models
from django.contrib import admin
class ProjectFieldInline(admin.StackedInline):
model = models.ProjectField
extra = 0
class ProjectAdmin(admin.ModelAdmin):
inlines = [ProjectFieldInline]
admin.site.register(models.Project, ProjectAdmin)
I can't say one hundred percent that this will work for what you are asking, but I recomend giving the app above a try and seeing how close it is to what you want.

Django Model Design: Registered and Unregistered Users referenced together

Experimenting with django, I am trying to design a site that will reference registered users of the site as well as non-registered users. Trying to figure out how to best design my models for this, I'd like to give the non-registered user the ability to register and have it linked to the information I already have. I've read some other SO questions that are sort of related so I know I should be using a seperate class (registered & non-registered), but how would I reference 2 different models using a one foreign key?
Models.py:
from django.db import models
from django.contrib.auth.models import User
class NonRegisteredPerson(models.Model):
first_name = models.CharField(max_length=20, default='')
last_name = models.CharField(max_length=20, default='')
email = models.EmailField(max_length=20,default='', blank=True)
class Seat(models.Model):
num = models.CharField(max_length=100, blank=True)
# For the Non Registered User
occupant = models.ForeignKey('NonRegisteredPerson')
# For the Registered User - using Built-in User
occupant = models.ForeignKey(User)
How do I get "occupant" to reference NonRegisteredPerson and User?
Don't know if this matters, but the way I would handle if a NonRegisteredUser signs up for the site, is check if their e-mail exists in the NonRegisteredPerson model, if it does then delete them from that model and add to the Built-in User.
I know this must be a common scenario, but I don't know what or where I should be looking up for this. TIA.

have multiple users as one model field in many to one format django models

I want to create a minimalist task management app to learn Django's basics. So there will be Projects , Tasks and Users as the three big entities.
A Project can have multiple users
A Project can have multiple tasks
A task can be assigned to 1 user
I can unable to figure out how to do a Many-to-One from Project - > Users using django.contrib.auth.models.User as my Users source.
This is what I have so far, but I know it is wrong and I am unable to wrap my head around it. I tried to relate to other questions such as the one with Contestents and the one with Vulnerabilities URLS on StackOverflow. I am not sure if I have to write my own User Model, or somehow extend it.
class Project(models.Model):
Project_Name = models.CharField(max_length=100)
Project_Users = models.ManyToManyField(User)
class Tasks(models.Model):
Task_Name = models.CharField(max_length=300)
Task_AssignedToUser = models.ForeignKey("Project_Name", through=Users)
Thank you for your help.
class Project(models.Model):
name = models.CharField(max_length=100)
users = models.ManyToManyField(User)
class Task(models.Model):
project = models.ForeignKey(Project, related_name='project_tasks')
name = models.CharField(max_length=300)
assignee = models.ForeignKey(User, related_name='tasks')
Get the the users participating in a specific project:
p = Project.objects.get(name='myproject')
users = p.users.all()
Get a project's tasks:
users = p.project_tasks.all() # Because of `related_name` in Task.project
Get All the tasks a user has, of all the projects:
u = User.objects.get(username='someuser')
u.tasks.all() # Because of `related_name` in Task.assignee
Notes:
A ForeignKey is a Many to One relationship. e.g. A Task belongs to only one Project - A Project can have many Tasks.
You don't need superfluous field names. name is better than Project_Name
One question at a time.

Categories

Resources